Stáhnout prezentaci
Prezentace se nahrává, počkejte prosím
1
Memento
2
Motivace – kalkulačka 210° -0.5 5 0 sin *20 -5 +5 /20 ? 0.25 ^2 ?
3
Motivace – kalkulačka 210° -0.5 5 0 sin *20 -5 0.25 ^2
4
Motivace – zálohování databáze
5
Memento Známý také jako Token nebo Snapshot Kategorie: Behavioral patterns (vzory chování) Účel Uchování vnitřního stavu objektu bez porušení zapouzdření pro potřeby budoucí možnosti vrátit se k němu zpět Motivace Undo/rollback Checkpointy Dočasné operace Zotavení z chyb Použití Obnovení operačního systému Transakce v databázích Složité matematické výpočty, při kterých se můžou ztratit dlouho počítaná data Historie tahů ve hrách, načítání a ukládání stavu hry Uchování rozmístění objektů v grafických editorech
6
Struktura
7
Originator Objekt, který si chce nechat ukládat svůj vnitřní stav Memento vytváří pro uchování svého vnitřního stavu Memento využívá pro obnovení svého vnitřního stavu
8
Struktura Caretaker Je zodpovědný za uchování potřebných Mement S Mementem pracuje jako s černou skříňkou, nevidí na jeho obsah
9
Struktura Memento Reprezentuje uložený vnitřní stav Originatoru Chrání privátní data Originatora Implementuje 2 různá rozhraní: Wide interface – pro Originatora Narrow interface – pro Caretakera
10
Interakce Caretaker požádá Originator o Memento Nějaký čas si ho podrží Kdykoli se pak může rozhodnout Memento vrátit zpět Originatoru Originator vyrobí Memento reprezentující jeho aktuální stav Originator přečte data z daného Mementa a změní svůj stav
11
Vlastnosti + Stav se uchovává mimo vlastní objekt, zjednodušuje se tím Originator Zbavuje odpovědnosti v Originatoru za zabezpečení přístupu k uloženým datům Privátní data Originatoru uchovaná v Mementu jsou čitelná jen pro Originator samotný Zabraňuje odhalení vnitřních implementace Originatoru Caretaker může aplikovat různé strategie pro uchovávání a zahazování Mement Prakticky neomezená kapacita uložených stavů lze implementovat pomocí zásobníku objektů Memento - Může být paměťově i časově náročné, pokud jsou stavy příliš velké a kopírují se velká množství dat 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á
12
Metody zpřístupněné Originatoru Implementace – friend (C++) 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_; }; Memento využívá privátní metody, které zpřístupňuje Originatoru pomocí klíčového slova friend
13
Implementace – vnitřní třída (Java) class Originator { private String state; public Memento createMemento() { return new Memento(state); } public void setMemento(Memento memento) { state = memento.getState(); } public void doSomething(String data) { state = data; } public class Memento { private final String state; private Memento(String stateToSave) { state = stateToSave; } private String getState() { return state; } Memento je vnitřní třída Originatoru Originator má přístup k privátním položkám Mementa
14
Implementace – immutable memento (C#) public class Originator { public string State { get; set; } public Memento CreateMemento() { return new Memento(State); } public void SetMemento(Memento memento) { State = memento.Data; } public class Memento { public string Data { get; private set; } public Memento(string data) { Data = data; } Memento je čitelné veřejně, ale nelze jeho stav měnit
15
Implementace – serializace (C#) [Serializable] class Originator { private List state = new List (); public Memento CreateMemento() { Memento memento = new Memento(); return memento.SetState(state); } public void SetMemento(Memento memento) { state = (List ) memento.GetState(); } public void DoSomething(string s) { state.Add(s); Console.WriteLine(s); } [Serializable] class Memento { MemoryStream stream = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); public Memento SetState(object o) { formatter.Serialize(stream, o); return this; } public object GetState() { stream.Seek(0, SeekOrigin.Begin); object o = formatter.Deserialize(stream); stream.Close(); return o; } Serializace Zajistí správu privátních položek a vytváření hluboké kopie stavu
16
Implementace – přírůstková mementa Ukládání přírůstkových změn Memento obsahuje pouze změny vůči předcházejícímu stavu Originator musí dostat Mementa ve správném (obráceném) pořadí Můžeme kombinovat přírůstková Mementa s Mementy obsahujícími plný stav Line 17: + Lorem ipsum … Line 27–34: - A B C D E Line 2: + /n
17
Příklad – kalkulačka s historií Kalkulačka s funkcí zpět 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
18
Příklad – kalkulačka s historií Memento Stav Originatoru (hodnota na kalkulačce) Zabrání vytváření Mementa mimo Originator class CalculatorMemento { private: friend class Calculator; CalculatorMemento(); CalculatorMemento(const double value) : value_(value) { } void setState(const double value) { value_ = value; } double getState() const { return value_; } double value_; }; Zpřístupnění privátních položek Mementa Originatoru
19
Příklad – kalkulačka s historií Originator Originator se nestará o objekt Mementa class Calculator { public: Calculator() : value_(0) { } void execute(const Command command, const double value) { // perform the calculation } const CalculatorMemento* createMemento() { return new CalculatorMemento(value_); } void setMemento(const CalculatorMemento* m) { value_ = m->getState(); } private: int value_; };
20
Příklad – kalkulačka s historií 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 class CalculatorCaretaker { public: void execute(const Command command, const double 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_; };
21
Příklad – piškvorky s ukládáním hry Desková hra s možností uložit a vrátit stav hry
22
Příklad – piškvorky s ukládáním hry Originator class Game { [Serializable] struct State { public char[,] board; public char currentPlayer; } private State state; // Methods for initialization and playing the game, displaying the board etc. public GameSave CreateSave() { GameSave memento = new GameSave(); return memento.SetState(state); } public void RestoreSave(GameSave memento) { state = (State) memento.GetState(); }
23
Příklad – piškvorky s ukládáním hry Memento a Caretaker [Serializable] class GameSave { MemoryStream stream = new MemoryStream(); static BinaryFormatter formatter = new BinaryFormatter(); public GameSave SetState(object o) { formatter.Serialize(stream, o); return this; } public object GetState() { stream.Seek(0, SeekOrigin.Begin); object o = formatter.Deserialize(stream); stream.Close(); return o; } class GameSaveCaretaker { public GameSave GameSave { get; set; } }
24
Shrnutí Kdy využít Memento Potřebujeme-li uložit stav objektu pro případný pozdější návrat Je-li nepřípustné porušit zapouzdření a uveřejnit detaily implementace zvenku Související návrhové vzory Command Může využívat Memento pro návrat operací Iterator Mementa mohou být použita pro iteraci
Podobné prezentace
© 2024 SlidePlayer.cz Inc.
All rights reserved.