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:
- Handler (Manejador): Defineix una interfície per manejar les peticions i opcionalment per establir el següent manejador en la cadena.
- 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.
- 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
- Interfície Handler: Defineix els mètodes
setNextHandler
ihandleRequest
. - Classe AbstractHandler: Implementa la interfície Handler i proporciona una implementació per establir el següent manejador en la cadena.
- ConcreteHandlerA i ConcreteHandlerB: Implementen el mètode
handleRequest
per manejar peticions específiques. - 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ó
- Interfície SupportHandler: Defineix els mètodes
setNextHandler
ihandleRequest
. - Classe AbstractSupportHandler: Implementa la interfície SupportHandler i proporciona una implementació per establir el següent manejador en la cadena.
- BasicSupportHandler, AdvancedSupportHandler i ExpertSupportHandler: Implementen el mètode
handleRequest
per manejar problemes específics. - 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.
Curs de Patrons de Disseny de Programari
Mòdul 1: Introducció als Patrons de Disseny
- Què són els Patrons de Disseny?
- Història i Origen dels Patrons de Disseny
- Classificació dels Patrons de Disseny
- Avantatges i Desavantatges d'Usar Patrons de Disseny
Mòdul 2: Patrons Creacionals
Mòdul 3: Patrons Estructurals
Mòdul 4: Patrons de Comportament
- Introducció als Patrons de Comportament
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Mòdul 5: Aplicació de Patrons de Disseny
- Com Seleccionar el Patró Adequat
- Exemples Pràctics d'Ús de Patrons
- Patrons de Disseny en Projectes Reals
- Refactorització Usant Patrons de Disseny
Mòdul 6: Patrons de Disseny Avançats
- Patrons de Disseny en Arquitectures Modernes
- Patrons de Disseny en Microserveis
- Patrons de Disseny en Sistemes Distribuïts
- Patrons de Disseny en Desenvolupament Àgil