Daré una respuesta más, pero creo que la cobertura ha sido insuficiente hasta el momento.
El tema está lejos de ser trivial, y Google devuelve una buena cantidad de resultados. Muchas aplicaciones implementan una operación de "deshacer" y hay muchas variantes.
Hay 2 patrones de diseño que nos puede ayudar aquí:
Command
: es una cosificación de una acción
Memento
: que consiste en el almacenamiento de estado (por lo general implica algún tipo de serialización)
El patrón Command
se usa mucho en entornos gráficos porque generalmente hay varias formas de realizar una acción. Piense en Guardar en Microsoft Word por ejemplo:
- puede hacer clic en el icono Guardar
- se puede entrar en Archivo menú y haga clic en Guardar
- utiliza el método abreviado , normalmente CTRL + S
Y, por supuesto Guardar probablemente se implemente en el término de , guarde como.
La ventaja del patrón Command
aquí es doble:
- puede crear una pila de objetos
- puede pedir a cada objeto de implementar una operación
undo
Ahora, hay varios problemas propios de undo
:
- algunas operaciones no se pueden deshacer (por ejemplo, considere
rm
en Linux o el Vaciar la papelera acción en Windows)
- algunas operaciones son difíciles de deshacer, o puede no ser natural (que necesita para almacenar algún estado, el objeto normalmente se destruye pero aquí necesitaría almacenarlo dentro del comando para la acción de deshacer)
- generalmente pensamos en deshacer/rehacer como una pila, algunos programas (principalmente gráficos) proponen deshacer los artículos sin deshacer realmente lo que se ha perdido hecho después, esto es mucho más difícil de lograr, especialmente cuando las acciones más nuevas se han construido sobre la de deshacer ...
Debido a que hay varios problemas, hay varias estrategias:
- Para un simple comando, usted podría considerar la implementación de un deshacer (por ejemplo, añadiendo un carácter se puede deshacer quitándolo)
- Para un comando más complejo, puede considerar implementar deshacer como restaurar el estado anterior (ahí es donde
Memento
se activan)
- Si tiene muchos Comandos complejos, eso podría significar muchos
Memento
que consumen espacio, entonces puede nos e un enfoque que consiste solamente en memorizar una instantánea cada 10 o 20 comandos, y luego volver a hacer los comandos desde la última instantánea hasta el comando deshacer
De hecho, es probable que pueda mezclar Command
y Memento
en el ocio , dependiendo de los detalles de su sistema y, por lo tanto, de la complejidad de ambos.
Solo me gustaría deshacer la última acción ejecutada para empezar (usando una pila de acciones). La funcionalidad de deshacer cualquier acción que el usuario desee es mucho más complicada.
Parece que te han vencido en este, pero me gusta tu línea de pensamiento. Especialmente eres el único que consideró el problema de querer deshacer algo que no está en la parte superior de la pila, ¡lo cual no es trivial! –
Gracias, y sí, las otras respuestas apuntaban a patrones, pero en realidad no los discutían. Eso está muy bien, pero no soy un gran fanático de intentar adaptar los patrones a los problemas como punto de partida. Usualmente (para mí, usando TDD) funciona de la otra manera; un patrón se revela una vez que se alcanza la solución. –