Introducción
El patrón Chain of Responsibility es un patrón de diseño de comportamiento que permite que un objeto pase una solicitud a lo largo de una cadena de manejadores. Al recibir una solicitud, cada manejador decide si procesa la solicitud o la pasa al siguiente manejador en la cadena.
Conceptos Clave
- Manejador (Handler): Interfaz o clase abstracta que define un método para manejar las solicitudes.
- Solicitud (Request): La operación o mensaje que se quiere procesar.
- Cadena (Chain): Secuencia de manejadores que procesan la solicitud.
Ventajas
- Desacoplamiento: El emisor de la solicitud no necesita conocer la estructura de la cadena ni los manejadores específicos.
- Flexibilidad: Es fácil añadir o cambiar manejadores sin modificar el código existente.
Desventajas
- Depuración: Puede ser difícil de depurar y entender el flujo de la solicitud a través de la cadena.
- Rendimiento: Si la cadena es muy larga, puede afectar el rendimiento.
Estructura
La estructura básica del patrón Chain of Responsibility incluye los siguientes componentes:
- Handler (Manejador): Define una interfaz para manejar las solicitudes.
- ConcreteHandler (Manejador Concreto): Implementa el manejo de las solicitudes. Puede acceder al siguiente manejador en la cadena.
- Client (Cliente): Inicia la solicitud a un manejador en la cadena.
Diagrama UML
+----------------+ +---------------------+ | Client | | Handler | |----------------| |---------------------| | - handler: | | + handleRequest(): | | Handler | | void | +----------------+ +---------------------+ | ^ | | v | +----------------+ +---------------------+ |ConcreteHandler1| |ConcreteHandler2 | |----------------| |---------------------| | + handleRequest(): | | + handleRequest(): | | void | | void | +----------------+ +---------------------+
Implementación en Código
A continuación, se muestra una implementación del patrón Chain of Responsibility en Python:
Ejemplo en Python
class Handler: def __init__(self, successor=None): self._successor = successor def handle_request(self, request): raise NotImplementedError("Subclasses must implement this method") class ConcreteHandler1(Handler): def handle_request(self, request): if 0 < request <= 10: print(f"ConcreteHandler1 handled request {request}") elif self._successor: self._successor.handle_request(request) class ConcreteHandler2(Handler): def handle_request(self, request): if 10 < request <= 20: print(f"ConcreteHandler2 handled request {request}") elif self._successor: self._successor.handle_request(request) class ConcreteHandler3(Handler): def handle_request(self, request): if 20 < request <= 30: print(f"ConcreteHandler3 handled request {request}") elif self._successor: self._successor.handle_request(request) # Client code if __name__ == "__main__": # Create handlers handler1 = ConcreteHandler1() handler2 = ConcreteHandler2(handler1) handler3 = ConcreteHandler3(handler2) # Create requests requests = [5, 14, 22, 18, 3, 27] # Process requests for request in requests: handler3.handle_request(request)
Explicación del Código
- Handler: Clase base abstracta que define el método
handle_request
. - ConcreteHandler1, ConcreteHandler2, ConcreteHandler3: Clases concretas que implementan el método
handle_request
y manejan las solicitudes dentro de un rango específico. - Client Code: Crea una cadena de manejadores y procesa una lista de solicitudes.
Ejercicio Práctico
Ejercicio
Implemente una cadena de responsabilidad para manejar solicitudes de soporte técnico. La cadena debe incluir los siguientes niveles de soporte:
- Soporte Básico: Maneja solicitudes de nivel 1.
- Soporte Intermedio: Maneja solicitudes de nivel 2.
- Soporte Avanzado: Maneja solicitudes de nivel 3.
Cada manejador debe imprimir un mensaje indicando que ha manejado la solicitud o pasarla al siguiente nivel si no puede manejarla.
Solución
class SupportHandler: def __init__(self, successor=None): self._successor = successor def handle_request(self, level): raise NotImplementedError("Subclasses must implement this method") class BasicSupport(SupportHandler): def handle_request(self, level): if level == 1: print("BasicSupport handled the request") elif self._successor: self._successor.handle_request(level) class IntermediateSupport(SupportHandler): def handle_request(self, level): if level == 2: print("IntermediateSupport handled the request") elif self._successor: self._successor.handle_request(level) class AdvancedSupport(SupportHandler): def handle_request(self, level): if level == 3: print("AdvancedSupport handled the request") elif self._successor: self._successor.handle_request(level) # Client code if __name__ == "__main__": # Create handlers basic_support = BasicSupport() intermediate_support = IntermediateSupport(basic_support) advanced_support = AdvancedSupport(intermediate_support) # Create requests support_levels = [1, 2, 3, 2, 1, 3] # Process requests for level in support_levels: advanced_support.handle_request(level)
Explicación de la Solución
- SupportHandler: Clase base abstracta que define el método
handle_request
. - BasicSupport, IntermediateSupport, AdvancedSupport: Clases concretas que implementan el método
handle_request
y manejan solicitudes de diferentes niveles. - Client Code: Crea una cadena de manejadores de soporte y procesa una lista de solicitudes de soporte.
Conclusión
El patrón Chain of Responsibility es útil para desacoplar el emisor de una solicitud de sus manejadores, permitiendo una mayor flexibilidad y extensibilidad en el manejo de solicitudes. Sin embargo, es importante tener en cuenta las posibles dificultades en la depuración y el rendimiento cuando se utiliza este patrón en cadenas largas.
En el siguiente tema, exploraremos el patrón Command, otro patrón de comportamiento que encapsula una solicitud como un objeto, permitiendo parametrizar a los clientes con diferentes solicitudes, encolarlas o registrar solicitudes, y soportar operaciones que se pueden deshacer.
Curso de Patrones de Diseño de Software
Módulo 1: Introducción a los Patrones de Diseño
- ¿Qué son los Patrones de Diseño?
- Historia y Origen de los Patrones de Diseño
- Clasificación de los Patrones de Diseño
- Ventajas y Desventajas de Usar Patrones de Diseño
Módulo 2: Patrones Creacionales
- Introducción a los Patrones Creacionales
- Singleton
- Factory Method
- Abstract Factory
- Builder
- Prototype
Módulo 3: Patrones Estructurales
Módulo 4: Patrones de Comportamiento
- Introducción a los Patrones de Comportamiento
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Módulo 5: Aplicación de Patrones de Diseño
- Cómo Seleccionar el Patrón Adecuado
- Ejemplos Prácticos de Uso de Patrones
- Patrones de Diseño en Proyectos Reales
- Refactorización Usando Patrones de Diseño
Módulo 6: Patrones de Diseño Avanzados
- Patrones de Diseño en Arquitecturas Modernas
- Patrones de Diseño en Microservicios
- Patrones de Diseño en Sistemas Distribuidos
- Patrones de Diseño en Desarrollo Ágil