Introducció

El patró de disseny Chain of Responsibility (Cadena de Responsabilitat) és un patró de comportament que permet que un objecte passi una petició a una cadena d'objectes potencials per manejar-la. Aquest patró és útil quan es vol evitar el coupling entre l'emissor d'una petició i el seu receptor, permetent que múltiples objectes tinguin l'oportunitat de processar la petició.

Objectius del Patró

  • Desacoblar l'emissor del receptor: Permet que l'emissor d'una petició no conegui quin objecte la processarà.
  • Flexibilitat en el maneig de peticions: Facilita l'addició o modificació de manejadors sense afectar altres parts del sistema.
  • Responsabilitat compartida: Permet que múltiples objectes tinguin l'oportunitat de processar la petició.

Estructura del Patró

El patró Chain of Responsibility es compon de les següents parts:

  1. Handler (Manejador): Defineix una interfície per manejar les peticions i opcionalment per establir el següent manejador en la cadena.
  2. ConcreteHandler (Manejador Concret): Implementa la interfície del manejador i processa les peticions que pot manejar. Si no pot manejar una petició, la passa al següent manejador en la cadena.
  3. Client (Client): Inicia la petició al primer manejador de la cadena.

Diagrama UML

+-----------------+        +-----------------+
|    Client       |        |    Handler      |
|-----------------|        |-----------------|
| - handler: Handler |----->| + handleRequest(): void |
+-----------------+        +-----------------+
                                    |
                                    v
                          +-----------------+
                          | ConcreteHandler |
                          |-----------------|
                          | + handleRequest(): void |
                          +-----------------+

Implementació en Codi

A continuació es mostra una implementació del patró Chain of Responsibility en Java:

// Interfície Handler
interface Handler {
    void setNextHandler(Handler handler);
    void handleRequest(String request);
}

// Classe abstracta ConcreteHandler
abstract class AbstractHandler implements Handler {
    protected Handler nextHandler;

    @Override
    public void setNextHandler(Handler handler) {
        this.nextHandler = handler;
    }

    @Override
    public void handleRequest(String request) {
        if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }
}

// Manejador concret A
class ConcreteHandlerA extends AbstractHandler {
    @Override
    public void handleRequest(String request) {
        if (request.equals("A")) {
            System.out.println("ConcreteHandlerA handled the request.");
        } else {
            super.handleRequest(request);
        }
    }
}

// Manejador concret B
class ConcreteHandlerB extends AbstractHandler {
    @Override
    public void handleRequest(String request) {
        if (request.equals("B")) {
            System.out.println("ConcreteHandlerB handled the request.");
        } else {
            super.handleRequest(request);
        }
    }
}

// Client
public class Client {
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();

        handlerA.setNextHandler(handlerB);

        handlerA.handleRequest("A");
        handlerA.handleRequest("B");
        handlerA.handleRequest("C");
    }
}

Explicació del Codi

  1. Interfície Handler: Defineix els mètodes setNextHandler i handleRequest.
  2. Classe AbstractHandler: Implementa la interfície Handler i proporciona una implementació per establir el següent manejador en la cadena.
  3. ConcreteHandlerA i ConcreteHandlerB: Implementen el mètode handleRequest per manejar peticions específiques.
  4. Client: Configura la cadena de manejadors i envia peticions.

Exercicis Pràctics

Exercici 1

Implementa un sistema de suport tècnic utilitzant el patró Chain of Responsibility. El sistema ha de tenir tres nivells de suport: Suport Bàsic, Suport Avançat i Suport Expert. Cada nivell ha de manejar diferents tipus de problemes.

Solució

// Interfície Handler
interface SupportHandler {
    void setNextHandler(SupportHandler handler);
    void handleRequest(String issue);
}

// Classe abstracta AbstractSupportHandler
abstract class AbstractSupportHandler implements SupportHandler {
    protected SupportHandler nextHandler;

    @Override
    public void setNextHandler(SupportHandler handler) {
        this.nextHandler = handler;
    }

    @Override
    public void handleRequest(String issue) {
        if (nextHandler != null) {
            nextHandler.handleRequest(issue);
        }
    }
}

// Suport Bàsic
class BasicSupportHandler extends AbstractSupportHandler {
    @Override
    public void handleRequest(String issue) {
        if (issue.equals("basic")) {
            System.out.println("BasicSupportHandler handled the issue.");
        } else {
            super.handleRequest(issue);
        }
    }
}

// Suport Avançat
class AdvancedSupportHandler extends AbstractSupportHandler {
    @Override
    public void handleRequest(String issue) {
        if (issue.equals("advanced")) {
            System.out.println("AdvancedSupportHandler handled the issue.");
        } else {
            super.handleRequest(issue);
        }
    }
}

// Suport Expert
class ExpertSupportHandler extends AbstractSupportHandler {
    @Override
    public void handleRequest(String issue) {
        if (issue.equals("expert")) {
            System.out.println("ExpertSupportHandler handled the issue.");
        } else {
            super.handleRequest(issue);
        }
    }
}

// Client
public class SupportClient {
    public static void main(String[] args) {
        SupportHandler basicSupport = new BasicSupportHandler();
        SupportHandler advancedSupport = new AdvancedSupportHandler();
        SupportHandler expertSupport = new ExpertSupportHandler();

        basicSupport.setNextHandler(advancedSupport);
        advancedSupport.setNextHandler(expertSupport);

        basicSupport.handleRequest("basic");
        basicSupport.handleRequest("advanced");
        basicSupport.handleRequest("expert");
        basicSupport.handleRequest("unknown");
    }
}

Explicació de la Solució

  1. Interfície SupportHandler: Defineix els mètodes setNextHandler i handleRequest.
  2. Classe AbstractSupportHandler: Implementa la interfície SupportHandler i proporciona una implementació per establir el següent manejador en la cadena.
  3. BasicSupportHandler, AdvancedSupportHandler i ExpertSupportHandler: Implementen el mètode handleRequest per manejar problemes específics.
  4. SupportClient: Configura la cadena de manejadors i envia problemes.

Errors Comuns i Consells

  • No establir el següent manejador: Assegura't de configurar correctament la cadena de manejadors utilitzant el mètode setNextHandler.
  • No passar la petició al següent manejador: Si un manejador no pot processar una petició, ha de passar-la al següent manejador en la cadena.
  • Coupling entre manejadors: Evita el coupling directe entre manejadors per mantenir la flexibilitat i la facilitat de manteniment.

Resum

El patró Chain of Responsibility permet que una petició sigui manejada per una cadena d'objectes, desacoblant l'emissor del receptor i proporcionant flexibilitat en el maneig de peticions. Hem vist la seva estructura, implementació en codi i un exercici pràctic per reforçar els conceptes apresos. Amb aquest patró, pots crear sistemes més flexibles i mantenibles, on les responsabilitats es poden distribuir entre múltiples objectes.

© Copyright 2024. Tots els drets reservats