A mio parere, UNDO / REDO potrebbe essere implementato in 2 modi in generale. 1. Livello di comando (chiamato livello di comando Annulla / Ripeti) 2. Livello documento (chiamato Annulla / Ripeti globale)
Livello di comando: come molte risposte sottolineano, ciò viene ottenuto in modo efficiente utilizzando lo schema Memento. Se il comando supporta anche la memorizzazione su giornale dell'azione, è facilmente supportata una ripetizione.
Limitazione: una volta che l'ambito del comando è fuori, l'annullamento / ripetizione è impossibile, il che porta all'annullamento / ripetizione a livello di documento (globale)
Immagino che il tuo caso si adatterebbe all'annullamento / ripetizione globale poiché è adatto per un modello che richiede molto spazio di memoria. Inoltre, questo è adatto anche per annullare / ripetere selettivamente. Esistono due tipi primitivi
- Tutta la memoria annulla / ripeti
- Livello oggetto Annulla Ripeti
In "All memory Undo / Redo", l'intera memoria viene trattata come un dato connesso (come un albero, o un elenco o un grafico) e la memoria è gestita dall'applicazione piuttosto che dal sistema operativo. Quindi gli operatori new e delete se in C ++ sono sovraccaricati per contenere strutture più specifiche per implementare efficacemente operazioni come un file. Se un nodo viene modificato, b. detenere e cancellare i dati ecc., Il modo in cui funziona è fondamentalmente copiare l'intera memoria (assumendo che l'allocazione della memoria sia già ottimizzata e gestita dall'applicazione utilizzando algoritmi avanzati) e memorizzarla in uno stack. Se viene richiesta la copia della memoria, la struttura ad albero viene copiata in base alla necessità di avere una copia superficiale o profonda. Viene eseguita una copia completa solo per quella variabile che viene modificata. Poiché ogni variabile viene allocata utilizzando l'allocazione personalizzata, l'applicazione ha l'ultima parola su quando eliminarla, se necessario. Le cose diventano molto interessanti se dobbiamo partizionare l'Undo / Redo quando accade che abbiamo bisogno di Undo / Redo selettivo e programmatico di un insieme di operazioni. In questo caso, solo a quelle nuove variabili, o variabili cancellate o variabili modificate viene dato un flag in modo che Annulla / Ripeti solo annulli / ripristini quella memoria Le cose diventano ancora più interessanti se dobbiamo fare un Annulla / Ripristina parziale all'interno di un oggetto. In tal caso, viene utilizzata un'idea più recente di "modello visitatore". Si chiama "Annulla / ripeti a livello oggetto" o alle variabili cancellate o alle variabili modificate viene dato un flag in modo che Annulla / Ripristina solo annulli / ripristini quella memoria. Le cose diventano ancora più interessanti se dobbiamo fare un Annulla / Ripristina parziale all'interno di un oggetto. In tal caso, viene utilizzata un'idea più recente di "modello visitatore". Si chiama "Annulla / ripeti a livello oggetto" o alle variabili cancellate o alle variabili modificate viene dato un flag in modo che Annulla / Ripristina solo annulli / ripristini quella memoria. Le cose diventano ancora più interessanti se dobbiamo fare un Annulla / Ripristina parziale all'interno di un oggetto. In tal caso, viene utilizzata un'idea più recente di "modello visitatore". Si chiama "Annulla / ripeti a livello oggetto"
- Livello oggetto Annulla / Ripristina: quando viene chiamata la notifica di annullamento / ripristino, ogni oggetto implementa un'operazione di streaming in cui, lo streamer ottiene dall'oggetto i vecchi dati / nuovi dati programmati. I dati che non vengono disturbati vengono lasciati indisturbati. Ogni oggetto riceve uno streamer come argomento e all'interno della chiamata UNDo / Redo, trasmette / scarica i dati dell'oggetto.
Sia 1 che 2 potrebbero avere metodi come 1. BeforeUndo () 2. AfterUndo () 3. BeforeRedo () 4. AfterRedo (). Questi metodi devono essere pubblicati nel comando di base Undo / redo (non il comando contestuale) in modo che anche tutti gli oggetti implementino questi metodi per ottenere un'azione specifica.
Una buona strategia è creare un ibrido di 1 e 2. Il bello è che questi metodi (1 e 2) utilizzano essi stessi schemi di comando