Memento programtervezési minta
A Memento programtervezési minta biztosítja, hogy egy objektum visszaállítható legyen az előző állapotába.
A Memento minta három objektummal implementálható: originator (kezdeményező), caretaker (gondnok), memento (emlékeztető). Az originator egy objektum, aminek van valamilyen belső állapota. A caretaker valamit módosít az originator belső állapotán, azonban azt akarja, hogy lehetősége legyen visszavonni a változásokat. A caretaker először kér az originator-tól egy memento objektumot. Ezután valamilyen műveletet (vagy műveleteket) végez az originator-on, majd, ha vissza akarja állítani az előző állapotot, akkor visszaadja az originator-nak a memento objektumot. A memento objektum önmagában egy átlátszatlan objektum (a caretaker nem változtathatja meg, vagy nem ajánlott megváltoztatnia). Amikor ezt a mintát használjuk, ügyelni kell arra, hogy ez csak egy objektummal foglalkozik, az originator eközben megváltoztathat más objektumokat vagy erőforrásokat.
Különösen jól használható például visszavonás (undo/redo) funkcionalitás megvalósításakor dokumentumszerkesztés során. Előnye, hogy nem sérti az egységbezárás határait. Hátránya, hogy sokszor erőforrásigényes (pl. teljes dokumentumtartalom mentése, több példányban).
Java példa
A következő Java program illusztrálja a Memento minta "visszavonás"ának használatát.
import java.util.List; import java.util.ArrayList; class Originator { private String state; // The class could also contain additional data that is not part of the // state saved in the memento.. public void set(String state) { System.out.println("Originator: Setting state to " + state); this.state = state; } public Memento saveToMemento() { System.out.println("Originator: Saving to Memento."); return new Memento(this.state); } public void restoreFromMemento(Memento memento) { this.state = memento.getSavedState(); System.out.println("Originator: State after restoring from Memento: " + state); } public class Memento { private final String state; public Memento(String stateToSave) { state = stateToSave; } public String getSavedState() { return state; } } } class Caretaker { public static void main(String[] args) { List<Originator.Memento> savedStates = new ArrayList<Originator.Memento>(); Originator originator = new Originator(); originator.set("State1"); originator.set("State2"); savedStates.add(originator.saveToMemento()); originator.set("State3"); // We can request multiple mementos, and choose which one to roll back to. savedStates.add(originator.saveToMemento()); originator.set("State4"); originator.restoreFromMemento(savedStates.get(1)); } }
A program kimenete:
Originator: Setting state to State1 Originator: Setting state to State2 Originator: Saving to Memento. Originator: Setting state to State3 Originator: Saving to Memento. Originator: Setting state to State4 Originator: State after restoring from Memento: State3
Ez a példa egy Stringet használ állapotként, amelyik egy megváltoztathatatlan objektum Java-ban. Valós életbeli forgatókönyvek esetén az állapot csaknem minden esetben egy objektum lesz és ez esetben az állapot egy példányát kell használni.
Megjegyezzük, hogy megvalósítás rámutat egy hátrányra is: deklarálni kell egy belső osztályt. Jobb lenne, ha a mementó stratégiát egynél több objektumra lehetne alkalmazni.
Leginkább három módja van a mementó elérésének:
- Szerializáció.
- Egy osztályt deklarálunk ugyanabban a csomagban.
- Az objektum egy proxyn keresztül szintén elérhetővé tehető, az adott objektumon egy save/restore (mentés/visszatöltés) műveletén keresztül.
C# Példa
A Memento minta lehetővé teszi, hogy rögzítsük egy objektum állapotát az egységbezárás megsértése nélkül, úgy, hogy később vissza tudjuk azt állítani. Itt egy olyan példa látható ahol a memento objektumot konkrétan arra használjuk, hogy visszavonjuk az objektumban történő változásokat:
//IVSR : Memento példa C# kód //eredeti objektum public class OriginalObject { public string String1 { get; set; } public string String2 { get; set; } public Memento MyMemento { get; set; } public OriginalObject(string str1, string str2) { this.String1 = str1; this.String2 = str2; this.MyMemento = new Memento(str1, str2); } public void Revert() { this.String1 = this.MyMemento.string1; this.String2 = this.MyMemento.string2; } } //memento objektum public class Memento { public readonly string string1; public readonly string string2; public Memento(string str1, string str2) { string1 = str1; string2 = str2; } }
Jegyzetek
Források
További információk
- Benedek Zoltán: Szoftvertechnikák - Tervezési minták / 3 (magyar nyelven) (pdf) pp. 23-36. BME AUT, 2020. november 24. (Hozzáférés: 2023. április 26.)