Patrones de diseño de comportamiento: Chain of Responsability

Intención del patrón

  • Evitar el acoplamiento entre el emisor de una solicitud y quien la recibe dando a más de un objeto la posibilidad de atender la solicitud. Encadenamiento de objetos que reciben y pasan las solicitudes a lo largo de la cadena hasta un objeto que la maneja.
  • Lanzar y liberar solicitudes con una canalización de procesamiento individual que contiene muchos posibles "manejadores".
  • Una lista enlazada orientada a objeto con recursividad transversal.

Ejemplo de problema

Existe un potencialmente variable número de "manejadores", "elementos de procesamiento" o "nodos" y una gran cantidad de peticiones que deben ser manejadas. La necesidad de procesar eficientemente las solicitudes sin relacionar manera dura los manejadores y las precedencias; o mapeos entre la solicitud y el manejador.


Discusión

Encapsular los elementos de procesamiento en una abstracción de canal (pipeline) y los clientes del tipo lanzar y liberar (launch and leve) tienen sus peticiones a la entrada de la tubería.

Este patrón, recibe conjuntos de objetos.y entonces pasa cualquier solicitud de un objeto a otro hasta que se alcanza uno capaz de administrarla. El número y tipo de objetos "manejadores" no es conocido en primera instancia, ya que ellos pueden ser configurados dinámicamente. El mecanismo de encadenado utiliza composición recursiva para permitir un número ilimitado de manejadores para ser enlazados.
Chain of Responsability simplifica las interconexiones entre objetos. En lugar de utilizar emisores y receptores (senders and receivers) manteniendo referencias a todos los posibles receptores candidatos, cada emisor mantiene una única referencia al primer eslabón de la cadena y cada receptor mantiene una sola referencia a su sucesor inmediato en la cadena.
Se debe estar seguro de la existencia de una "red de seguridad" para "atrapar" cualquier solicitud que se encuentre sin manejar.
No debe usarse este patrón cuando cada solicitud es manejada por un solo administrador o, cuando el objeto cliente conoce cuál es el servicio que debe administrar su solicitud.

Estructura

Las clases derivadas conocen cómo satisfacer la solicitud del cliente.Si el objeto "actual" no está disponible o no es suficiente, entonces delega a la clase base, la cual, a su vez, delega hacia el siguiente objeto y el círculo de vida continúa.


Múltiples administradores podrían contribuir a la administración de cada solicitud. Ésta puede ser pasada a todo el largo de la cadena, teniendo en cuenta que el último no debería delegar hacia un "siguiente nulo".

Ejemplo

El patrón Chain of Responsability evita el acoplamiento entre el emisor de una solicitud y el receptor de la misma mediante el otorgamiento de más de un objeto con la posibilidad de administrar dicha solicitud. ATM utiliza este patrón en el mecanismo de entrega de dinero


Check list

  1. La clase base mantiene un puntero al "siguiente" objeto.
  2. Cada clase derivada implementa su contribución al manejo de la solicitud.
  3. Si la solicitud necesita ser "pasada", entonces, la clase derivada llama a la clase base para que ésta la delegue hacia el siguiente objeto administrador.
  4. El cliente crea y enlaza la cadena (la cual puede incluir un enlace desde el último objeto hacia el objeto raíz).
  5. El cliente "lanza y libera" cada solicitud al nodo raíz.

Reglas de oro


  • Chain of Responsability, Command, Mediator y Observer indican cómo se puede desacoplar a los emisores de los receptores, pero con diferentes ventajas y desventajas. Chain of Responsability pasa una solicitud a lo largo de toda una cadena de posibles receptores.
  • Chain of Responsability puede usar Command para representar solicitudes como objetos.
  • Chain of Responsability es a menudo aplicada en conjunto con Composite. Allí, los padres de un componente pueden actuar como su sucesor.


Ejemplo de código en C#

using System;

class MainApp
{
  static void Main()
  {
    // Setup Chain of Responsibility 
    Handler h1 = new ConcreteHandler1();
    Handler h2 = new ConcreteHandler2();
    Handler h3 = new ConcreteHandler3();
    h1.SetSuccessor(h2);
    h2.SetSuccessor(h3);

    // Generate and process request 
    int[] requests = {2, 5, 14, 22, 18, 3, 27, 20};

    foreach (int request in requests)
    {
      h1.HandleRequest(request);
    }

    // Wait for user 
    Console.Read();
  }
}

// "Handler" 
abstract class Handler 
{
  protected Handler successor;

  public void SetSuccessor(Handler successor)
  {
    this.successor = successor;
  }

  public abstract void HandleRequest(int request);
}

// "ConcreteHandler1" 
class ConcreteHandler1 : Handler
{
  public override void HandleRequest(int request)
  {
    if (request >= 0 && request < 10)
    {
      Console.WriteLine("{0} handled request {1}", 
        this.GetType().Name, request);
    }
    else if (successor != null)
    {
      successor.HandleRequest(request);
    }
  }
}

// "ConcreteHandler2" 
class ConcreteHandler2 : Handler
{
  public override void HandleRequest(int request)
  {
    if (request >= 10 && request < 20)
    {
      Console.WriteLine("{0} handled request {1}", 
        this.GetType().Name, request);
    }
    else if (successor != null)
    {
      successor.HandleRequest(request);
    }
  }
}

// "ConcreteHandler3" 
class ConcreteHandler3 : Handler
{
  public override void HandleRequest(int request)
  {
    if (request >= 20 && request < 30)
    {
      Console.WriteLine("{0} handled request {1}", 
        this.GetType().Name, request);
    }
    else if (successor != null)
    {
      successor.HandleRequest(request);
    }
  }
}

3 comentarios:

Anónimo dijo...

quiero ventajas

Anónimo dijo...

quiero ventajas

Juan Barrionuevo dijo...

Podrías ser más específico?

Publicar un comentario

Muchas gracias por leer el post y comentarlo.

 
Copyright 2009 Programación SOLIDa
BloggerTheme by BloggerThemes | Design by 9thsphere