Design patterns: Memento
Il Memento Pattern è un pattern comportamentale che permette di catturare e salvare lo stato interno di un oggetto senza violarne l’incapsulamento, consentendo successivamente di ripristinare lo stato salvato. Questo pattern è utile quando si vuole implementare un sistema di undo/redo o per mantenere traccia degli stati passati di un oggetto.
Punti di Forza
- Salvataggio e Ripristino dello Stato: Consente di memorizzare lo stato interno di un oggetto e ripristinarlo in seguito, fornendo funzionalità di undo/redo in modo semplice ed efficace.
- Incapsulamento dello Stato: Mantiene l’incapsulamento dell’oggetto poiché il memento non rivela i dettagli dell’implementazione o lo stato interno dell’oggetto a cui è associato.
- Semplice Gestione degli Stati Complessi: Facilita la gestione di oggetti con stati complessi, permettendo di passare facilmente tra stati precedenti o successivi.
- Separazione delle Responsabilità: Il Memento Pattern separa la responsabilità di memorizzare lo stato (gestito dal memento) dalla logica aziendale dell’oggetto principale (gestito dall’originator).
- Indipendenza dal Client: Il client non ha bisogno di conoscere i dettagli di come gli stati vengono salvati e ripristinati. Deve solo gestire il memento come un oggetto opaco.
Caso d’Uso
Immaginiamo un editor di testo che permette di annullare le modifiche (funzione “undo”) grazie al Memento Pattern.
Codice PHP
//Classe `Editor` (Originator)
class Editor {
private $content;
public function setContent($content) {
$this->content = $content;
}
public function getContent() {
return $this->content;
}
// Creare un memento che memorizza lo stato corrente
public function save() {
return new EditorMemento($this->content);
}
// Ripristinare lo stato salvato da un memento
public function restore(EditorMemento $memento) {
$this->content = $memento->getContent();
}
}
//Classe `Editor` (Originator)
class EditorMemento {
private $content;
public function __construct($content) {
$this->content = $content;
}
public function getContent() {
return $this->content;
}
}
// Classe History (Caretaker)
class History {
private $mementos = [];
// Aggiungere un memento alla storia
public function push(EditorMemento $memento) {
$this->mementos[] = $memento;
}
// Ripristinare l'ultimo stato salvato
public function pop() {
if (!empty($this->mementos)) {
return array_pop($this->mementos);
}
return null;
}
}
// Utilizzo del Memento Pattern
$editor = new Editor();
$history = new History();
// Prima versione del contenuto
$editor->setContent("Prima versione del testo.");
$history->push($editor->save());
// Seconda versione del contenuto
$editor->setContent("Seconda versione del testo.");
$history->push($editor->save());
// Terza versione del contenuto
$editor->setContent("Terza versione del testo.");
echo "Contenuto attuale: " . $editor->getContent() . PHP_EOL;
// Ripristinare l'ultima versione salvata
$editor->restore($history->pop());
echo "Contenuto dopo l'undo: " . $editor->getContent() . PHP_EOL;
// Ripristinare la versione ancora precedente
$editor->restore($history->pop());
echo "Contenuto dopo un altro undo: " . $editor->getContent() . PHP_EOL;
/* Output
Contenuto attuale: Terza versione del testo.
Contenuto dopo l'undo: Seconda versione del testo.
Contenuto dopo un altro undo: Prima versione del testo.
*/
Conclusione
Il Memento Pattern è ideale quando hai bisogno di tenere traccia degli stati precedenti di un oggetto, come nei sistemi di undo/redo. Mantiene il principio dell’incapsulamento mentre semplifica la gestione di stati complessi, senza esporre i dettagli di implementazione agli altri componenti del sistema.