Command Definice Nvrhov vzor Command je vzor chovn

  • Slides: 21
Download presentation
Command

Command

Definice Návrhový vzor Command je vzor chování (behaviorální návrhový vzor), který zapouzdřuje příkazy do

Definice Návrhový vzor Command je vzor chování (behaviorální návrhový vzor), který zapouzdřuje příkazy do objektu. Objekt pak jako proměnnou předáva aplikaci z důvodu například jejího zařazení do fronty k pozdějšímu vykonání nebo rekonstrukci historie příkazů s možností Undo / Redo.

Motivace Návrhový vzor Command je vzor chování (behaviorální návrhový vzor), který zapouzdřuje příkazy do

Motivace Návrhový vzor Command je vzor chování (behaviorální návrhový vzor), který zapouzdřuje příkazy do objektu. Objekt pak jako proměnnou předáva aplikaci z důvodu například jejího zařazení do fronty k pozdějšímu vykonání nebo rekonstrukci historie příkazů s možností Undo / Redo. ■ Potřebujeme reprezentovat žádost o vykonání akce standardní přístup je zavolat metodu na objektu ❑ metoda se provede okamžitě ❑ potřebujeme speciální sémantiku ❑ zpožděné vykonání ❑ vzdálené vykonání ❑ explicitní kontrola akcí ❑ ❑ potřeba abstrakce volání

Motivace

Motivace

