Command Pattern és a pénzügy/számvitel
2 min readMost, hogy a mai napi orbitális szívás programozási kihívásokon túlestem, ideje megosztani az infót valami másról, hogy mások is szívjanak annyit, mint én.

A Command tervezési minta egy az adat-vezérelt minták közül és viselkedési minták közé tartozik. Lényege annyi, hogy a kérés egy objektumba van csomagolva, ilyen formában kerül átadásra az ún. invoker objektum karmai közé. Az utána megkeresi az illetékes ojjektumot ami képes ennek a "parancsnak" a teljesítésére és átadja annak, ami ezek után jó katonához híven teljesíti is azt.
Akkor most nézzük meg, hogy is lehet outsource-olni a problémát egy másik fejlesztőnek? Ha már annyit beszélgettünk megrendelésekről Martin papával, akkor most ismét legyen ez a téma.
Tegyük fel, hogy tőzsdézünk. Ennélfogva eladni/venni fogunk, viszont mindkettő egy "megrendelés" lesz. Ennélfogva azokat valamilan módon ebből az osztályból kellene származtatni. Sőt! Mivel a fenti kettő megvalósításának logikája nagyban eltér egymástól (no meg interfészt fogunk typehintelni), ezért interfészként fogjuk definiálni.
[tabs type="horizontal"][tabs_head][tab_title]PHP[/tab_title][/tabs_head][tab]
<?php interface Order { // a jól szituált megrendelés interfész public function execute(); // lesz egy végrehajtás metódusa minden megrendelésnek }
[/tab][/tabs]
Ez lesz a Command pattern-ünk interfésze, viszont nem ártana meg is valósítani mindezt, mint a levegőbe beszélni, nemde? Ahhoz, hogy bármilyen részvényt megvegyünk, nem ártana maga a részvény, nemde? Hozzuk létre ezt, valamint az eladás/vétel "parancsait":
[tabs type="horizontal"][tabs_head][tab_title]PHP[/tab_title][/tabs_head][tab]
<?php class Stock { // a részvényünk, a'la value object. Ezt fogjuk type hintelni, hiszen nem lehet csak úgy mindenféle részvényt megvenni! private $name = "Letscode"; // nem ártana vállalkozási formát váltanom... private $quantity = 10; // 10 részvényt kezelünk public function buy() { echo $quantity. " darab ". $name . " részvényt megvettek."; } public function sell() { // legyen valami bizonyíték is, nemde echo $quantity. " darab ". $name . " részvényt eladtak."; } } class BuyStock implements Order { // ezzel tudjuk majd jól megvenni a részvényeket private $stock; // a részvényünket itt tároljuk public function __construct(Stock $stock) { $this->stock = $stock; // átadjuk neki a konstruktorban a részvényt, amire vonatkozik } public function execute() { // az interfész megkötése $this->stock->buy(); // a parancs végrehajtásakor megvesszük a részvényt } } class SellStock implements Order { // ezzel tudjuk majd jól eladni a részvényeket private $stock; // a részvényünket itt tároljuk public function __construct(Stock $stock) { $this->stock = $stock; // átadjuk neki a konstruktorban a részvényt, amire vonatkozik } public function execute() { // az interfész megkötése $this->stock->sell(); // a parancs végrehajtásakor eladjuk a részvényt } }
[/tab][/tabs]
Most, hogy megvan a részvény, megvan a parancs rá, hogy vegyél,
igyál, eladj, nem ártana megkreálni a kis droidot, aki teljesíti a kis parancsainkat!
[tabs type="horizontal"][tabs_head][tab_title]PHP[/tab_title][/tabs_head][tab]
<?php class Broker { // a mi kis brókerünk, aki éhbérért az egekig röpít minket private $orderList = array(); // a megrendeléseket tartalmazó tömb public function takeOrder(Order $order) { // itt tudunk neki parancsokat adni $this->orderList[] = $order; // amiket beleoktrojál a tömbbe } public function placeOrders() { // itt pedig elvégzi a feladatot amiért fizetjük foreach ($this->orderList as $order) { // végigmegyünk az ordereken $order->execute(); // nem tudjuk, hogy az vétel/adás, viszont azt tudjuk, hogy mivel az Order interfészt implementálta, ezért végrehajtható } $this->orderList = array(); // kiűrítjük a listánkat } } // na akkor nézzük hogy is tudjuk munkára fogni a kis minion-unkat! $stock = new Stock(); // egy jóféle letscode részvény! $broker = new Broker(); // felveszünk egy új brókert $broker->takeOrder(new BuyStock($stock)); // adunk neki egy parancsot, miszerint vegyen egy ilyen részvényt $broker->takeOrder(new SellStock($stock)); // majd eladunk egy ilyet // megjegyzés: a fentiek még nem kerültek végrehajtásra, szóval ha időközben lelövik a brókerünket, akkor nem vesz semmit $broker->placeOrders(); // megmondjuk neki, hogy most rögtön végezze el a feladatot
[/tab][/tabs]
A command pattern igen egyszerű minta, mint láthatjuk és ezért nem egy nagy ördöngősség elsajátítani. Segítségével a parancsokat egy végrehajtási sorba tehetjük, megjegyezhetjük azok végrehajtását, visszamondhatjuk, stb. Elválaszthatjuk az objektumot ami kéri az adott feladatot attól ami konkrétan elvégzi és a kettő között egy jól átjárható interfészt hozhatunk létre.
A sellatockban sell kellene a buy helyett az execute functionbe, nem?
Dede, köszi hogy szóltál, javítva!
Nincs mit, szuperek a cikkeid és nagyon jók amiket a mintákrol írsz, jöhetne még belőle több is 🙂 plusz a laravelbol 😛
Köszi a pozitív megerősítést, örülök ha tetszik. Lesz még bőven cikk mindkettőről, nem kell félni, csak sok mindenről írnék és elég nehéz dönteni, hogy mi is legyen az. Egyébként majd pesten lehet Schönherz kereteken belül előadok, na meg készülőben egy online oktatási felület is.
Szuper! Az online biztos érdekelne, pesten sajna ritkán járok…