A szolga egy programtervezési minta, amit akkor használunk, ha osztályok egy csoportja számára szeretnénk néhány funkciót készíteni anélkül, hogy minden funkciót hozzájuk rendelnénk egyesével. A Szolga egy olyan osztály, melynek példánya (vagy csak maga az osztály) olyan metódusokat biztosit, melyek a kívánt szolgáltatást ellátják, miközben az objektumok, melyeknek (vagy melyekkel) a szolga tesz valamit, paraméterként jelennek meg.
Szolgát használunk, ha osztályok valamilyen csoportja számára valamilyen viselkedést szeretnénk biztosítani. Ahelyett, hogy ezt a viselkedést minden osztályban külön definiálnánk – vagy amikor nem tudjuk ezt a viselkedést alkalmazni a közös ős osztály esetén – csak egyszer definiálunk, a szolgában.
Például: van néhány osztályunk, melyek geometriai objektumokat jelölnek (téglalap, ellipszis és háromszög). Ábrázolhatjuk ezeket vásznon. Amikor 'mozgatás' metódust szeretnénk adni ezeknek az objektumoknak lehetőségünk van minden osztályban külön implementálni ezt a metódust, vagy megadhatunk egy implementálandó interfészt, majd felajánlhatjuk a szolga 'mozgatás' metódusát. Meghatározunk egy interfészt, hogy biztosítsuk a kiszolgált osztályoknak vannak olyan metódusai, melyre a szolgának szüksége van a kívánt viselkedés biztosításához. Ha folytatjuk korábbi példánkat, létrehozunk egy 'Movable' interfészt, mely megszabja, hogy minden osztályban, mely ezt az interfészt implementálja, legyen egy 'getPosition' és egy 'setPosition' metódus. Az első metódus feladata, hogy megszerezze a vásznon lévő objektum pozícióját, míg a második meghatározza az objektum elhelyezkedését és megrajzolja azt a vásznon. Majd létrehozunk egy 'MoveServant' szolga osztályt, melynek két metódusa lesz: 'moveTo(Moveable movedObject, Position where)' és 'MoveBy(moveable movedObect, int dx, int dy). Most már használhatjuk a szolga osztályt, hogy mozgassunk minden objektumot, mely implementálja a Moveable-t. Így a 'moving' kód csak egy osztályban jelenik meg a kódban, mely tiszteletben tartja a 'Separation of Concerns' szabályt.
Két lehetséges mód van, hogy implementáljuk ezt a tervezési mintát.
Ez az egyszerű példa bemutatja a fent leírt szituációt. Csak illusztráció és nem teszti lehetővé az objektumok tényleges kirajzolását, vagy annak meghatározását, hogy hogyan néznek ki.
// Szolga osztály, mely a Movable interface-t implementáló osztályoknak ajánlja szolgáltatásait
public class MoveServant {
// Függvény, mely átmozgatja a Movable implementáló interfészt olyan pozícióba, ahol
public void moveTo(Movable serviced, Position where) {
// Itt további funkciókat adhatunk meg, melynek segítségével a mozgatás szebbé tehető
serviced.setPosition(where);
}
// Függvény, mely elmozgatja a Movable implementációs osztályt dx és dy értékkel
public void moveBy(Movable serviced, int dx, int dy) {
// Itt további funkciókat adhatunk meg
dx += serviced.getPosition().xPosition;
dy += serviced.getPosition().yPosition;
serviced.setPosition(new Position(dx, dy));
}
}
// Interfész, mely meghatározza, hogy mely kiszolgált osztályokat kell implementálni, kiszolgálni a Szolgának.
public interface Movable {
public void setPosition(Position p);
public Position getPosition();
}
// Az egyik geometriai osztály
public class Triangle implements Movable {
// A geometriai alakzat helye valamely vásznon
private Position p;
// Függvény, mely átállítja a geometriai alakzat pozícióját
public void setPosition(Position p) {
this.p = p;
}
// Függvény, mely visszaadja a geometriai alakzat pozícióját
public Position getPosition() {
return this.p;
}
}
// A másik geometriai osztály
public class Ellipse implements Movable {
// A geometriai alakzat helye valamely vásznon
private Position p;
// Függvény, mely átállítja a geometriai alakzat pozícióját
public void setPosition(Position p) {
this.p = p;
}
// Függvény, mely visszaadja a geometriai alakzat pozícióját
public Position getPosition() {
return this.p;
}
}
// A harmadik geometriai osztály
public class Rectangle implements Movable {
// A geometriai alakzat helye valamely vásznon
private Position p;
// Függvény, mely átállítja a geometriai alakzat pozícióját
public void setPosition(Position p) {
this.p = p;
}
// Függvény, mely visszaadja a geometriai alakzat pozícióját
public Position getPosition() {
return this.p;
}
}
// Egyszerű konténer osztály a pozicionáláshoz
public class Position {
public int xPosition;
public int yPosition;
public Position(int dx, int dy) {
xPosition = dx;
yPosition = dy;
}
}
Két nagyon hasonló tervezési minta a szolga és parancs, olyannyira, hogy megvalósításuk gyakran látszólag teljesen azonos. A kettő között a különbség a megközelítésben található.
Annak ellenére, hogy ez a két tervezési minta nagyon hasonló, ez nem feltétlenül igaz minden esetben. Számos olyan eset ismert, ahol a parancs minta alkalmazása teljesen eltér a szolga mintától. Ezekben az esetekben a meghívott függvénynek csak egy másik függvényre hivatkozó referenciát kell átadni, mely segít a célunk elérésében. Mivel sok nyelvben nem adhatunk referenciát függvényeknek (pl Java), a referencia helyett egy olyan osztályt kell megalkotnunk, mely implementál egy interfészt, amely elfogadja az átadott metódus aláírását.
Pecinovský, Rudolf (2006. június 1.). „Let’s Modify the Objects First Approach into Design Patterns First”. Eleventh Annual Conference on Innovation and Technology in Computer Science Education, University of Bologna.
Ez a szócikk részben vagy egészben a Servant (design pattern) című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.