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

Programtervezési minták
Java-kódpéldák
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 = 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 =* 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 =* 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 =* 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 =* 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 Programtervezési minták Java-kódpéldák