Motivace / Naivní implementace public void Check. Action(string action) { if (action == "New")

Motivace / Naivní implementace public void Check. Action(string action) { if (action == "New") { // handle action for new command } else if (action == "Open") { // handle action for open command } else if (action == "Save") { // handle action for save command } else (action == "Quit") { // handle action for quit command } } Porušení principu otevřenosti a uzavřenosti OOP

„Kuchařka“ Návrhový vzor Command je vzor chování (behaviorální návrhový vzor), ve kterém je objekt

„Kuchařka“ Návrhový vzor Command je vzor chování (behaviorální návrhový vzor), ve kterém je objekt použit k zapouzdření všech informací potřebných ke zpožděnému spuštění události. Tyto informace zahrnují jméno metody, objekt, kterému metoda patří a hodnoty jejích parametrů. definujeme Command interface se signaturou metody „execute()“ ❑ vytvoříme konkrétní implementace Command interface, které zapouzdřují: ❑ ➢ ➢ ➢ „receiver“ objekt („na čem se má akce zavolat“) cílová metoda („co se má zavolat“) argumenty pro cílovou metodu vytvoříme instanci Command objektu pro každou událost ❑ předáme Command objekt invokeru (senderu) ❑ invoker rozhodne, kdy bude execute() zavolána ❑

Obecná struktura s příkladem Aplikace při vytváření GUI Menu item Paste command Document document->Paste()

Obecná struktura s příkladem Aplikace při vytváření GUI Menu item Paste command Document document->Paste()

Konkrétních Commandů je typicky několik

Konkrétních Commandů je typicky několik

Konkrétní použití, runtime

Konkrétní použití, runtime

Příklad class Light { void Turn. On() { Write. Line("Light on"); } Receiver void

Příklad class Light { void Turn. On() { Write. Line("Light on"); } Receiver void Turn. Off() { Write. Line("Light off"); } public interface ICommand { void Execute(); } Interface class Light. On. Command : ICommand { private Light my. Light; } Light. On. Command(Light light) { my. Light = light; } class Switch Invoker { private ICommand up. Command, down. Command; void Execute() { my. Light. Turn. On(); } public Switch(ICommand up, ICommand down) { up. Command = up; down. Command = down; } } class Light. Off. Command : ICommand { private Light my. Light; Light. Off. Command(Light light) { my. Light = light; } public void Flip. Up() { up. Command. Execute(); } public void Flip. Down() { down. Command. Execute(); } } public void Execute() { my. Light. Turn. Off(); } } Command objekty

Příklad Client static void Main(string[] args) { Light light = new Light(); ICommand light.

Příklad Client static void Main(string[] args) { Light light = new Light(); ICommand light. On = new Light. On. Command(light); ICommand light. Off = new Light. Off. Command(light); Switch my. Switch = new Switch(light. On, light. Off); my. Switch. Flip. Up(); my. Switch. Flip. Down(); }

Příklad - rozšíření class Fan Jiný receiver { void Start. Rotate() { Write. Line("Fan

Příklad - rozšíření class Fan Jiný receiver { void Start. Rotate() { Write. Line("Fan rotating"); } class Fan. On. Command : ICommand { private Fan my. Fan; Fan. On. Command(Fan fan) { my. Fan = fan; } void Stop. Rotate() { Write. Line("Fan not rotating"); } void Execute() { my. Fan. Start. Rotate(); } } class Switch Stejný invoker { private ICommand up. Command, down. Command; Switch(ICommand up, ICommand down) { up. Command = up; down. Command = down; } void Flip. Up() { up. Command. Execute(); } void Flip. Down() { down. Command. Execute(); } } } class Fan. Off. Command : ICommand { private Fan my. Fan; Fan. Off. Command(Fan fan) { my. Fan = fan; } void Execute() { my. Fan. Stop. Rotate(); } } Jiné command objekty

Macro. Command ■ Kompozice posloupnosti volání (makro) ❑ založeno na Composite pattern ❑ chování

Macro. Command ■ Kompozice posloupnosti volání (makro) ❑ založeno na Composite pattern ❑ chování makra stejné jako jedné akce ❑ class Macro. Command : ICommand { private List<ICommand> commands; void Execute() { foreach (ICommand c in commands) c. Execute(); //. . . } }

Undo, redo ■ Je třeba ukládat stav receiveru reference na objekt receiveru ❑ argumenty

Undo, redo ■ Je třeba ukládat stav receiveru reference na objekt receiveru ❑ argumenty volání Command objektu ❑ původní hodnoty receiveru ❑ ■ Command objekty občas musí být kopírovány pokud se dále může měnit jejich stav ❑ prototype pattern ❑ ■ Pozor na chyby při undo/redo ❑ ■ zajistit konzistentní stav uložených command objektů (Memento) Alternativa: kompenzující opreace ❑ např. vypni - zapni

Undo interface ICommand { void Execute(); void Undo(); } Nová metoda class Paste. Command

Undo interface ICommand { void Execute(); void Undo(); } Nová metoda class Paste. Command : ICommand { private Document document; private string old. Text; Paste. Command(Document doc) { document = doc; } void Execute() { old. Text = document. Get. Text(); document. Paste(); } void Undo() { document. Set. Text(old. Text); } } Uloží stav Obnoví stav z uložených hodnot

Známé použití • • • Multi-level Undo • execute/undo, uchování/vytvoření předchozího stavu Macro recording

Známé použití • • • Multi-level Undo • execute/undo, uchování/vytvoření předchozího stavu Macro recording GUI toolkity • Java Swing – interface Action, metoda action. Performed • WPF. NET – ICommand Thread. Pool • odkládání požadavků do fronty - zpracování, až na ně přijde řada Parallel / cluster / distributed computing • hi-perf scheduler, job queues Předávání požadavků po síti, callbacky Progress bar • get. Estimated. Duration() Wizards • naklikat commandy, pak je najednou provést “transakční” chování • rollback, roll-forward

Fungus ■ Flowchart množina blocků (orientovaný graf) ❑ popisuje vztahy mezi blocky ❑ má

Fungus ■ Flowchart množina blocků (orientovaný graf) ❑ popisuje vztahy mezi blocky ❑ má vstupní bod a podmínky pro spuštění ❑ ■ Block ■ ■ množina commandů (pole) má na starosti jejich vykonávání

Fungus – Command class public class Command : Mono. Behaviour { [Hide. Inspector] public

Fungus – Command class public class Command : Mono. Behaviour { [Hide. Inspector] public string error. Message = ""; [Hide. Inspector] public int indent. Level; [Non. Serialized] public int command. Index; [Non. Serialized] public bool is. Executing; [Non. Serialized] public float executing. Icon. Timer; [Non. Serialized] public Block parent. Block; public virtual void Execute() { On. Enter(); } Metoda Execute() public virtual void Continue(int next. Command. Index) { On. Exit(); if (parent. Block != null) { parent. Block. jump. To. Command. Index = next. Command. Index; } } public virtual void Stop. Parent. Block() { On. Exit(); if (parent. Block != null) parent. Block. Stop(); } public virtual void /* Více kódu. . . */ } On. Stop. Executing() { } On. Enter() { } On. Exit() { } On. Reset() { }

Fungus – Block class (Execute. Block method) protected virtual IEnumerator Execute. Block(Action on. Complete

Fungus – Block class (Execute. Block method) protected virtual IEnumerator Execute. Block(Action on. Complete = null) { Flowchart flowchart = Get. Flowchart(); execution. State = Execution. State. Executing; int i = 0; while (true) { if (jump. To. Command. Index > -1) { i = jump. To. Command. Index; jump. To. Command. Index = -1; } /* Sanity checky, přeskočení zakázaných commandů, breaknutí z while na konci listu, etc. . . */ Command command = command. List[i]; active. Command = command; /* Další sanity checky. . . */ command. is. Executing = true; command. Execute(); // Wait until the executing command sets another command to jump to via Command. Continue() while (jump. To. Command. Index == -1) { yield return null; } command. is. Executing = false; } execution. State = Execution. State. Idle; active. Command = null; if (on. Complete != null) on. Complete(); }

Fungus – Jump Command [Command. Info("Flow", "Jump", "Move execution to a specific Label command")]

Fungus – Jump Command [Command. Info("Flow", "Jump", "Move execution to a specific Label command")] public class Jump : Command { [Tooltip("Label to jump to")] public Label target. Label; public override void On. Enter() { if (target. Label == null) { Continue(); return; } foreach (Command command in parent. Block. command. List) { Label label = command as Label; if (label != null && label == target. Label) { Continue(label. command. Index + 1); break; } } } /* Metody pro Unity inspektor. . . */ }

Související vzory ■ Composite ❑ ■ Memento ❑ ■ uchovávání stavu objektů pro undo

Související vzory ■ Composite ❑ ■ Memento ❑ ■ uchovávání stavu objektů pro undo Prototype ❑ ■ vytváření maker (Macro. Command) při undo ukládání kopií akcí Chain of Responsibility grafické toolkity – Command objekt může zpracovávat víc příjemců ❑ propagace změny stavu, řetězení ❑