2009-02-03 15 views
5

muszę zapisać historię stanów w ciągu kilku działań w aplikacji Java, które można później przeładowania w celu przywrócenia stanu w określonym działaniu. Innymi słowy, mam ekran, który ma stan powiązany z nim i muszę go przechowywać, jak również wszelkie zmiany w historii, aby w każdej chwili móc przywrócić stan ekranu. Jest to trochę jak "cofnij", ale nie dokładnie, ponieważ różnica między dwoma stanami może być bardzo duża i nie ma dobrze zdefiniowanych działań, które zmieniają stany.Tworzenie historii państw w Javie

Pozwól mi wyjaśnić na przykładzie: Bardzo podstawowy stan ekran może zawierać tylko jedną mapę. W stanie A ta mapa zawiera odniesienie do "Obiektu1" za pomocą klucza "Klucz1" i "Obiekt2" za pomocą klucza "Klucz2". W stanie B mapa nadal zawiera odniesienie do "Obiektu1", ale "Obiekt2" został zmodyfikowany i dodano "Obiekt3". Teraz muszę mieć możliwość powrotu do stanu A, co oznaczałoby "upuszczenie" obiektu 3 i przywrócenie obiektu 2 do poprzedniego stanu. Nie mogę zdefiniować żadnych niestandardowych "operacji cofania", ponieważ nie wiem, jakie zmiany zostały wprowadzone w Object2, a nawet jaki jest typ Object2. Ponadto, ponieważ referencja pozostaje taka sama dla obiektu 2 w stanie A i B, zmiany te są odzwierciedlane w stanie A, więc obiekt2 nie jest taki sam jak był.

Zdaję sobie sprawę, najlepszym rozwiązaniem jest wdrożenie metod klon, ale jak trzeba obsługiwać wszystkie typy obiektów (w tym prymitywów i standardowych zbiorów) nie jest to możliwe. Pomyślałem o używaniu serializowalnych, gdzie serializowałem mapę jak tylko nastąpi przemiana stanu, a następnie deserializuję ją, kiedy będzie potrzebna, ale wydaje się to bardzo brzydkim rozwiązaniem.

Czy ktoś ma jakieś inne pomysły? Dziękuję Ristretto

+0

Powiedziałeś, że musisz wspierać wszystkie rodzaje obiektów i prymitywów ... Wtedy mówisz, że myślisz o serializacji mapy. ... nie do końca rozumiem. –

Odpowiedz

0

Robimy coś podobnego do tego z serializacji.

Przechowujemy dane zarchiwizowane w systemie plików w postaci szeregowej. Część wykresu obiektu, który musimy przywrócić, jest serializowana, a także główny obiekt.

Upewnij się, że zmieniasz wersje swoich obiektów i upewnij się, że różnica może poradzić sobie z brakującymi/nowymi polami.

Zdecydowaliśmy się zapisać do systemu plików, ponieważ daje nam (efektywnie) nieograniczoną pojemność. Szybkość nie jest dla nas problemem, ale metoda systemu plików jest zaskakująco szybka, większość ludzi nie zauważa dodatkowych 50-100ms!

0

Zawsze można użyć serializacji;

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); 
objectOutputStream.writeObject(object); 
objectOutputStream.flush(); 
byteArrayOutputStream.close(); 
ByteArrayInputStream istream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); 
ObjectInputStream objectInputStream= new ObjectInputStream(istream); 
Object deserialized = objectInputStream.readObject(); 
istream.close(); 

Powolny i przylegający, ale działa.

12

Czy próbowałeś już zaglądać do Memento Design Pattern? Wydaje się szczególnie dobrze zdefiniowany dla twojego problemu. Z Wikipedii:

Wzór memento to oprogramowanie wzornictwo, które zapewnia możliwość do przywrócenia obiektu do stanu poprzedniego jej (cofnąć poprzez cofanie).

Ta sama strona ma także sekcję z Java implementation, ponieważ wspomniałeś, że jest to w Javie.

+0

Świetny link. Wszelkie sugestie, jak tego użyć dla obiektów o bardziej złożonym stanie (przykład po prostu używa ciągów) - serializacja? –

0

Jeśli to, co chcesz w rzeczywistości jest mapa, można zajrzeć do trwałych struktur danych; na przykład, trwałe drzewa B.

1

Rozważ zmianę perspektywy. Zamiast mutować obiekty tworzące stan ekranu, użyj stanu niezmiennego. Może to brzmieć jak sprzeczność w terminach, ale tak nie jest.

Powiedz na przykład (dla uproszczenia), że twój stan składa się z pojedynczego ciągu znaków. Oczywiście, ponieważ Ciągi są niezmienne, nie będziesz musiał klonować Łańcucha w celu zapisania i modyfikacji stanu. Na przykład:

public List<String> changeTheScreen(List<String> states) { 
    return states.cons(states.head() + "x"); 
} 

public void renderTheScreen(String currentState) { 
    // TODO: draw the screen given the current state 
} 

w powyższym przykładzie, List jest fj.data.List, niezmienna w pamięci pojedynczo-linked typ listy z biblioteki Functional Java (standardowe biblioteki nie mają listy niezmienna). Metoda pobiera historię stanów z bieżącym stanem na początku listy. Manipuluje stanem ekranu, tworząc nowy stan i umieszczając go na początku nowej listy stanów.

Zastosuj tę samą zasadę do każdego typu, którego chcesz użyć jako stanu. Upewnij się, że twój stan składa się w całości z niezmiennych obiektów (ciągi i prymitywy są już niezmienne). Użycie niezmiennych obiektów dla stanu pozwoli zaoszczędzić wielu kłopotów z utrzymaniem na drodze, a także zachować pamięć, ponieważ niezmienne rzeczy mogą być ponownie użyte bez konieczności klonowania.

Obiekt niezmienny zostanie zainicjowany w jego konstruktorze, a wszystkie jego pola wewnętrzne będą final.

Functional Java has an immutable map called TreeMap. by go użyć w następujący sposób:

public List<TreeMap<String, Object>> 
changeState(List<TreeMap<String, Object>> states) { 
    return states.cons(states.head().set("Key1", new Object1("x"))); 
} 
0

W moim projekcie, osiągnęliśmy coś bardzo podobnego przez szeregowania do plików XML. To działało dla nas dobrze. Wszystkie obiekty, które chcesz odzyskać - serializuj w pliku XML w ściśle określony sposób, aby w każdej chwili móc odzyskać stan z pliku XML.

Powiązane problemy