Sluha (návrhový vzor) - Servant (design pattern)
![]() | Tento článek má několik problémů. Prosím pomozte vylepši to nebo diskutovat o těchto problémech na internetu diskusní stránka. (Zjistěte, jak a kdy tyto zprávy ze šablony odebrat) (Zjistěte, jak a kdy odstranit tuto zprávu šablony)
|
v softwarové inženýrství, sluha vzor definuje objekt používaný k nabízení některých funkcí skupině třídy aniž by definoval tuto funkčnost v každém z nich. Sluha je třída, jejíž instance (nebo dokonce jen třída) poskytuje metody které se starají o požadovanou službu, zatímco předměty, pro které (nebo s kým) služebník něco dělá, jsou brány jako parametry.
Popis a jednoduchý příklad
Servant se používá k poskytování určitého chování skupině tříd. Místo toho, abychom definovali toto chování v každé třídě - nebo když toto chování nemůžeme vyloučit ve společné nadřazené třídě - je definováno jednou v Servantu.
Například: máme několik tříd představujících geometrické objekty (obdélník, elipsa a trojúhelník). Tyto objekty můžeme nakreslit na nějaké plátno. Když potřebujeme poskytnout metodu „přesunu“ pro tyto objekty, mohli bychom tuto metodu implementovat do každé třídy, nebo můžeme definovat rozhraní, které implementují, a poté nabídnout funkčnost „přesunu“ ve služebníkovi. Je definováno rozhraní, které zajišťuje, že obsluhované třídy mají metody, které obsluha potřebuje k zajištění požadovaného chování. Pokud budeme pokračovat v našem příkladu, definujeme rozhraní „Movable“ a určíme, že každá třída implementující toto rozhraní musí implementovat metodu „getPosition“ a „setPosition“. První metoda získá polohu objektu na plátně a druhá nastaví polohu objektu a nakreslí jej na plátno. Poté definujeme třídu služebníků „MoveServant“, která má dvě metody „moveTo (Movable moveObject, Position where)“ a moveBy (Movable moveObject, int dx, int dy). Třídu Servant lze nyní použít k přesunutí každého objektu, který implementuje Movable. „Pohybující se“ kód se tedy objevuje pouze v jedné třídě, která respektuje pravidlo „oddělení obav“.
Dva způsoby implementace
Existují dva způsoby, jak implementovat tento návrhový vzor.

- Uživatel zná služebníka (v takovém případě nepotřebuje znát obsluhované třídy) a posílá zprávy s jeho požadavky instancím služebníka a předává obsluhované objekty jako parametry.
- Obsluhované třídy (geometrické objekty z našeho příkladu) o služebníkovi nevědí, ale implementují rozhraní „IServiced“. Třída uživatelů pouze zavolá metodu služebníka a předá obsluhované objekty jako parametry. Tato situace je znázorněna na obrázku 1.

