Chain-of-responsibility pattern

Da Wikipedia, l'enciclopedia libera.

Il Chain-of-responsibility è un design pattern utilizzato nella programmazione ad oggetti e definito nel famoso libro della Gang of Four.

Scopo del pattern[modifica | modifica wikitesto]

Il pattern permette di separare gli oggetti che invocano richieste, dagli oggetti che le gestiscono, dando ad ognuno la possibilità di gestire queste richieste. Viene utilizzato il termine catena perché di fatto la richiesta viene inviata e "segue la catena" di oggetti, passando da uno all'altro, finché non trova quello che la gestisce.

Applicabilità[modifica | modifica wikitesto]

Il pattern è comodo quando non conosciamo a priori quale oggetto è in grado di gestire una determinata richiesta, sia perché effettivamente è sconosciuto staticamente o sia perché l'insieme degli oggetti in grado di gestire richieste cambia dinamicamente a runtime.

Struttura[modifica | modifica wikitesto]

Struttura del pattern Chain-of-responsability

La struttura del pattern è piuttosto semplice, le componenti principali sono 2:

  • Handler, che rappresenta l'interfaccia che offre il metodo HandleRequest che sarà il metodo utilizzato dalle componenti per inoltrare richieste all'oggetto contenuto;
  • ConcreteHandler, che rappresenta l'effettiva implementazione della gestione degli eventi per un oggetto.

Ogni oggetto facente parte della catena deve implementare il metodo HandleRequest che gestirà il tipo di richiesta ricevuta (se è lui che se ne deve occupare), altrimenti chiamerà lo stesso metodo sull'oggetto contenuto all'interno (ed è per questo che si viene a formare una catena, allo stesso modo del pattern decorator).

Esempio[modifica | modifica wikitesto]

Java[modifica | modifica wikitesto]

Qui viene presentato un esempio del pattern in Java. Nell'esempio vi sono differenti ruoli ognuno con un limite massimo per un acquisto e un successore. Ogni volta che una prersona (che ha un determinato ruolo) riceve un ordine di acquisto che sorpassa il proprio limite, passa la richiesta al successore nella catena di comando.

Classe astratta PurchasePower con il metodo astratto processRequest.

abstract class PurchasePower {
    protected static final double BASE = 500;
    protected PurchasePower successor;

    abstract protected double getAllowable();
    abstract protected String getRole();

    public void setSuccessor(PurchasePower successor) {
        this.successor = successor;
    }

    public void processRequest(PurchaseRequest request){
        if (request.getAmount() < this.getAllowable()) {
            System.out.println(this.getRole() + " will approve $" + request.getAmount());
        } else if (successor != null) {
            successor.processRequest(request);
        }
    }
}

Quattro implementazioni della classe astratta con quattro ruoli: Manager, Director, Vice President, President

class ManagerPPower extends PurchasePower {
    
    protected double getAllowable(){
        return BASE*10;
    }

    protected String getRole(){
        return "Manager";
    }
}

class DirectorPPower extends PurchasePower {
    
    protected double getAllowable(){
        return BASE*20;
    }

    protected String getRole(){
        return "Director";
    }
}

class VicePresidentPPower extends PurchasePower {
    
    protected double getAllowable(){
        return BASE*40;
    }

    protected String getRole(){
        return "Vice President";
    }
}

class PresidentPPower extends PurchasePower {

    protected double getAllowable(){
        return BASE*60;
    }

    protected String getRole(){
        return "President";
    }
}

Classe PurchaseRequest che contiene i dati di una richiesta d'acquisto.

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;
    }
}

Nel seguente esempio la catena delle gerarchie è così definita: 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);
        }
    }
}

Altri progetti[modifica | modifica wikitesto]