fbpx
Wikipedia

Cadena de responsabilidad

El patrón de diseño o cadena de responsabilidad es un patrón de comportamiento que evita acoplar el emisor de una petición a su receptor dando a más de un objeto la posibilidad de responder a una petición. Para ello, se encadenan los receptores y pasa la petición a través de la cadena hasta que es procesada por algún objeto. Este patrón es utilizado a menudo en el contexto de las interfaces gráficas de usuario donde un objeto puede estar compuesto de varios objetos (que generalmente heredan de una super clase "vista"). No se debe confundir con el patrón Composite (patrón de diseño) que se basa en un concepto similar. Según si el ambiente de ventanas genera eventos, los objetos los manejan o los "pasan" (transmiten) hasta que algún elemento consume dicho evento y se detiene la propagación. Un claro ejemplo de cadena de responsabilidades sería una estructura de datos que contiene nodos cuya implementación es opaca para el usuario de dicha estructura de datos (no conoce salvo la interfaz de la estructura de datos). Internamente los nodos se relacionan mediante punteros y una llamada a un método de la estructura de datos hará que un mensaje se propague por la cadena de nodos hasta llegar a su receptor. Es decir, una petición de "búsqueda(clave)" al contenedor de nodos hará que el mismo pase dicho mensaje a uno de los nodos (raíz, primero, etc; dependiendo de como se haya implementado la estructura de datos) devolviendo el nodo el resultado si su atributo clave coincide con la búsqueda o mandando dicho mensaje al siguiente nodo en caso contrario. Obviamente se daría este caso a niveles teóricos pues existen formas más óptimas de solventar el anterior problema de ejemplo y; sobre todo, ha de tenerse en cuenta que una cadena muy grande de muchos elementos puede llegar a apilar en memoria una gran cantidad de llamadas a procedimientos hasta que la cadena retorne un resultado con su consiguiente coste asociado.

Motivación

Supongamos un servicio de ayuda sensible al contexto para una interfaz gráfica. El usuario puede obtener ayuda en cualquier parte de la interfaz pulsando con el ratón sobre ella. La ayuda proporcionada depende de la parte de la interfaz que se haya seleccionado así como de su contexto. Si no existe información de ayuda específica para esa parte el sistema debería mostrar un mensaje de ayuda más general sobre el contexto inmediato. El problema es que el objeto que en última instancia proporciona la ayuda no conoce explícitamente al objeto (por ejemplo, el botón) que inicializa la petición. Necesitamos un modo de desacoplar el botón que da lugar a la petición de ayuda de los objetos que podrían proporcionar dicha información. El patrón Cadena de Responsabilidad define cómo hacerlo. La idea de este patrón es desacoplar a los emisores y a los receptores dándole a varios objetos la posibilidad de tratar una petición. La petición se pasa a través de una cadena de objetos hasta que es procesada por uno de ellos.

 

Supongamos que el usuario solicita ayuda sobre un botón denominado "Imprimir", el cual se encuentra en una instancia de DialogoDeImpresion. El siguiente diagrama muestra cómo la petición de ayuda se reenvía

 

En este caso, la petición no es procesada ni por unBotonDeImpresion ni por unDialogoDeImpresion; se detiene en unaAplicación que podrá procesarla u obviarla. El cliente que dio origen a la petición no tiene ninguna referencia directa al objeto que finalmente la satisface. Para reenviar la petición a lo largo de la cadena, y garantizar que los receptores permanecen implícitos, cada objeto de la cadena comparte una interfaz común para procesar peticiones y para acceder a su sucesor. Por ejemplo, en este sistema de ayuda podría definirse una clase ManejadorDeAyuda.

 

Las clases Botón, Diálogo y Aplicación usan las operaciones de ManejadorDeAyuda para tratar peticiones de ayuda. La operación ManejarAyuda de ManejadorDeAyuda reenvía la petición al sucesor de manera predeterminada. Las subclases pueden redefinir esta operación para proporcionar ayuda en determinadas circunstancias; en caso contrario, pueden usar la implementación predeterminada para reenviar la petición.

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

  • Manejador: define una interfaz para tratar las peticiones. Opcionalmente, implementa el enlace al sucesor.
  • ManejadorConcreto: trata las peticiones de las que es responsable; si el ManejadorConcreto puede manejar la petición, lo hace; en caso contrario la reenvía a su sucesor.
  • Cliente: inicializa la petición a un Manejador Concreto de la cadena.

Colaboraciones

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

Ventajas

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 esta. 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.