- Obsluhované instance obsluhu znají a uživatel jim zasílá zprávy se svými požadavky (v takovém případě nemusí obsluhu znát). Obsluhované instance poté odesílají zprávy instancím služebníka a žádají o službu.
- Na obrázku 2 je znázorněna opačná situace, kdy uživatel neví o třídě služebníků a volá přímo obsluhované třídy. Obsluhované třídy pak požádají samotné sluhy, aby dosáhli požadované funkce.
Jak implementovat Servant
- Analyzujte, o jaké chování by se měl sluha postarat. Z obsluhovaného parametru uveďte, jaké metody bude obsluha definovat a co tyto metody budou potřebovat. Jinými slovy, co musí obsluhovaná instance poskytovat, aby metody zaměstnanců mohly dosáhnout svých cílů.
- Analyzujte, jaké schopnosti musí mít třídy obsluhované, aby mohly být správně obsluhovány.
- Definujeme rozhraní, které vynutí implementaci deklarovaných metod.
- Definujte rozhraní určující požadované chování obsluhovaných objektů. Pokud chce nějaká instance obsluhovat obsluhu, musí implementovat toto rozhraní.
- Definujte (nebo nějakým způsobem získávejte) určeného sluhu (jeho třídu).
- Implementujte definované rozhraní se servisovanými třídami.
Příklad
Tento jednoduchý příklad ukazuje výše popsanou situaci. Tento příklad je pouze ilustrativní a nenabízí žádný skutečný výkres geometrických objektů ani specifikaci toho, jak vypadají.
// Třída služebníků, která nabízí své funkce implementovaným třídám// Pohyblivé rozhraníveřejnost třída MoveServant { // Metoda, která přesune Movable implementation class do pozice where veřejnost prázdnota Přesunout do(Pohyblivý servisováno, Pozice kde) { // Udělejte nějaké další věci, abyste zajistili hladký a pěkný pohyb, to je // místo, kde se funkce nabízí servisováno.setPosition(kde); } // Metoda, která přesune Movable implementation class by dx and dy veřejnost prázdnota moveBy(Pohyblivý servisováno, int dx, int dy) { // toto je místo, kde můžete tuto funkcionalitu nabídnout dx += servisováno.getPosition().xPozice; dy += servisováno.getPosition().yPozice; servisováno.setPosition(Nový Pozice(dx, dy)); }}// Rozhraní určující, jaké obsluhované třídy musí být implementovány// obsluhováno služebníkem.veřejnost rozhraní Pohyblivý { veřejnost prázdnota setPosition(Pozice str); veřejnost Pozice getPosition();}// Jedna z geometrických třídveřejnost třída Trojúhelník nářadí Pohyblivý { // Poloha geometrického objektu na nějakém plátně soukromé Pozice str; // Metoda, která nastavuje polohu geometrického objektu veřejnost prázdnota setPosition(Pozice str) { tento.str = str; } // Metoda, která vrací polohu geometrického objektu veřejnost Pozice getPosition() { vrátit se tento.str; }}// Jedna z geometrických třídveřejnost třída Elipsa nářadí Pohyblivý { // Poloha geometrického objektu na nějakém plátně soukromé Pozice str; // Metoda, která nastavuje polohu geometrického objektu veřejnost prázdnota setPosition(Pozice str) { tento.str = str; } // Metoda, která vrací polohu geometrického objektu veřejnost Pozice getPosition() { vrátit se tento.str; }}// Jedna z geometrických třídveřejnost třída Obdélník nářadí Pohyblivý { // Poloha geometrického objektu na nějakém plátně soukromé Pozice str; // Metoda, která nastavuje polohu geometrického objektu veřejnost prázdnota setPosition(Pozice str) { tento.str = str; } // Metoda, která vrací polohu geometrického objektu veřejnost Pozice getPosition() { vrátit se tento.str; }}// Jen velmi jednoduchá třída kontejneru pro pozici.veřejnost třída Pozice { veřejnost int xPozice; veřejnost int yPozice; veřejnost Pozice(int dx, int dy) { xPozice = dx; yPozice = dy; }}
Podobný návrhový vzor: Příkaz
Designové vzory Příkaz a Servant jsou velmi podobné a jejich implementace jsou často prakticky stejné. Rozdíl mezi nimi je v přístupu k problému.
- Pro vzor služebníka máme nějaké objekty, kterým chceme nabídnout určité funkce. Vytváříme třídu, jejíž instance tuto funkci nabízejí a která definuje rozhraní, které musí obsluhované objekty implementovat. Obsluhované instance se potom předají jako parametry služebníkovi.
- Pro příkazový vzor máme některé objekty, které chceme upravit pomocí některých funkcí. Takže definujeme rozhraní, které příkazy, které požadovaná funkce musí být implementovány. Instance těchto příkazů jsou poté předávány původním objektům jako parametry jejich metod.
I když jsou návrhové vzory Command a Servant podobné, neznamená to, že to tak vždy je. Existuje řada situací, kdy použití příkazu návrhového vzoru nesouvisí s návrhovým vzorem Servant. V těchto situacích obvykle potřebujeme předat volaným metodám pouze odkaz na jinou metodu, kterou bude potřebovat k dosažení svého cíle. Protože nemůžeme předat odkazy na metody v mnoha jazycích, musíme předat objekt implementující rozhraní, které deklaruje podpis předané metody.
Viz také
Zdroje
Pecinovský, Rudolf; Jarmila Pavlíčková; Luboš Pavlíček (červen 2006). Pojďme nejprve upravit objekty nejprve do návrhových vzorů (PDF). Jedenáctá výroční konference o inovacích a technologiích ve výuce informatiky na Boloňské univerzitě.