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:

  1. Handler (Manejador): Define una interfaz para manejar las solicitudes.
  2. ConcreteHandler (Manejador Concreto): Implementa el manejo de las solicitudes. Puede acceder al siguiente manejador en la cadena.
  3. 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

  1. Handler: Clase base abstracta que define el método handle_request.
  2. ConcreteHandler1, ConcreteHandler2, ConcreteHandler3: Clases concretas que implementan el método handle_request y manejan las solicitudes dentro de un rango específico.
  3. 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:

  1. Soporte Básico: Maneja solicitudes de nivel 1.
  2. Soporte Intermedio: Maneja solicitudes de nivel 2.
  3. 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

  1. SupportHandler: Clase base abstracta que define el método handle_request.
  2. BasicSupport, IntermediateSupport, AdvancedSupport: Clases concretas que implementan el método handle_request y manejan solicitudes de diferentes niveles.
  3. 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.

© Copyright 2024. Todos los derechos reservados