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_requesty 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_requesty 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
