En mi opinión, UNDO / REDO podría implementarse de 2 maneras en general. 1. Nivel de comando (llamado nivel de comando Deshacer / Rehacer) 2. Nivel de documento (llamado Deshacer / Rehacer global)
Nivel de comando: como señalan muchas respuestas, esto se logra de manera eficiente utilizando el patrón Memento. Si el comando también admite registrar la acción en un diario, se admite fácilmente una rehacer.
Limitación: una vez que el alcance del comando está fuera, deshacer / rehacer es imposible, lo que lleva a deshacer / rehacer a nivel de documento (global)
Supongo que su caso encajaría en el deshacer / rehacer global, ya que es adecuado para un modelo que involucra mucho espacio de memoria. Además, esto también es adecuado para deshacer / rehacer selectivamente. Hay dos tipos primitivos
- Toda la memoria deshacer / rehacer
- Nivel de objeto Deshacer Rehacer
En "Deshacer / Rehacer toda la memoria", toda la memoria se trata como un dato conectado (como un árbol, una lista o un gráfico) y la memoria la administra la aplicación en lugar del sistema operativo. Por lo tanto, los operadores nuevos y de eliminación si están en C ++ están sobrecargados para contener estructuras más específicas para implementar de manera efectiva operaciones como a. Si se modifica algún nodo, b. guardar y borrar datos, etc., la forma en que funciona es básicamente copiar toda la memoria (asumiendo que la asignación de memoria ya está optimizada y administrada por la aplicación mediante algoritmos avanzados) y almacenarla en una pila. Si se solicita la copia de la memoria, la estructura del árbol se copia en función de la necesidad de tener una copia superficial o profunda. Se realiza una copia profunda solo para esa variable que se modifica. Dado que cada variable se asigna mediante una asignación personalizada, la aplicación tiene la última palabra cuando eliminarla si es necesario. Las cosas se vuelven muy interesantes si tenemos que dividir Deshacer / Rehacer cuando sucede que necesitamos Deshacer / Rehacer programáticamente-selectivamente un conjunto de operaciones. En este caso, solo esas nuevas variables, o las variables eliminadas o las variables modificadas reciben una bandera para que Deshacer / Rehacer solo deshaga / rehace esa memoria. Las cosas se vuelven aún más interesantes si necesitamos hacer un Deshacer / Rehacer parcial dentro de un objeto. Cuando tal es el caso, se utiliza una idea más nueva de "patrón de visitante". Se llama "Deshacer / rehacer a nivel de objeto". o las variables eliminadas o modificadas reciben una bandera para que Deshacer / Rehacer solo deshaga / rehace esa memoria. Las cosas se vuelven aún más interesantes si necesitamos hacer un Deshacer / Rehacer parcial dentro de un objeto. Cuando tal es el caso, se utiliza una idea más nueva de "patrón de visitante". Se llama "Deshacer / rehacer a nivel de objeto". o las variables eliminadas o modificadas reciben una bandera para que Deshacer / Rehacer solo deshaga / rehace esa memoria. Las cosas se vuelven aún más interesantes si necesitamos hacer un Deshacer / Rehacer parcial dentro de un objeto. Cuando tal es el caso, se utiliza una idea más nueva de "patrón de visitante". Se llama "Deshacer / rehacer a nivel de objeto".
- Deshacer / Rehacer a nivel de objeto: cuando se llama a la notificación de deshacer / rehacer, cada objeto implementa una operación de transmisión en la que el transmisor obtiene del objeto los datos antiguos / nuevos que está programado. Los datos que no se alteran se dejan intactos. Cada objeto recibe un streamer como argumento y dentro de la llamada UNDo / Redo, transmite / desentraña los datos del objeto.
Tanto 1 como 2 podrían tener métodos como 1. BeforeUndo () 2. AfterUndo () 3. BeforeRedo () 4. AfterRedo (). Estos métodos deben publicarse en el comando básico Deshacer / rehacer (no en el comando contextual) para que todos los objetos implementen estos métodos también para obtener una acción específica.
Una buena estrategia es crear un híbrido de 1 y 2. Lo bueno es que estos métodos (1 y 2) utilizan patrones de comando