Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Memento. Motivace – kalkulačka 210° sin * /20 ? 0.25 ^2 ?

Podobné prezentace


Prezentace na téma: "Memento. Motivace – kalkulačka 210° sin * /20 ? 0.25 ^2 ?"— Transkript prezentace:

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


Stáhnout ppt "Memento. Motivace – kalkulačka 210° sin * /20 ? 0.25 ^2 ?"

Podobné prezentace


Reklamy Google