2009-02-03 14 views
5

Necesito guardar un historial de estados sobre unas pocas acciones en una aplicación Java, que luego puedo volver a cargar para restaurar el estado en una determinada acción. En otras palabras, tengo una pantalla que tiene un estado asociado y necesito almacenarla, así como cualquier cambio en un historial, para poder restaurar el estado de la pantalla en cualquier momento. Esto es algo así como 'deshacer' pero no exactamente como la diferencia entre dos estados puede ser muy grande y no hay acciones bien definidas que cambien los estados.Crear historial de estados en Java

Déjenme explicar con un ejemplo: Un estado de pantalla muy básico podría contener un solo mapa. En el estado A, este mapa contiene una referencia a "Objeto1" con la clave "Tecla1" y "Objeto2" con la tecla "Tecla2". En el estado B, el mapa todavía contiene la referencia a "Object1", pero se modificó "Object2" y se agregó un "Object3". Ahora necesito poder volver al estado A, lo que implicaría "abandonar" Object3 y restaurar Object2 a su estado anterior. No puedo definir ninguna "acción de deshacer" personalizada, ya que no sé qué cambios se hicieron a Object2 o incluso cuál es el tipo de Object2. Además, como la referencia sigue siendo la misma para Object2 en los estados A y B, esos cambios se reflejan en el estado A, por lo que Object2 no es el mismo que era.

Me doy cuenta de que la mejor solución es implementar métodos de clonación, pero como necesito admitir todo tipo de objetos (incluidas las primitivas y las colecciones estándar) esto no es factible. Pensé en usar serializable, donde serializaría el mapa tan pronto como ocurriera una transición de estado y luego lo deserializaría cuando fuera necesario nuevamente, pero parece ser una solución muy fea.

¿Alguien tiene alguna otra idea? Gracias, Ristretto

+0

Dijiste que tienes que admitir todo tipo de objetos y primitivos ... Entonces dices que piensas en serializar el mapa. ... no entendiendo exactamente tu punto. –

Respuesta

0

Hacemos algo similar a esto con la serialización.

Almacenamos datos archivados en el sistema de archivos en forma serializada. La parte del gráfico de objeto que necesitamos restaurar está serializada, así como el objeto principal.

Asegúrese de que la versión de sus objetos y asegúrese de que su diferenciación puede hacer frente a los campos faltantes/nuevos.

Elegimos almacenar en el sistema de archivos porque nos brinda capacidad (efectivamente) ilimitada. La velocidad no es un problema para nosotros, pero el método del sistema de archivos es sorprendentemente rápido, ¡la mayoría de las personas no notan los 50-100 ms adicionales!

0

Siempre se puede usar la serialización;

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(); 

Lento y torpe, pero funciona.

12

¿Ha intentado buscar en el Memento Design Pattern? Parece particularmente bien definido para tu problema. De Wikipedia:

El patrón memento es un patrón de diseño de software que proporciona la capacidad para restaurar un objeto a su estado anterior (deshace a través de rollback).

La misma página también tiene una sección con un Java implementation ya que mencionas que está en Java.

+0

Gran enlace. ¿Alguna sugerencia sobre cómo usar esto para objetos con estado más complejo (el ejemplo solo usa cadenas) - serialización? –

0

Si lo que quieres es de hecho un mapa, es posible que desee ver en las estructuras de datos persistentes; por ejemplo, árboles B persistentes.

1

Considera un cambio de perspectiva. En lugar de mutar los objetos que componen el estado de la pantalla, use un estado inmutable. Esto puede parecer una contradicción en términos, pero no lo es.

Por ejemplo, digamos (por razones de simplicidad) que su estado consiste en una sola Cadena. Obviamente, dado que las cadenas son inmutables, no tendrá que clonar la cadena para guardar y modificar el estado. Por ejemplo:

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 
} 

En el ejemplo anterior, List es fj.data.List, una inmutable de enlace simple-en-memoria tipo de lista de la biblioteca Functional Java (las bibliotecas estándar no tienen una lista inmutable). El método tomaría el historial de estados, con el estado actual al principio de la lista. Manipula el estado de la pantalla creando un nuevo estado y poniéndolo al frente de una nueva lista de estados.

Aplique este mismo principio a cualquier tipo que desee usar como estado. Asegúrese de que su estado se compone completamente de objetos inmutables (las cadenas y primitivas ya son inmutables). El uso de objetos inmutables para el estado le ahorrará muchos dolores de cabeza de mantenimiento en el futuro, además de conservar la memoria, ya que las cosas inmutables se pueden reutilizar sin tener que clonar.

Un objeto inmutable se inicializará en su constructor y todos sus campos internos serán final.

Functional Java has an immutable map called TreeMap. Se podría utilizar de la siguiente manera:

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

En mi proyecto, hemos logrado algo muy similar serializando a archivos XML. Eso funcionó bien para nosotros. Todos los objetos que desea recuperar: serialice en un archivo XML de una manera bien definida para que en cualquier momento posterior pueda recuperar el estado del archivo XML.

Cuestiones relacionadas