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
setNextHandlerihandleRequest. - 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
handleRequestper 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
setNextHandlerihandleRequest. - 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
handleRequestper 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
