Komentář: neutrální text textu, nyní částečně jako průvodce
Služebník (anglicky Servant) je návrhový vzor využívaný v objektově orientovaném programování. Tento vzor řeší problém, kdy potřebujeme definovat společnou funkčnost pro instance více tříd současně, přičemž tyto třídy nemohou mít společného rodiče, kam bychom definici této funkčnosti umístili.
Motivace
Návrhový vzor Služebník využijeme v případě, když:
Několik tříd potřebuje definovat stejnou činnost a nechceme definovat na několika místech stejný kód
Objekt má úkol, který naprogramovat buď neumíme, nebo bychom jej sice zvládli, ale víme, že je úloha již naprogramovaná jinde
Připravujeme řešení, které chceme definovat dostatečně obecné, aby je mohli používat všichni, kteří je budou v budoucnu potřebovat, a přitom nevíme, kdo budou ti potřební
Implementace vzoru
Služebník nepracuje sám, ale komunikuje s obsluhovanými instancemi.
Aby mohl instance bezproblémově obsluhovat, klade na ně požadavky,
co všechno musejí obsluhované instance umět
Služebník:
Definuje rozhraní, v němž deklaruje své požadavky na obsluhované instance
Metody služebníka pak budou akceptovat instance tohoto rozhraní jako své parametry
Instance, která chce být obsloužena:
Implementuje příslušné rozhraní, aby se mohla vydávat za jeho instanci. Implementací tohoto rozhraní deklaruje, že umí to, co od ní služebník k její plnohodnotné obsluze požaduje.
Terminologie
V následujícím popisu jsou použity termíny:
klient – objekt, který něco požaduje po obsluhovaných objektech.
služebník – objekt, který nabízí nějakou službu objektům, implementujícím rozhraní IObsluhovaný
IObsluhovaný – rozhraní, jehož implementaci vyžaduje služebník od obsluhovaných objektů
obsluhovaný – Objekt, který implementuje rozhraní IObsluhovaný a je proto schopen být obsluhován služebníkem.
Možná použití
Návrhový vzor Služebník používám ve dvou drobně odlišných situacích.
Služebníka zná obsluhovaný objekt
V prvním případě Klient (Client) posílá Obsluhovanému objektu zprávu se svým požadavkem. Obsluhovaný neumí nebo nechce na zprávu reagovat sám, a proto si 'pozve' Služebníka, který mu pomůže požadovanou funkci realizovat, a předá se jeho metodě jako parametr. Klient přitom vůbec nemusí vědět, že Obsluhovaný použil služeb Služebníka.
Příklad
Tento jednoduchý příklad v programovacím jazyce Java ukazuje situaci, kdy Služebníka (Servant) zná Obsluhovaný (User) objekt. Příklad je pouze ilustrativní a neposkytuje žádné vykreslování geometrických objektů, ani specifikace jak vypadají.
// MoveServant je trida poskytujici funkcionalitu// tridam implementujicim interface MovablepublicclassMoveServant{// Metoda, ktera presune jakoukoliv tridu implementujici Movable// na zcela novou pozicipublicvoidmove(Movableserviced,PositionAbsoluteabsolute){// nastavi novou poziciserviced.setPosition(absolute);}// Metoda, ktera presune jakoukoliv tridu implementujici Movable// na pozici, posunutou v obou smerech o PositionRelativepublicvoidmove(Movableserviced,PositionRelativerelative){// nacte aktualni absolutni pozici objektu servicedPositionAbsoluteposition=serviced.getPosition();// posune aktualni pozici PositionAbsolute o pozici relativni PositionRelativeposition.add(relative);// a aktualizuje vysledekserviced.setPosition(position);}}// Interface urcujici, co obsluhovane tridy musi implementovat, aby// mohli byt obslouzeny servantem MoveServantpublicinterfaceMovable{// metoda setPosition, ktera umoznuje presouvat MovablepublicvoidsetPosition(PositionAbsolutep);// metoda getPosition, ktera umoznuje ziskat polohupublicPositionAbsolutegetPosition();}// trojuhelnik implementujici rozhrani MovablepublicclassTriangleimplementsMovable{privatePositionAbsolutep;// pro urceni pozice trojuhelniku@OverridepublicvoidsetPosition(PositionAbsolutep){// nastaveni pozice trojuhelnikuthis.p=p;}@OverridepublicPositionAbsolutegetPosition(){// ziskani pozice trojuhelnikureturnthis.p;}}// ctyrstran implementujici rozhrani MovablepublicclassRectangleimplementsMovable{privatePositionAbsolutep;// pro urceni pozice ctyrstranu@OverridepublicvoidsetPosition(PositionAbsolutep){// nastaveni pozice ctyrstranuthis.p=p;}@OverridepublicPositionAbsolutegetPosition(){// ziskani pozice ctyrstranureturnthis.p;}}publicclassPositionAbsolute{//absolutni poziceprivateintx;//souradnice xprivateinty;//souradnice ypublicintgetX(){returnx;}//getter pro xpublicintgetY(){returny;}//getter pro y//pricte k absolutni pozici relativnipublicvoidadd(PositionRelativerelative){x+=relative.getX();y+=relative.getY();}publicPositionAbsolute(intsx,intsy){//konstruktor teto tridyx=sx;y=sy;}}publicclassPositionRelative{//relativni pozice/posunutiprivateintx;//souradnice xprivateinty;//souradnice ypublicintgetX(){returnx;}//getter pro xpublicintgetY(){returny;}//getter pro ypublicPositionRelative(intdx,intdy){//konstruktor teto tridyx=dx;y=dy;}}publicclassClient{publicstaticvoidmain(String[]args){MoveServantms=newMoveServant();ms.move(newTriangle(),newPositionAbsolute(10,10));MoveServantms2=newMoveServant();ms2.move(newRectangle(),newPositionRelative(5,5));}}
Služebníka zná klientský objekt
V druhém případě Klient (Client) ví, že Obsluhovaný objekt implementuje rozhraní Obsluhovaný (Movable) a že klientem požadovanou službu umí splnit Služebník (MoveServant). Zavolá proto Služebníka sám a předá mu Obsluhovaný objekt (Triangle nebo Rectangle) jako parametr. Obsluhovaný v tomto případě vůbec nemusí vědět, že je předáván jako parametr některé z metod Služebníka a že je následně obsluhován Služebníkem.
Příklad
Tento jednoduchý příklad v programovacím jazyce Java ukazuje situaci, kdy Služebníka (Servant) zná Klientský (Serviced) objekt. Příklad je pouze ilustrativní a neposkytuje žádné vykreslování geometrických objektů, ani specifikace jak vypadají.
// MoveServant je trida poskytujici funkcionalitu// tridam implementujicim interface MovablepublicclassMoveServant{// Metoda, ktera presune jakoukoliv tridu implementujici Movable// na zcela novou pozicipublicvoidmove(Movableserviced,PositionAbsoluteabsolute){// nastavi novou poziciserviced.setPosition(absolute);}// Metoda, ktera presune jakoukoliv tridu implementujici Movable// na pozici, posunutou v obou smerech o PositionRelativepublicvoidmove(Movableserviced,PositionRelativerelative){// nacte aktualni absolutni pozici objektu servicedPositionAbsoluteposition=serviced.getPosition();// posune aktualni pozici PositionAbsolute o pozici relativni PositionRelativeposition.add(relative);// a aktualizuje vysledekserviced.setPosition(position);}}// Interface urcujici, co obsluhovane tridy musi implementovat, aby// mohli byt obslouzeny servantem MoveServantpublicinterfaceMovable{// metoda setPosition, ktera umoznuje presouvat MovablepublicvoidsetPosition(PositionAbsolutep);// metoda getPosition, ktera umoznuje ziskat polohupublicPositionAbsolutegetPosition();}// trojuhelnik implementujici rozhrani MovablepublicclassTriangleimplementsMovable{privatePositionAbsolutep;// pro urceni pozice trojuhelniku@OverridepublicvoidsetPosition(PositionAbsolutep){// nastaveni pozice trojuhelnikuthis.p=p;}@OverridepublicPositionAbsolutegetPosition(){// ziskani pozice trojuhelnikureturnthis.p;}publicvoidmove(PositionAbsoluteabsolute){MoveServantms=newMoveServant();ms.move(this,absolute);}publicvoidmove(PositionRelativerelative){MoveServantms=newMoveServant();ms.move(this,relative);}}// ctyrstran implementujici rozhrani MovablepublicclassRectangleimplementsMovable{privatePositionAbsolutep;// pro urceni pozice ctyrstranu@OverridepublicvoidsetPosition(PositionAbsolutep){// nastaveni pozice ctyrstranuthis.p=p;}@OverridepublicPositionAbsolutegetPosition(){// ziskani pozice ctyrstranureturnthis.p;}publicvoidmove(PositionAbsoluteabsolute){MoveServantms=newMoveServant();ms.move(this,absolute);}publicvoidmove(PositionRelativerelative){MoveServantms=newMoveServant();ms.move(this,relative);}}publicclassPositionAbsolute{//absolutni poziceprivateintx;//souradnice xprivateinty;//souradnice ypublicintgetX(){returnx;}//getter pro xpublicintgetY(){returny;}//getter pro y//pricte k absolutni pozici relativnipublicvoidadd(PositionRelativerelative){x+=relative.getX();y+=relative.getY();}publicPositionAbsolute(intsx,intsy){//konstruktor teto tridyx=sx;y=sy;}}publicclassPositionRelative{//relativni pozice/posunutiprivateintx;//souradnice xprivateinty;//souradnice ypublicintgetX(){returnx;}//getter pro xpublicintgetY(){returny;}//getter pro ypublicPositionRelative(intdx,intdy){//konstruktor teto tridyx=dx;y=dy;}}publicclassClient{publicstaticvoidmain(String[]args){Triangletriangle=newTriangle();triangle.move(newPositionAbsolute(10,10));Rectanglerectangle=newRectangle();rectangle.move(newPositionRelative(5,5));}}
Podobné návrhové vzory
Návrhový vzor Služebník je velmi podobný vzoru Command (Příkaz). Architektura je stejná, liší se pouze posloupností úvah architekta aplikace.
PECINOVSKÝ, Rudolf. Myslíme objektově v jazyku Java – Kompletní učebnice pro začátečníky, 2. aktualizované a rozšířené vydání.. [s.l.]: Grada, 2009. ISBN978-80-247-2653-3.