Implementación

  • Implementación de la cadena sucesora. Hay dos formas posibles de implementarla:
  1. Definir nuevos enlaces (normalmente en el Manejador, pero también podría ser en los objetos ManejadorConcreto).
  2. Usar enlaces existentes (otras asociaciones existentes). Por ejemplo, en el patrón Composición puede existir ya que un enlace al padre 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:
  1. Una petición es una invocación a una operación insertada en el código. Esto resulta conveniente y seguro, pero solo se pueden reenviar el conjunto prefijado de peticiones que define la clase Manejador.
  2. 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.

Patrones relacionados

Este patrón se aplica en ocasiones con el patrón Composición. En él, los padres de los componentes pueden actuar como sucesores.

Ejemplo

Diagrama de clases

 

Diagrama de clases comentado

 

Java

public class Cliente { public static void main(String argv[]) { Unidad smith = new Coronel("Smith", null); Unidad truman = new Coronel("Truman", "Tomar posición enemiga"); Unidad ryan = new Soldado("Ryan"); Unidad rambo = new Soldado("Rambo"); System.out.println(rambo.orden()); // rambo -> rambo.establecerMando(truman); System.out.println(rambo.orden()); // rambo -> truman ryan.establecerMando(rambo); System.out.println(ryan.orden()); // ryan -> rambo -> truman } } 
/**  * La clase Unidad representa la clase abstracta manejadora de la cadena de responsabilidad.  * El servicio delegado en la cadena es la solicitud de una orden al mando directo  */ public abstract class Unidad { /* en el constructor, además de un nombre para la unidad, se inicializa la referencia  que implementa la cadena de responsabilidad (_mando): en principio no hay sucesor */ public Unidad(String nombre) { _mando = null; _nombre = nombre; } public String toString() { return _nombre; } // cambia el mando de una unidad (modifica cadena de responsabilidad) public void establecerMando(Unidad mando) { _mando = mando; } /* comportamiento por defecto de la cadena: delegar en el mando directo o, si se   alcanza el final de la cadena, utilizar una resolución por defecto (sin orden) */ public String orden() { return (_mando != null ? _mando.orden() : "(sin orden)"); } private Unidad _mando; private String _nombre; } 
/**  * La clase Coronel modifica ligeramente el comportamiento por defecto de la cadena de  * responsabilidad: si el coronel tiene una orden específica, utiliza ésta para resolver  * el servicio. Si no tiene una orden específica (_orden==null), emplea el comportamiento  * convencional de las unidades  */ public class Coronel extends Unidad { // inicializa la parte de unidad e inicializa el estado propio del Coronel (_orden) public Coronel(String nombre, String orden) { super(nombre); _orden = orden; } /* refinamiento del servicio que utiliza la cadena de responsabilidad, resolviendo  localmente si tiene órdenes específicas o comportándose convencionalmente en  caso contrario */ public String orden() { return (_orden != null ? _orden : super.orden()); } public String toString() { return ("Coronel " + super.toString()); } private String _orden; } 
/**  * Esta clase es una extensión instanciable de la superclase Unidad que respeta el  * comportamiento por defecto de la cadena de responsabilidad  */  public class Soldado extends Unidad {  // el constructor sólo tiene que inicializar la parte correspondiente a la superclase  public Soldado(String nombre) {  super(nombre);  }  public String toString() { return ("Soldado " + super.toString()); } } 

Diagrama de secuencia

 
  •   Datos: Q231062
  •   Multimedia: Chain-of-responsibility pattern

Enlaces externos

  • Sencillo ejemplo de Chain of Responsibility por Juan Camba

cadena, responsabilidad, patrón, diseño, cadena, responsabilidad, patrón, comportamiento, evita, acoplar, emisor, petición, receptor, dando, más, objeto, posibilidad, responder, petición, para, ello, encadenan, receptores, pasa, petición, través, cadena, hasta. El patron de diseno o cadena de responsabilidad es un patron de comportamiento que evita acoplar el emisor de una peticion a su receptor dando a mas de un objeto la posibilidad de responder a una peticion Para ello se encadenan los receptores y pasa la peticion a traves de la cadena hasta que es procesada por algun objeto Este patron es utilizado a menudo en el contexto de las interfaces graficas de usuario donde un objeto puede estar compuesto de varios objetos que generalmente heredan de una super clase vista No se debe confundir con el patron Composite patron de diseno que se basa en un concepto similar Segun si el ambiente de ventanas genera eventos los objetos los manejan o los pasan transmiten hasta que algun elemento consume dicho evento y se detiene la propagacion Un claro ejemplo de cadena de responsabilidades seria una estructura de datos que contiene nodos cuya implementacion es opaca para el usuario de dicha estructura de datos no conoce salvo la interfaz de la estructura de datos Internamente los nodos se relacionan mediante punteros y una llamada a un metodo de la estructura de datos hara que un mensaje se propague por la cadena de nodos hasta llegar a su receptor Es decir una peticion de busqueda clave al contenedor de nodos hara que el mismo pase dicho mensaje a uno de los nodos raiz primero etc dependiendo de como se haya implementado la estructura de datos devolviendo el nodo el resultado si su atributo clave coincide con la busqueda o mandando dicho mensaje al siguiente nodo en caso contrario Obviamente se daria este caso a niveles teoricos pues existen formas mas optimas de solventar el anterior problema de ejemplo y sobre todo ha de tenerse en cuenta que una cadena muy grande de muchos elementos puede llegar a apilar en memoria una gran cantidad de llamadas a procedimientos hasta que la cadena retorne un resultado con su consiguiente coste asociado Indice 1 Motivacion 2 Aplicabilidad 3 Estructura 4 Participantes 5 Colaboraciones 6 Ventajas 7 Implementacion 8 Patrones relacionados 9 Ejemplo 9 1 Diagrama de clases 9 2 Diagrama de clases comentado 9 3 Java 9 4 Diagrama de secuencia 9 5 Enlaces externosMotivacion EditarSupongamos un servicio de ayuda sensible al contexto para una interfaz grafica El usuario puede obtener ayuda en cualquier parte de la interfaz pulsando con el raton sobre ella La ayuda proporcionada depende de la parte de la interfaz que se haya seleccionado asi como de su contexto Si no existe informacion de ayuda especifica para esa parte el sistema deberia mostrar un mensaje de ayuda mas general sobre el contexto inmediato El problema es que el objeto que en ultima instancia proporciona la ayuda no conoce explicitamente al objeto por ejemplo el boton que inicializa la peticion Necesitamos un modo de desacoplar el boton que da lugar a la peticion de ayuda de los objetos que podrian proporcionar dicha informacion El patron Cadena de Responsabilidad define como hacerlo La idea de este patron es desacoplar a los emisores y a los receptores dandole a varios objetos la posibilidad de tratar una peticion La peticion se pasa a traves de una cadena de objetos hasta que es procesada por uno de ellos Supongamos que el usuario solicita ayuda sobre un boton denominado Imprimir el cual se encuentra en una instancia de DialogoDeImpresion El siguiente diagrama muestra como la peticion de ayuda se reenvia En este caso la peticion no es procesada ni por unBotonDeImpresion ni por unDialogoDeImpresion se detiene en unaAplicacion que podra procesarla u obviarla El cliente que dio origen a la peticion no tiene ninguna referencia directa al objeto que finalmente la satisface Para reenviar la peticion a lo largo de la cadena y garantizar que los receptores permanecen implicitos cada objeto de la cadena comparte una interfaz comun para procesar peticiones y para acceder a su sucesor Por ejemplo en este sistema de ayuda podria definirse una clase ManejadorDeAyuda Las clases Boton Dialogo y Aplicacion usan las operaciones de ManejadorDeAyuda para tratar peticiones de ayuda La operacion ManejarAyuda de ManejadorDeAyuda reenvia la peticion al sucesor de manera predeterminada Las subclases pueden redefinir esta operacion para proporcionar ayuda en determinadas circunstancias en caso contrario pueden usar la implementacion predeterminada para reenviar la peticion Aplicabilidad EditarEl patron Cadena de Responsabilidad debe usarse cuando hay mas de un objeto que puede manejar una peticion y el manejador no se conoce a priori sino que deberia determinarse automaticamente se quiere enviar una peticion a un objeto entre varios sin especificar explicitamente el receptor el conjunto de objetos que pueden tratar una peticion deberia ser especificado dinamicamente Estructura Editar Participantes EditarManejador define una interfaz para tratar las peticiones Opcionalmente implementa el enlace al sucesor ManejadorConcreto trata las peticiones de las que es responsable si el ManejadorConcreto puede manejar la peticion lo hace en caso contrario la reenvia a su sucesor Cliente inicializa la peticion a un Manejador Concreto de la cadena Colaboraciones EditarCuando un cliente envia una peticion esta se propaga a traves de la cadena hasta que un objeto ManejadorConcreto se hace responsable de procesarla Ventajas EditarLas ventajas de este patron son Reduce el acoplamiento El patron libera a un objeto de tener que saber que otro objeto maneja una peticion Ni el receptor ni el emisor se conocen explicitamente entre ellos y un objeto de la cadena tampoco tiene que conocer la estructura de esta Por lo tanto simplifica las interconexiones entre objetos En vez de que los objetos mantengan referencias a todos los posibles receptores solo tienen una unica referencia a su sucesor Anade flexibilidad para asignar responsabilidades a objetos Se pueden anadir o cambiar responsabilidades entre objetos para tratar una peticion modificando la cadena de ejecucion en tiempo de ejecucion Esto se puede combinar con la herencia para especializar los manejadores estaticamente Por otra parte presenta el inconveniente de no garantizar la recepcion Dado que las peticiones no tienen un receptor explicito no hay garantias de que sean manejadas La peticion puede alcanzar el final de la cadena sin haber sido procesada Implementacion EditarImplementacion de la cadena sucesora Hay dos formas posibles de implementarla Definir nuevos enlaces normalmente en el Manejador pero tambien podria ser en los objetos ManejadorConcreto Usar enlaces existentes otras asociaciones existentes Por ejemplo en el patron Composicion puede existir ya que un enlace al padre puede utilizarse para definir la cadena de responsabilidad sin necesidad de anadir otra asociacion Conexion 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 ademas se encarga de mantener el sucesor Esto permite que el manejador proporcione una implementacion predeterminada de ManejarPeticion que reenvie la peticion al sucesor si hay alguno Si una subclase de ManejadorConcreto no esta interesada en dicha peticion no tiene que redefinir la operacion de reenvio Representacion de peticiones Hay varias opciones para representar las peticiones Una peticion es una invocacion a una operacion insertada en el codigo Esto resulta conveniente y seguro pero solo se pueden reenviar el conjunto prefijado de peticiones que define la clase Manejador Una unica funcion manejadora que reciba un codigo de peticion como parametro Esto permite un numero arbitrario de peticiones pero emisor y receptor deben ponerse de acuerdo sobre como codificarse la peticion Patrones relacionados EditarEste patron se aplica en ocasiones con el patron Composicion En el los padres de los componentes pueden actuar como sucesores Ejemplo EditarDiagrama de clases Editar Diagrama de clases comentado Editar Java Editar public class Cliente public static void main String argv Unidad smith new Coronel Smith null Unidad truman new Coronel Truman Tomar posicion enemiga Unidad ryan new Soldado Ryan Unidad rambo new Soldado Rambo System out println rambo orden rambo gt rambo establecerMando truman System out println rambo orden rambo gt truman ryan establecerMando rambo System out println ryan orden ryan gt rambo gt truman La clase Unidad representa la clase abstracta manejadora de la cadena de responsabilidad El servicio delegado en la cadena es la solicitud de una orden al mando directo public abstract class Unidad en el constructor ademas de un nombre para la unidad se inicializa la referencia que implementa la cadena de responsabilidad mando en principio no hay sucesor public Unidad String nombre mando null nombre nombre public String toString return nombre cambia el mando de una unidad modifica cadena de responsabilidad public void establecerMando Unidad mando mando mando comportamiento por defecto de la cadena delegar en el mando directo o si se alcanza el final de la cadena utilizar una resolucion por defecto sin orden public String orden return mando null mando orden sin orden private Unidad mando private String nombre La clase Coronel modifica ligeramente el comportamiento por defecto de la cadena de responsabilidad si el coronel tiene una orden especifica utiliza esta para resolver el servicio Si no tiene una orden especifica orden null emplea el comportamiento convencional de las unidades public class Coronel extends Unidad inicializa la parte de unidad e inicializa el estado propio del Coronel orden public Coronel String nombre String orden super nombre orden orden refinamiento del servicio que utiliza la cadena de responsabilidad resolviendo localmente si tiene ordenes especificas o comportandose convencionalmente en caso contrario public String orden return orden null orden super orden public String toString return Coronel super toString private String orden Esta clase es una extension instanciable de la superclase Unidad que respeta el comportamiento por defecto de la cadena de responsabilidad public class Soldado extends Unidad el constructor solo tiene que inicializar la parte correspondiente a la superclase public Soldado String nombre super nombre public String toString return Soldado super toString Diagrama de secuencia Editar Datos Q231062 Multimedia Chain of responsibility pattern Enlaces externos Editar Sencillo ejemplo de Chain of Responsibility por Juan Camba Obtenido de https es wikipedia org w index php title Cadena de responsabilidad amp oldid 131289590, wikipedia, wiki, leyendo, leer, libro, biblioteca,

español

, española, descargar, gratis, descargar gratis, mp3, video, mp4, 3gp, jpg, jpeg, gif, png, imagen, música, canción, película, libro, juego, juegos