Vzor příkazu - Command pattern
![]() | Tento článek obsahuje a seznam doporučení, související čtení nebo externí odkazy, ale jeho zdroje zůstávají nejasné, protože mu chybí vložené citace.Prosinec 2012) (Zjistěte, jak a kdy odstranit tuto zprávu šablony) ( |
v objektově orientované programování, vzor příkazu je behaviorální návrhový vzor ve kterém je objekt zvyklý zapouzdřit všechny informace potřebné k provedení akce nebo spuštění události později. Tyto informace zahrnují název metody, objekt, který vlastní metodu, a hodnoty parametrů metody.
Čtyři výrazy vždy spojené se vzorem příkazu jsou příkaz, přijímač, vyvolávač a klient. A příkaz objekt ví o přijímač a vyvolá metodu přijímače. Hodnoty pro parametry metody přijímače jsou uloženy v příkazu. Objekt příjemce pro provedení těchto metod je také uložen v objektu příkazu pomocí agregace. The přijímač pak dělá práci, když vykonat()
metoda v příkaz je nazýván. An vyvolávač objekt ví, jak provést příkaz, a volitelně vede účetnictví o provádění příkazu. Vyvolávač neví nic o konkrétním příkazu, ví jen o příkazu rozhraní. Objekty invokerů, objekty příkazů a objekty přijímače jsou drženy a klient objekt, klient rozhoduje, které objekty přijímače přiřadí objektům příkazů a které příkazy přiřadí volajícímu. Klient se rozhodne, které příkazy se mají v kterém bodě provést. Chcete-li provést příkaz, předá objekt příkazu objektu vyvolávajícího.
Použití příkazových objektů usnadňuje konstrukci obecných komponent, které potřebují delegovat, sekvenovat nebo spouštět volání metod v době jejich výběru, aniž by bylo nutné znát třídu metody nebo parametry metody. Použití objektu invoker umožňuje pohodlné provádění účetnictví o provádění příkazů a také implementaci různých režimů pro příkazy, které jsou spravovány objektem invoker, aniž by klient musel vědět o existenci účetnictví nebo režimů.
Ústřední myšlenky tohoto návrhového vzoru úzce odrážejí sémantiku prvotřídní funkce a funkce vyššího řádu v funkční programovací jazyky. Objekt invoker je konkrétně funkcí vyššího řádu, jejíž objekt příkazu je argumentem první třídy.
Přehled
Příkaz[1]designový vzor je jedním z dvaceti tří známých GoF návrhové vzory které popisují, jak řešit opakující se konstrukční problémy při navrhování flexibilního a opakovaně použitelného objektově orientovaného softwaru, tj. objektů, které se snadněji implementují, mění, testují a znovu používají.
Použití návrhového vzoru příkazu může vyřešit tyto problémy:[2]
- Je třeba se vyhnout spojování vyvolávajícího požadavku s konkrétním požadavkem. To znamená, že je třeba se vyhnout pevně připojeným požadavkům.
- Mělo by být možné nakonfigurovat objekt (který vyvolá požadavek) s požadavkem.
Implementace (pevné zapojení) požadavku přímo do třídy je nepružná, protože spojuje třídu s konkrétním požadavkem v době kompilace, což znemožňuje specifikovat požadavek za běhu.
Použití návrhového vzoru příkazu popisuje následující řešení:
- Definujte samostatné (příkazové) objekty, které zapouzdřují požadavek.
- Třída deleguje požadavek na objekt příkazu namísto přímé implementace konkrétního požadavku.
To umožňuje konfigurovat třídu pomocí objektu příkazu, který se používá k provedení požadavku. Třída již není spojena s konkrétním požadavkem a nemá žádné znalosti (je nezávislé) o tom, jak se požadavek provádí.
Viz také diagram tříd a sekvencí UML níže.
Struktura
Třída a sekvenční diagram UML

Ve výše uvedeném UML třídní diagram, Vyvolávač
třída neimplementuje požadavek přímo. Místo toho Vyvolávač
Odkazuje na Příkaz
rozhraní k provedení požadavku (command.execute ()
), což činí Vyvolávač
bez ohledu na to, jak se požadavek provádí Command1
třída implementuje Příkaz
rozhraní provedením akce na přijímači (receiver1.action1 ()
).
The UML sekvenční diagram ukazuje interakce za běhu: Vyvolávač
volání objektu vykonat()
na Command1
objekt.Command1
hovory akce1 ()
na Přijímač 1
objekt, který provádí požadavek.
Diagram tříd UML

Použití
- Tlačítka GUI a položky nabídky
- v Houpačka a Borland Delphi programování, an
Akce
je příkazový objekt. Kromě schopnosti provést požadovaný příkaz, Akce může mít přidruženou ikonu, klávesovou zkratku, text popisu nástroje atd. Tlačítko panelu nástrojů nebo součást položky nabídky lze úplně inicializovat pouze pomocí Akce objekt. - Makro záznam
- Pokud jsou všechny akce uživatele reprezentovány objekty příkazů, program může zaznamenat posloupnost akcí jednoduše tím, že ponechá seznam objektů příkazů při jejich provádění. Poté může „přehrávat“ stejné akce opakovaným spuštěním stejných příkazových objektů v pořadí. Pokud program vloží skriptovací modul, může každý příkazový objekt implementovat a toScript () metoda a akce uživatele lze poté snadno zaznamenat jako skripty.
- Mobilní kód
- Pomocí jazyků, jako je Java, kde lze kód streamovat / rozdělovat z jednoho místa na druhé pomocí URLClassloaders a Codebases, mohou příkazy umožnit doručování nového chování do vzdálených umístění (příkaz EJB, Master Worker).
- Víceúrovňový vrátit
- Pokud jsou všechny akce uživatele v programu implementovány jako objekty příkazů, může program uchovat hromadu naposledy spuštěných příkazů. Když chce uživatel zrušit příkaz, program jednoduše vyskočí na nejnovější příkazový objekt a provede jeho vrátit() metoda.
- Síťování
- Je možné posílat celé objekty příkazů po síti, které mají být provedeny na ostatních strojích, například akce hráčů v počítačových hrách.
- Paralelní zpracování
- Kde jsou příkazy zapisovány jako úkoly do sdíleného prostředku a prováděny mnoha vlákny paralelně (možná na vzdálených počítačích; tato varianta se často označuje jako vzor Master / Worker)
- Indikátory průběhu
- Předpokládejme, že program má sled příkazů, které provádí v pořadí. Pokud má každý příkazový objekt a getEstimatedDuration () metoda může program snadno odhadnout celkovou dobu trvání. Může zobrazit indikátor průběhu, který smysluplně odráží, jak blízko je program k dokončení všech úkolů.
- Bazény závitů
- Typická, obecná třída fondu vláken může mít veřejnost addTask () metoda, která přidá pracovní položku do interní fronty úkolů čekajících na dokončení. Udržuje fond vláken, která spouští příkazy z fronty. Položky ve frontě jsou objekty příkazů. Tyto objekty obvykle implementují společné rozhraní, jako je java.lang.Runnable který umožňuje fondu vláken vykonat příkaz, přestože samotná třída fondu vláken byla napsána bez znalosti konkrétních úkolů, pro které by byla použita.
- Transakční chování
- Podobně jako zpět může databázový stroj nebo instalační program softwaru vést seznam operací, které byly nebo budou provedeny. Pokud jeden z nich selže, všechny ostatní mohou být obráceny nebo vyřazeny (obvykle se volají vrácení zpět). Například pokud musí být aktualizovány dvě databázové tabulky, které na sebe odkazují, a druhá aktualizace selže, lze transakci vrátit zpět, takže první tabulka nyní neobsahuje neplatný odkaz.
- Čarodějové
- Průvodce často představuje několik stránek konfigurace pro jednu akci, ke které dojde, pouze když uživatel klikne na tlačítko „Dokončit“ na poslední stránce. V těchto případech je přirozeným způsobem, jak oddělit kód uživatelského rozhraní od kódu aplikace, implementovat průvodce pomocí objektu příkazu. Objekt příkazu je vytvořen při prvním zobrazení průvodce. Každá stránka průvodce ukládá své změny grafického uživatelského rozhraní do objektu příkazu, takže objekt je naplněn postupem uživatele. „Dokončit“ jednoduše vyvolá hovor vykonat(). Tímto způsobem bude třída příkazů fungovat.
Terminologie
Terminologie použitá k popisu implementace vzorů příkazů není konzistentní, a proto může být matoucí. To je výsledek dvojznačnost, použití synonyma a implementace, které mohou zakrýt původní vzor tím, že jdou daleko za něj.
- Dvojznačnost.
- Termín příkaz je nejednoznačný. Například, posunout nahoru, posunout nahoru může odkazovat na jeden příkaz (pohyb nahoru), který by měl být proveden dvakrát, nebo může odkazovat na dva příkazy, z nichž každý dělá stejnou věc (pohyb nahoru). Pokud je předchozí příkaz dvakrát přidán do zásobníku zpět, obě položky v zásobníku odkazují na stejnou instanci příkazu. To může být vhodné, když lze příkaz vrátit vždy stejným způsobem (např. Přejít dolů). Oba Gang čtyř a Příklad Java níže použijte tento výklad pojmu příkaz. Na druhou stranu, pokud jsou tyto příkazy přidány do zásobníku zpět, zásobník odkazuje na dva samostatné objekty. To může být vhodné, když každý objekt v zásobníku musí obsahovat informace, které umožňují vrácení příkazu. Například vrátit zpět a smazat výběr příkaz může objekt obsahovat kopii odstraněného textu, aby mohl být znovu vložen, pokud smazat výběr příkaz musí být vrácen. Všimněte si, že použití samostatného objektu pro každé vyvolání příkazu je také příkladem řetězec odpovědnosti.
- Termín vykonat je také nejednoznačný. Může odkazovat na spuštění kódu identifikovaného objektem příkazu vykonat metoda. V Microsoftu Windows Presentation Foundation příkaz je považován za provedený, když je příkaz vykonat byla vyvolána metoda, ale to nutně neznamená, že byl spuštěn kód aplikace. K tomu dojde až po dalším zpracování událostí.
- Synonyma a homonyma.
- Klient, zdroj, vyvolávač: klepnutí na tlačítko, tlačítko na panelu nástrojů nebo na položku nabídky, klávesová zkratka stisknutá uživatelem.
- Objekt příkazu, směrovaný objekt příkazu, objekt akce: samostatný objekt (např. existuje pouze jeden objekt CopyCommand), který ví o klávesových zkratkách, obrázcích tlačítek, textu příkazu atd. souvisejících s příkazem. Objekt source / invoker volá metodu execute / performAction objektu Command / Action. Objekt Command / Action upozorní příslušné objekty zdroje / vyvolávače, když se změnila dostupnost příkazu / akce. To umožňuje, aby tlačítka a položky nabídky byly neaktivní (šedé), když nelze provést / provést příkaz / akci.
- Přijímač, cílový objekt: objekt, který se má zkopírovat, vložit, přesunout atd. Objekt přijímače vlastní metodu, která je volána příkazem vykonat metoda. Přijímač je obvykle také cílovým objektem. Například pokud je objekt přijímače a kurzor a metoda se nazývá moveUp, pak by se dalo očekávat, že kurzor je cílem akce moveUp. Na druhou stranu, pokud je kód definován samotným objektem příkazu, bude cílovým objektem úplně jiný objekt.
- Objekt příkazu, směrované argumenty události, objekt události: objekt, který je předán ze zdroje do objektu Command / Action, do objektu Target do kódu, který provádí práci. Každé kliknutí na tlačítko nebo klávesová zkratka má za následek nový objekt příkazu / události. Některé implementace přidávají více informací k objektu příkazu / události při jeho předávání z jednoho objektu (např. CopyCommand) do druhého (např. Sekce dokumentu). Jiné implementace umisťují objekty příkazů / událostí do jiných objektů událostí (například do pole uvnitř většího pole), když se pohybují po řádku, aby nedocházelo ke konfliktům pojmenování. (Viz také řetězec odpovědnosti.)
- Handler, ExecutedRoutedEventHandler, metoda, funkce: skutečný kód, který provádí kopírování, vkládání, přesouvání atd. V některých implementacích je kód obslužné rutiny součástí objektu příkazu / akce. V jiných implementacích je kód součástí přijímače / cílového objektu a v ještě dalších implementacích je kód obslužné rutiny udržován odděleně od ostatních objektů.
- Správce příkazů, zpět správce, plánovač, fronta, dispečer, vyvolávač: objekt, který vkládá objekty příkazů / událostí do zásobníku zpět nebo znovu, nebo který se drží objektů příkazů / událostí, dokud na ně nejsou připraveny jiné objekty, nebo který směruje objekty příkazů / událostí k příslušnému přijímači / cíli kód objektu nebo obslužné rutiny.
- Implementace, které přesahují původní vzor příkazu.
- Microsoft Windows Presentation Foundation (WPF), zavádí směrované příkazy, které kombinují vzor příkazu se zpracováním události. Výsledkem je, že objekt příkazu již neobsahuje odkaz na cílový objekt ani odkaz na kód aplikace. Místo toho vyvolání objektu příkazu vykonat Výsledkem příkazu je tzv Provedená směrovaná událost že během tunelování nebo probublávání akce může dojít k tzv vazba objekt, který identifikuje cíl a kód aplikace, který je spuštěn v tomto bodě.
Příklad
Zvažte „jednoduchý“ přepínač. V tomto příkladu nakonfigurujeme přepínač pomocí dvou příkazů: zapnutí světla a vypnutí světla.
Výhodou této konkrétní implementace povelového vzoru je, že přepínač lze použít s jakýmkoli zařízením, nejen s osvětlením. Přepínač v následující implementaci C # zapíná a vypíná světlo, ale konstruktor přepínače je schopen přijmout všechny podtřídy příkazu pro své dva parametry. Přepínač můžete například nakonfigurovat tak, aby spouštěl motor.
použitím Systém;jmenný prostor CommandPattern{ veřejnost rozhraní ICommand { prázdnota Vykonat(); } / * Třída Invoker * / veřejnost třída Přepínač { ICommand _closedCommand; ICommand _otevřený příkaz; veřejnost Přepínač(ICommand closedCommand, ICommand openedCommand) { tento._closedCommand = closedCommand; tento._otevřený příkaz = openedCommand; } // Uzavřete obvod / zapněte napájení veřejnost prázdnota Zavřít() { tento._closedCommand.Vykonat(); } // Otevřete obvod / vypněte napájení veřejnost prázdnota Otevřeno() { tento._otevřený příkaz.Vykonat(); } } / * Rozhraní, které definuje akce, které může přijímač provádět * / veřejnost rozhraní ISwitchable { prázdnota Zapnutí(); prázdnota Vypnout(); } / * Třída přijímače * / veřejnost třída Světlo : ISwitchable { veřejnost prázdnota Zapnutí() { Řídicí panel.WriteLine("Světlo svítí"); } veřejnost prázdnota Vypnout() { Řídicí panel.WriteLine(„Světlo nesvítí“); } } / * Příkaz pro vypnutí zařízení - ConcreteCommand # 1 * / veřejnost třída ZavřítPříkaz : ICommand { soukromé ISpínatelné _přepínatelné; veřejnost ZavřítPříkaz(ISpínatelné přepínatelné) { _přepínatelné = přepínatelné; } veřejnost prázdnota Vykonat() { _přepínatelné.Vypnout(); } } / * Příkaz pro zapnutí zařízení - ConcreteCommand # 2 * / veřejnost třída OpenSwitchCommand : ICommand { soukromé ISpínatelné _přepínatelné; veřejnost OpenSwitchCommand(ISwitchable přepínatelné) { _přepínatelné = přepínatelné; } veřejnost prázdnota Vykonat() { _přepínatelné.Zapnutí(); } } / * Testovací třída nebo klient * / vnitřní třída Program { veřejnost statický prázdnota Hlavní(tětiva[] argumenty) { tětiva argument = argumenty.Délka > 0 ? argumenty[0].ToUpper() : nula; ISpínatelné svítilna = Nový Světlo(); // Předá každému příkazu odkaz na instanci lampy ICommand switchClose = Nový ZavřítPříkaz(svítilna); ICommand switchOpen = Nový OpenSwitchCommand(svítilna); // Předání odkazu na instance objektů Command do přepínače Přepínač @přepínač = Nový Přepínač(switchClose, switchOpen); -li (argument == "NA") { // Přepínač (vyvolávač) vyvolá Execute () na objekt příkazu. @přepínač.Otevřeno(); } jiný -li (argument == "VYPNUTO") { // Přepínač (vyvolávač) vyvolá Execute () na objekt příkazu. @přepínač.Zavřít(); } jiný { Řídicí panel.WriteLine(Je vyžadován argument „ZAPNUTO“ nebo „VYPNUTO“. “); } } }}
Viz také
- Dávková fronta
- Uzavření
- Příkazová fronta
- Funkční objekt
- Plánovač úloh
- Řadič zobrazení modelu
- Prioritní fronta
- Softwarový návrhový vzor
- GoF - návrhové vzory
Reference
- ^ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Návrhové vzory: Prvky opakovaně použitelného objektově orientovaného softwaru. Addison Wesley. str.233ff. ISBN 0-201-63361-2.CS1 maint: více jmen: seznam autorů (odkaz)
- ^ „Návrhový vzor příkazu - problém, řešení a použitelnost“. w3sDesign.com. Citováno 2017-08-12.
- ^ „Návrhový vzor příkazu - struktura a spolupráce“. w3sDesign.com. Citováno 2017-08-12.