Servant (Služebník)

Návrhové vzory Servant (Služebník)

Návrhový vzor Služebník použijeme tehdy, chceme-li několika třídám přidat další funkčnost, aniž bychom zasahovali do jejich rozhraní. Služebník nám tak přidává novou funkčnost, aniž by musel být v dané třídě. Jedná se o idiom. Není tedy zařazen mezi „ty pravé“ návrhové vzory z GoF. Jeho použití je ale někdy velmi užitečné.

Motivace

Někdy se můžeme dostat do situace, kdy máme určitou skupinu tříd, kterým chceme přidat další funkčnost. Přímou implementací bychom ale tuto funkčnost museli zkopírovat do každé z nich, což je při programování popř. rozšiřování aplikace dálnice do pekel (nehledě na to, že tím porušujeme princip DRY). Další možností je samozřejmě definovat společného předka, ale to také nelze vždy udělat. Funkčnost, o kterou chceme třídy rozšířit, s nimi totiž nemusí vůbec souviset. Třídy by se pak musely starat o víc věcí naráz (princip SRP, který je také velmi důležitý při návrhu). V takovém případě můžeme funkčnost vyčlenit do samostatné třídy (tzv. Služebník).

Vzor

Jedná se vlastně o takovou přepravku na metody, které obsluhují instance určité skupiny tříd. Služebník je samostatná třída, která obsahuje metody manipulující s instancemi původních tříd (dál jen jako obsluhované). Budeme-li chtít po nějaké obsluhované třídě splnit určitou úlohu (třeba plynulý posun - animaci), požádáme o tuto úlohu služebníka, kterému předáme právě instanci obsluhované třídy. Služebník pak bude s obsluhovanými třídami komunikovat přes nějaké rozhraní (např. IMovable - v tomto případě poskytne metody jako setPoint a getPoint, abychom mohli objekt postupně posouvat). Toto rozhraní musíme pochopitelně také implementovat všem třídám, se kterými bude služebník pracovat.

V podstatě můžeme vzor Služebník implementovat dvěma způsoby: obsluhovaná třída nemusí o služebníkovi vědět vůbec nic (ukázka - UML diagram 1), nebo naopak o služebníkovi nemusí nic vědět uživatel (ukázka - UML diagram 2). V prvním případě se dotazujeme na určitou úlohu přímo obsluhované třídy přes služebníka, kterému musíme předat instanci obsluhované třídy. V tom druhém o nějakém služebníku nemusíme nic vědět. Po dotázání na určitou úlohu obsluhované třídy si zavolá metodu služebníka sama obsluhovaná metoda. Obě tyto implementace jsou správné. Záleží na vás, jak budete chtít služebníka implementovat.

Operace požaduje uživatel od samotného služebníka

Operace požaduje uživatel od samotného služebníka

Operace požaduje uživatel od obsluhované třídy

Operace požaduje uživatel od obsluhované třídy

Jak můžeme vyčíst z diagramu, každá třída, která chce být obsloužena, implementuje rozhraní IObsluhovatelný. Služebník pak pracuje pouze s tímto rozhraním. Pokud bychom chtěli služebníka pro animaci, budeme nejspíš potřebovat již zmíněné metody getPoint() a setPoint(Point), díky kterým bychom mohli posouvat obsluhovanou instancí (resp. nějaký graficky objekt, který představuje). Příklady se liší ve vazbě uživatele na služebníka. Zatímco v prvním případě má uživatel ke služebníkovi přímou vazbu, v druhém je volán až obsluhovanými třídami a uživatel na něj tedy nemá přímou vazbu, čehož lze využít třeba pro zapouzdření.

Závěr

Vzor Služebník použijeme tehdy, cheme-li přidat skupině tříd nějakou schopnost a nechceme ji přitom implementovat do původní třídy. Je realizován samostatnou třídou, která manipuluje s obsluhovanou instancí (resp. s jejím rozhranním). Jedná se o idiom a není tedy v GoF.


 

  Aktivity (1)

Článek pro vás napsal Drahomír Hanák
Avatar
Autor v současné době studuje Informatiku. Zajímá se o programování, matematiku a grafiku.

Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!


 


Miniatura
Všechny články v sekci
Návrhové vzory
Miniatura
Následující článek
Proxy (zástupce)

 

 

Komentáře

Avatar
rainbof
Člen
Avatar
rainbof:

"Operace požaduje uživatel od samotného služebníka"
http://www.itnetwork.cz/…ervant-2.png

nechápu. podlož nějakým kódem prosím.

 
Odpovědět 6.2.2013 11:23
Avatar
Drahomír Hanák
Tým ITnetwork
Avatar
Odpovídá na rainbof
Drahomír Hanák:

Ten popisek patří k tomu prvnímu diagramu ;)

Máš prostě nějakou třídu Služebník, která přes rozhraní komunikuje s obsluhovaným objektem. Něco na stylu:

// Rozhraní, přes které komunikuje
interface IPosuvnyObjekt
{
    public void setPoint(int x, int y) { ... }
}

// Obsluhovaný objekt - čtverec
class Ctverec implements IPosuvnyObjekt
{
    ...
}

// Služebník, přidávající funkci animace
class SluzebnikAnimace
{
    public void animuj(IPosuvnyObjekt obsluhovany)
    {
        obsluhovany.setPoint(...);
    }
}

Přičemž ty voláš metodu animuj na SluzebnikAnimace (obsluhovaný objekt mu můžeš předat třeba v konstruktoru nebo v metodě, záleží na situaci), ne na obsluhované třídě (na Obdélníku). V tom druhém případě by si obsluhovaný objekt (obdélník) sám držel instanci služebníka (poskytující animaci) a volal by jeho metody sám ani bys nemusel vědět, že existuje.

 
Odpovědět 6.2.2013 21:01
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.