miércoles, 29 de abril de 2015

Chain of Responsability


Chain of Responsability

Propósito

Establecer una cadena en un sistema, para que un mensaje pueda ser manejado en el nivel en el que se recibe en primer lugar, o ser redirigido a un objeto que pueda manejarlo.


También conocido como: Chain of Responsability (Cadena de Responsabilidad)


Motivación

La petición debe ser procesada por los receptores, lo cual quiere decir que, ésta petición queda al margen del uso exclusivo.

Pretendemos dar una mayor detalle y especificación a las peticiones generadas. Las peticiones serán filtradas por todos los receptores a medida que se van generando los resultados esperados.

Aplicabilidad

El patrón Cadena de Responsabilidad debe usarse cuando: 

  • Hay más de un objeto que puede manejar una petición, y el manejador no se conoce a priori, sino que debería determinarse automáticamente. 
  • Se quiere enviar una petición a un objeto entre varios sin especificar explícitamente el receptor. 
  • El conjunto de objetos que pueden tratar una petición debería ser especificado dinámicamente. 

Estructura





Participantes


Handler (Aprobación): Define una interface para el manejo de las solicitudes.

(optional):  implementa el sucesor de enlaces.

ConcreteHandler (Director, VicePresidente, Presidente): Se ocupa de las solicitudes, es responsable del acceso al sucesor del enlace. Si el ConcreteHandler puede manejar la solicitud, de lo contrario envía la solicitud a un sucesor.

Client (ChainApp): Inicia la solicitud de un objeto ConcreteHandler en la cadena.


Colaboraciones

Cuando un cliente envía una petición, ésta se propaga a través de la cadena hasta que un objeto ManejadorConcreto se hace responsable de procesarla.


Consecuencias


Las ventajas de este patrón son:

  • Reduce el acoplamiento. El patrón libera a un objeto de tener que saber qué otro objeto maneja una petición. Ni el receptor ni el emisor se conocen explícitamente entre ellos, y un objeto de la cadena tampoco tiene que conocer la estructura de ésta. Por lo tanto, simplifica las interconexiones entre objetos. En vez de que los objetos mantengan referencias a todos los posibles receptores, sólo tienen una única referencia a su sucesor. 
  • Añade flexibilidad para asignar responsabilidades a objetos. Se pueden añadir o cambiar responsabilidades entre objetos para tratar una petición modificando la cadena de ejecución en tiempo de ejecución. Esto se puede combinar con la herencia para especializar los manejadores estáticamente. 
Por otra parte presenta el inconveniente de no garantizar la recepción. Dado que las peticiones no tienen un receptor explícito, no hay garantías de que sean manejadas. La petición puede alcanzar el final de la cadena sin haber sido procesada.


Implementacion

Implementación de la cadena sucesora. Hay dos formas posibles de implementarla: 

  • Definir nuevos enlaces (normalmente en el Manejador, pero también podría ser en los objetos ManejadorConcreto). 
  • Usar enlaces existentes (otras asociaciones existentes). Por ejemplo, en el patrón Composición puede existir ya un enlace al padre que puede utilizarse para definir la cadena de responsabilidad sin necesidad de añadir otra asociación. 
  • Conexión de los sucesores. Si no hay referencias preexistentes para definir una cadena, entonces tendremos que introducirlas nosotros mismos. En este caso, el Manejador define la interfaz y además, se encarga de mantener el sucesor. Esto permite que el manejador proporcione una implementación predeterminada de ManejarPetición que reenvíe la petición al sucesor (si hay alguno). Si una subclase de ManejadorConcreto no está interesada en dicha petición, no tiene que redefinir la operación de reenvío. 
  • Representación de peticiones. Hay varias opciones para representar las peticiones: 
  • Una petición es una invocación a una operación insertada en el código. Esto resulta conveniente y seguro, pero sólo se pueden reenviar el conjunto prefijado de peticiones que define la clase Manejador. 
  • Una única función manejadora que reciba un código de petición como parámetro. Esto permite un número arbitrario de peticiones pero emisor y receptor deben ponerse de acuerdo sobre cómo codificarse la petición. 

Código de ejemplo

El cliente hace una petición y según la elección, se crea o se hace la accion dependiendo la clase que tenga esa responsabilidad.

public abstract class Pinturas { 
/*public static int ERR = 3; 
public static int NOTICE = 5; 
public static int DEBUG = 7; 
*/ protected String color; 
protected Pinturas next; 
// el siguiente elemento en la cadena 
public Pinturas setNext(Pinturas l) 
next = l;
return this; 
abstract public void mensaje(String msg); 
public class PinturaBlanca extends Pinturas{ public PinturaBlanca() 
this.color = "Blanca"; 
//this.mask = mask; 
public void mensaje( String msg ) 
if (color.compareTo(msg) == 0) 
System.out.println("Pintamos de Blanco"); 
}
else 
if (next != null) 
next.mensaje(msg); 
public class PinturaAzul extends Pinturas{ public PinturaAzul() 
this.color = "Azul"; 
//this.mask = mask; 
public void mensaje( String msg ) 
if (color.compareTo(msg) == 0) 
System.out.println("Pintamos de Azul"); 
}
else 
if (next != null) 
next.mensaje(msg); 
public class PinturaAmarilla extends Pinturas{ public PinturaAmarilla() 
{
this.color = "Amarillo"; 
//this.mask = mask; 
public void mensaje( String msg ) 
if (color.compareTo(msg) == 0) 
System.out.println("Pintamos de Amarillo"); 
}
else 
if (next != null) 
next.mensaje(msg); 
public class Cliente { 
public static void main(String[] args) 
// Construimos la cadena Pinturas pint = new PinturaAzul().setNext( new PinturaBlanca().setNext( new PinturaAmarilla() ) );
pint.mensaje("Amarillo"); 
}

Usos conocidos
  • Varias bibliotecas de clases usan este patrón para manejar los eventos de usuario. Aunque usan nombres distintos, la idea es siempre la misma: cuando el usuario hace clic con el ratón o pulsa una tecla, se genera un evento y se pasa a lo largo de la cadena. 
  • El framework de editores gráficos Unidraw define objetos que encapsulan peticiones a los objetos Component y ComponentView. Estos objetos se estructuran jerárquicamente, así pueden reenviar interpretaciones de órdenes a su padre, quien a su vez puede reenviarlas, formando una cadena de responsabilidad. 
  • ET++ usa una cadena de responsabilidad para tratar la actualización de gráficos. Un objeto gráfico llama a una operación cada vez que quiere actualizarse, pero el objeto no sabe lo suficiente sobre su contexto, por lo tanto la operación debe reenviar la petición. 
Patrones relacionados

El patrón Cadena de Responsabilidad se suele aplicar junto con el patrón Composite. En él, los padres de los componentes pueden actuar como sucesores.


Referencias

  • Design Patterns Elements of Reusable Object-Oriented Software, GoF.
  • http://kybele.escet.urjc.es/documentos/SI/Patrones/05_Chain.ppt
  • http://dmi.uib.es/~yuhua/APOO07-08/Presentation/ChRespons.pdf

No hay comentarios:

Publicar un comentario