À mon avis, l'UNDO / REDO pourrait être mis en œuvre de deux manières au sens large. 1. Niveau de commande (appelé niveau de commande Undo / Redo) 2. Niveau de document (appelé global Undo / Redo)
Niveau de commande: comme le soulignent de nombreuses réponses, cela est efficacement réalisé en utilisant le modèle Memento. Si la commande prend également en charge la journalisation de l'action, une restauration est facilement prise en charge.
Limitation: une fois que la portée de la commande est sortie, l'annulation / le rétablissement est impossible, ce qui conduit à l'annulation / rétablissement au niveau du document (global)
Je suppose que votre cas s'intégrerait dans l'annulation / le rétablissement global car il convient à un modèle qui implique beaucoup d'espace mémoire. En outre, cela convient également pour annuler / rétablir sélectivement. Il existe deux types primitifs
- Annulation / rétablissement de toute la mémoire
- Niveau objet Annuler Refaire
Dans "Toute la mémoire Undo / Redo", toute la mémoire est traitée comme une donnée connectée (comme un arbre, une liste ou un graphique) et la mémoire est gérée par l'application plutôt que par l'OS. Ainsi, les opérateurs new et delete si en C ++ sont surchargés pour contenir des structures plus spécifiques pour implémenter efficacement des opérations telles que a. Si un nœud est modifié, b. conserver et effacer les données, etc., son fonctionnement consiste essentiellement à copier toute la mémoire (en supposant que l'allocation de mémoire est déjà optimisée et gérée par l'application à l'aide d'algorithmes avancés) et à la stocker dans une pile. Si la copie de la mémoire est demandée, l'arborescence est copiée en fonction de la nécessité d'avoir une copie superficielle ou profonde. Une copie complète est effectuée uniquement pour cette variable qui est modifiée. Étant donné que chaque variable est allouée à l'aide d'une allocation personnalisée, l'application a le dernier mot pour la supprimer le cas échéant. Les choses deviennent très intéressantes si nous devons partitionner le Undo / Redo quand il se trouve que nous devons annuler / rétablir de manière sélective par programme un ensemble d'opérations. Dans ce cas, seules ces nouvelles variables, ou les variables supprimées ou les variables modifiées reçoivent un drapeau afin que Annuler / Rétablir uniquement annule / répète ces mémoires. Lorsque tel est le cas, une nouvelle idée de «modèle de visiteur» est utilisée. Il s’appelle «Annuler / rétablir au niveau de l’objet» ou les variables supprimées ou les variables modifiées reçoivent un drapeau pour qu'Undo / Redo n'annule / ne rétablisse que ces mémoires. Les choses deviennent encore plus intéressantes si nous devons faire un Undo / Redo partiel à l'intérieur d'un objet. Lorsque tel est le cas, une nouvelle idée de «modèle de visiteur» est utilisée. Il s’appelle «Annuler / rétablir au niveau de l’objet» ou les variables supprimées ou les variables modifiées reçoivent un drapeau pour qu'Undo / Redo n'annule / ne rétablisse que ces mémoires. Les choses deviennent encore plus intéressantes si nous devons faire un Undo / Redo partiel à l'intérieur d'un objet. Lorsque tel est le cas, une nouvelle idée de «modèle de visiteur» est utilisée. Il s’appelle «Annuler / rétablir au niveau de l’objet»
- Niveau objet Undo / Redo: Lorsque la notification d'annulation / de rétablissement est appelée, chaque objet implémente une opération de streaming dans laquelle, le streamer obtient de l'objet les anciennes données / nouvelles données qui sont programmées. Les données qui ne sont pas perturbées ne sont pas perturbées. Chaque objet reçoit un streamer comme argument et à l'intérieur de l'appel UNDo / Redo, il diffuse / déprime les données de l'objet.
1 et 2 peuvent avoir des méthodes telles que 1. BeforeUndo () 2. AfterUndo () 3. BeforeRedo () 4. AfterRedo (). Ces méthodes doivent être publiées dans la commande de base Undo / Redo (pas dans la commande contextuelle) afin que tous les objets implémentent également ces méthodes pour obtenir une action spécifique.
Une bonne stratégie consiste à créer un hybride de 1 et 2. La beauté est que ces méthodes (1 et 2) utilisent elles-mêmes des modèles de commande