Memento
Obnovení operačního systému ( Windows | Linux...) Všichni víme, co jsou transekce v databázi Memento – zálohování databáze
Občas je potřeba udělat kroky zpět Memento –kroky zpět Dead move
Memento Známý také jako Token, Snapshot Účel Kategorie: behavioral patterns (vzory chování) Uchovávání vnitřního stavu objektu bez porušení zapouzdření Motivace Undo/rollback Checkpointy Pro dočasné operace nebo zotavení z chyb Použití Save/Load funkce ve hrách Transakce v databázích Složité matematické výpočty, při kterých se můžou ztratit dlouho počítaná data V grafických editorech, pro uchování stavu obrazovky při posouvaní objektů
Memento – struktura Struktura Účastníci Originator : Objekt, jehož vnitřní stav chceme uložit Memento : Reprezentuje uložené stavy Originátoru Caretaker : Řídí ukládání/načítání Mementa do/z Originátoru
Memento – účastníci Memento Uchovává vnitřní stav Originátoru Implementuje 2 různá rozhraní: Wide Interface – pro Originator Narrow Interface – pro Caretaker Chrání privátní data Originátora Originátor Vytváří Memento pro uchování svého vnitřního stavu Používá Memento pro obnovení svého vnitřního stavu Caretaker Je zodpovědný za uchování Mementa Nevidí obsah Mementa
Memento – interakce Caretaker požádá Originator o Memento. Nějaký čas jej podrží a pak vrátí zpátky Originátoru.
Memento – souvislosti Vlastnosti Uchovává vnitřní stav objektu a umožňuje jeho pozdější obnovení Uchovává stav mimo vlastní objekt Zjednodušuje Originator Zabraňuje odhalení vnitřních částí Originátoru Caretaker může aplikovat různé strategie pro uchovávání/zahazování Může být paměťově náročné Je úzce svázané s typem objektu, jehož obsah si pamatuje Definice dvou různých rozhraní může být v některých jazycích složitá
C++ Memento – privátní metody Zpřístupněné Originátoru pomocí klíčového slova friend class Originator { public: Memento* createMemento(); void setMemento(const Memento*); private: State* state_; }; class Memento { public: virtual ~Memento(); private: friend class Originator; Memento(); void setState(State*); State* getState(); private: State* state_; }; Metody zpřístupněné Originátoru Memento – implementace
Java Memento je vnitřní třída třídy Originator Bez problémů přistoupí k privátním položkám třídy Originator class Originator { private String state; public void set(String state) { this.state = state; } public Memento getMemento() { return new Memento(state); } public void restoreFromMemento(Memento memento) { state = memento.getSavedState(); } public static class Memento { private final String state; private Memento(String stateToSave) { state = stateToSave; } private String getSavedState() { return state; } Memento – implementace
C# // Originator [Serializable()] class Originator { List state = new List (); public void Operation (string s) { state.Add(s); foreach (string line in state) Console.WriteLine(line); Console.WriteLine("======================="); } // The reference to the memento is passed back to the client public Memento SetMemento() { Memento memento = new Memento(); return memento.Save(state); } public void GetMemento(Memento memento) { state = (List ) memento.Restore(); } Memento – implementace [Serializable()] // Serializes by deep copy to memory and back class Memento { MemoryStream stream = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); public Memento Save (object o) { formatter.Serialize(stream, o); return this; } public object Restore() { stream.Seek(0, SeekOrigin.Begin); object o = formatter.Deserialize(stream); stream.Close(); return o; } class Caretaker { public Memento Memento {get; set;} }
Memento – implementace Serializace Levný způsob zachycení aktuálního stavu Originátoru Snazší perzistence Ukládání přírůstkových změn Memento obsahuje změny vůči předcházejícímu stavu Originator musí dostat Mementa ve správném pořadí Můžeme kombinovat přírůstková Mementa s Mementy obsahujícími plný stav
Memento – příklady Kalkulačka s funkcí undo Uživatel chce mít možnost vrátit se zpátky ve výpočtu Ne všechny funkce jsou inverzní – je nutno použít Memento Zabrání opakování složitých výpočtů při chybě uživatele
Memento – příklady class CalculatorMemento { private: friend class Calculator; CalculatorMemento(); CalculatorMemento(const int value) : value_(value) { } void setState(const int value) { value_ = value; } int getState() const { return value_; } int value_; } Kalkulačka – Memento Stav Originátoru. Hodnota na kalkulačce Zabrání vytváření Mementa mimo Originator
Memento – příklady class Calculator { public: Calculator() : value_(0) { } void execute(const Command command, const int value) {... } const CalculatorMemento *createMemento() { return new CalculatorMemento(value_); } void setMemento(const CalculatorMemento *m) { value_ = m->getState(); } private: int value_; }; Kalkulačka – Originator Originator se nestará o objekt Mementa
Memento – příklady class CalculatorWithUndo { public: void execute(const Command command, const int value) { undoStack_.push(calculator_.createMemento()); calculator_.execute(command, value); } void undo() { if (!undoStack_.empty()) { const CalculatorMemento *m = undoStack_.top(); calculator_.setMemento(m); delete m; undoStack_.pop(); } private: std::stack undoStack_; Calculator calculator_; }; Kalkulačka s funkcí undo – Caretaker Uložení stavu před vykonáním příkazu Caretaker má zodpovědnost za objekt Mementa Zásobník pro jednotlivá Mementa a undo operace
Memento – příklady class Game { // nine spaces char[] board = { 'X', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; public void Play(int pos) { } // The reference to the memento is passed back to the client public Memento Save() { Memento memento = new Memento(); return memento.Save(board); } public void Restore(Memento memento) { board = (char[])memento.Restore(); Player = board[0]; } public void DisplayBoard() { } Piškvorky s funkcí undo C# – Originator
Memento – příklady [Serializable()] // Serializes by deep copy to memory and back class Memento { MemoryStream stream = new MemoryStream(); static BinaryFormatter formatter = new BinaryFormatter(); public Memento Save(object o) { formatter.Serialize(stream, o); return this; } public object Restore() { stream.Seek(0, SeekOrigin.Begin); object o = formatter.Deserialize(stream); stream.Close(); return o; } Piškvorky s funkcí undo C# – Memento a Caretaker class Caretaker { public Memento Memento { get; set; } }
Memento – shrnutí Kdy užít Memento Je-li potřeba zachovat vnitřní stav objektu Je-li nepřípustné porušit zapouzdření Související návrhové vzory Command Užívá Memento pro vrácení při nevratných operacích Iterator Mementa mohou být použita pro iteraci