Patrones de Diseño (XIV): Patrones de Comportamiento - Chain of Responsability

Vamos a revisar el último grupo de patrones de diseño, los patrones de comportamiento, que definen las interacciones y responsabilidades de los objetos.

Los patrones de comportamiento más conocidos son: Chain of Responsibility, Command, Interpreter, Mediator, Memento, Observer, State, Strategy, Template Method y Visitor.

En esta entrega vamos a hablar de Chain of Responsability, patrón cuyo objetivo principal es desacoplar al emisor de un mensaje del receptor del mismo, permitiendo de esta manera que más de un objeto responda.

El nombre viene a raíz de su funcionamiento, ya que trata de encadenar a los receptores del mensaje que irán pasándoselo hasta que uno de ellos lo procese. Veamos la plantilla:

Chain of Responsability


Nombre: Chain of Responsability

Problema y Contexto:

Cuando hay comunicación entre 2 objetos, normalmente estos se acoplan mediante una conexión. Pretendemos desacoplar el sistema, pero nuestro problema es que el receptor del mensaje no va a conocer directamente el origen del mismo. El patrón Chain of Resbonsability trata de resolver esta situación.

Se aplica cuando:

  • Varios objetos pueden manejar cierta petición, y el manejador no se conoce a priori, sino que debería determinarse automáticamente.
  • Pretendemos enviar un mensaje a un objeto entre varios sin especificar explícitamente el receptor.
  • Los objetos que pueden tratar el mensaje deberían ser especificados dinámicamente.

Solución y Estructura:

Para solucionar este problema debemos encontrar un mecanismo mediante el cual pasar mensajes a través la cadena de objetos, para que si el que lo recibe no sabe procesarlo lo pase a otro objeto.

Para lograr esto, crearemos una interfaz Manejador que permite tratar las peticiones en general. Crearemos también algunos ManejadoresConcretos que son los que se encargan de procesar una petición concreta. El cliente que desea enviar el mensaje pasará el mismo a un Manejardor concreto, que se encargará o bien de procesarlo o bien de transferirlo a otros objetos que pertenezcan a la cadena.

La estructura es la siguiente:

https://upload.wikimedia.org/wikipedia/commons/1/1f/Chain_of_responsibility.jpg

Donde:

Manejador: Interfaz que define las operaciones necesarias para tratar los mensajes y propagarlos si corresponde.

ManejadorConcreto: Implementa la interfaz Manejador. Se encarga de procesar un tipo de mensaje concreto o propagar el mensaje a otro miembro de la cadena en caso de que el mensaje no sea de dicho tipo.

Client: Trata de enviar un mensaje a un destino propagándolo mediante un Manejador conocido.

Consecuencias:

POSITIVAS:

  • Elimina o reduce el acoplamiento existente entre el emisor y el receptor del mensaje.
  • Flexibilidad a la hora de establecer las responsabilidades, permitiendo modificarlas en tiempo de ejecución.

NEGATIVAS:

  • No garantiza la recepción.


Patrones Relacionados: Composite

Ejemplo:

Vamos a ver este patrón mediante un ejemplo, como siempre. En el ejemplo, el Cliente de la cadena será un confidente que pasará un mensaje encriptado a una cadena de responsabilidad formada por policías. Según la encriptación del mensaje, este puede ser entendido por uno o más miembros de la cadena de responsabilidad.

// NOTA: la clase Mensaje no está implemntada por simplicidad e irrelevancia 
// Mensaje tiene los métodos siguientes:
// Mensaje(String codificacion, String text);
// String obtenerCodificacion();
// String desencriptar(String key);

// En primer lugar definiremos la clase abstracta ManejadorMensaje
public absatract class ManejadorMensaje{
ManejadorMensaje proximo;

public void establecerProximo(ManejadorMensaje proximo){
this.proximo = proximo;
}

public abstract void manejarMensaje(Mensaje msg);
}

// Seguiremos con el manejador concreto PolicíaEstándar
public class PoliciaEstandar extends ManejadorMensaje{
private String key = "0069A0";
@Override
public void manejarMensaje(Mensaje msg){
if(msg.obtenerCodificacion().equals("base"))
System.out.println(desencriptar(key));
else
this.proximo.manejarMensaje(msg);
}
}

// Otro manejador concreto PolicíaEspecial
public class PoliciaEspecial extends ManejadorMensaje{
private String key = "0A89E4";
@Override
public void manejarMensaje(Mensaje msg){
if(msg.obtenerCodificacion().equals("especial"))
System.out.println(desencriptar(key));
else
this.proximo.manejarMensaje(msg);
}
}

// Por ultimo crearemos PolicíaElite
public class PoliciaElite extends ManejadorMensaje{
private String master_key = "F0FEF2";
@Override
public void manejarMensaje(Mensaje msg){
System.out.println(desencriptar(master_key));
}
}

// Ahora crearemos la clase principal de nuestro cliente
// Le pasará el mensaje codificado a la cadena de policías
public static void main(String [] args){
ManejadorMensaje policia1 = new PoliciaEstandar();
ManejadorMensaje policia2 = new PoliciaEspecial();
ManejadorMensaje policia3 = new PoliciaElite();

policia1.establecerProximo(policia2);
policia2.establecerProximo(policia3);

Mensaje mensaje = new Mensaje("especial", "Este mensaje va para la policía especial");

policia1.manejarMensaje(mensaje);

mensaje = new Mensaje("top-secret", "Este mensaje va para la policía de élite");
policia1.manejarMensaje(mensaje);
}

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP