Felelősséglánc programtervezési minta
Az objektumorientált tervezésben a felelősséglánc egy tervezési minta, amely parancsobjektumokból és feldolgozó objektumokból áll. Minden egyes feldolgozó objektum tartalmazza azt a logikát, amellyel a parancsobjektum definiálható és kezelhető, valamint olyan folyamatokat, amiket kidolgozásra továbbadhat a lánc egy következő folyamatának. Olyan mechanizmus is létezik, amivel lehetőségünk adódik arra, hogy a felelősséglánc végén egy újabb feldolgozó objektumot adjunk hozzá.
A standard felelősséglánc egyik variációja úgy viselkedik, mint egy diszpécserközpont, mert képes parancsokat küldeni különböző irányokba, amivel át tudja alakítani a felelősségláncot. Bizonyos esetekben előfordulhat rekurzió. Ez akkor történik, amikor az éppen aktuálisan futó objektum meghív egy magasabban futó műveletet egy paranccsal, aminek az a célja, hogy a futó objektum kisebb részekre vágásával megpróbálja megoldani a problémát. Ebben az esetben a rekurzió vagy addig folytatódik, amíg a parancs futását le nem állítjuk, vagy addig, amíg az összes ágat be nem futja. Az XML fordító működik rekurzív módon.
Ez a tervezési minta hozzájárult a laza csatoltság ötletéhez, ami az egyik legjobb programozási gyakorlatnak tekinthető.
Példa
[szerkesztés]Java példa
[szerkesztés]Az alábbi példa bemutatja a tervezési mintát Java nyelven. Ebben a példában különböző szerepeket mutatunk be, ezek mindegyike tartalmaz egy fix fizetési limitet, valamint öröklődést. Minden alkalommal, amikor a felhasználó meghívja a fizetési kérést, és a kérésben szereplő összeg meghaladja a fixre állított fizetési limitet, a kérést átadja az osztály a gyermekének.
A PhurchasePower egy abstract osztály, egy processRequest nevű absztrakt metódussal.
abstract class PurchasePower {
protected static final double BASE = 500;
protected PurchasePower successor;
public void setSuccessor(PurchasePower successor) {
this.successor = successor;
}
abstract public void processRequest(PurchaseRequest request);
}
Az abstract osztály felett négy megvalósítás van: Manager, Director, Vice President, President.
class ManagerPPower extends PurchasePower {
private final double ALLOWABLE = 10 * BASE;
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < ALLOWABLE) {
System.out.println("Manager will approve $" + request.getAmount());
} else if (successor != null) {
successor.processRequest(request);
}
}
}
class DirectorPPower extends PurchasePower {
private final double ALLOWABLE = 20 * BASE;
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < ALLOWABLE) {
System.out.println("Director will approve $" + request.getAmount());
} else if (successor != null) {
successor.processRequest(request);
}
}
}
class VicePresidentPPower extends PurchasePower {
private final double ALLOWABLE = 40 * BASE;
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < ALLOWABLE) {
System.out.println("Vice President will approve $" + request.getAmount());
} else if (successor != null) {
successor.processRequest(request);
}
}
}
class PresidentPPower extends PurchasePower {
private final double ALLOWABLE = 60 * BASE;
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < ALLOWABLE) {
System.out.println("President will approve $" + request.getAmount());
} else {
System.out.println( "Your request for $" + request.getAmount() + " needs a board meeting!");
}
}
}
A következő kód definiálja a PurchaseRequest osztályt és beállítja a kért adatokat.
class PurchaseRequest {
private double amount;
private String purpose;
public PurchaseRequest(double amount, String purpose) {
this.amount = amount;
this.purpose = purpose;
}
public double getAmount() {
return amount;
}
public void setAmount(double amt) {
amount = amt;
}
public String getPurpose() {
return purpose;
}
public void setPurpose(String reason) {
purpose = reason;
}
}
A következő példában az örökös osztályok beállítják a korábban definiált megvalósításokat, ebben a sorrendben: Manager -> Director -> Vice President -> President.
class CheckAuthority {
public static void main(String[] args) {
ManagerPPower manager = new ManagerPPower();
DirectorPPower director = new DirectorPPower();
VicePresidentPPower vp = new VicePresidentPPower();
PresidentPPower president = new PresidentPPower();
manager.setSuccessor(director);
director.setSuccessor(vp);
vp.setSuccessor(president);
// Press Ctrl+C to end.
try {
while (true) {
System.out.println("Enter the amount to check who should approve your expenditure.");
System.out.print(">");
double d = Double.parseDouble(new BufferedReader(new InputStreamReader(System.in)).readLine());
manager.processRequest(new PurchaseRequest(d, "General"));
}
} catch(Exception e) {
System.exit(1);
}
}
}
Megvalósítások
[szerkesztés]A Cocoa és a Cocoa Touch keretrendszer
[szerkesztés]A Cocoa és Cocoa Touch keretrendszert az OS X és iOS operációs rendszerek használják. A két keretrendszer gyakran használja a felelősséglánc tervezési mintát az események kezelésére.Az objektumok meghívnak egy válaszadó objektumot, ami öröklődik az NSResponder (OS X)/UIResponder (iOS) osztályokban. Az összes nézet objektumban (NSView/UIView), nézetet irányító objektumban (NSViewController/UIViewController), ablak objektumokban (NSWindow/UIWindow), valamint az applikációs objektumban (NSApplication/UIApplication) van válaszadó objektum
Tipikusan, amikor a nézet kap egy eseményt, amit nem tud kezelni, kiszervezi azt a nézet irányító, vagy az ablak objektumokba. Ha ezek az objektumok sem tudják kezelni az eseményt, akkor ők is kiszervezik az applikációs objektum felé, ami a láncban az utolsó objektum.
Például:
- OS X-en, amikor megmozdítasz egy ablakot az egérrel, akkor azt normál estben bárhová le lehet tenni. Kivételt képez az a helyzet, amikor egy másik esemény útban van (pl. csúszkairányító), Ha nincs nézet (vagy szupernézet), hogy azt lekezelje, akkor az operációs rendszer elküldi az eseményt a felelősségláncba, átadva így a felelősséget annak.
- iOS-en éppen a mozgatott esemény az, amelyik vezeti a hierarchiát a nézet alatti osztály helyett. Övé a prioritás, és ha ez problémát okoz, akkor a válaszadó lánc felfüggeszti az összes nézeteseményt, és lekezelni a problémás részt.
Kapcsolódó szócikkek
[szerkesztés]További információk
[szerkesztés]Fordítás
[szerkesztés]Ez a szócikk részben vagy egészben a Chain-of-responsibility 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.