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
Java példa
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
A Cocoa és a Cocoa Touch keretrendszer
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
- Egyszeres felelősség elve
További információk
- https://web.archive.org/web/20180227070352/http://www.blackwasp.co.uk/ChainOfResponsibility.aspx
Fordítá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.