Chain of Responsibility (padrón de deseño)
Este artigo precisa de máis fontes ou referencias que aparezan nunha publicación acreditada que poidan verificar o seu contido, como libros ou outras publicacións especializadas no tema. Por favor, axude mellorando este artigo. (Desde novembro de 2016.) |
Este artigo ou sección precisa dunha revisión do formato que siga o libro de estilo da Galipedia. Pode axudar a mellorar este artigo e outros en condicións semellantes. |
Este artigo ou sección precisa dunha revisión ortográfica e/ou de gramática (recurso útil: corrector ortográfico en liña de galego). Podes axudarte do revisor ortográfico, activándoo en: Preferencias → Trebellos → Navegación → Ortografía: Activar o revisor ortográfico. Colabora connosco neste artigo e noutros en condicións semellantes para que a Galipedia mellore e medre. |
Cadea de Responsabilidade (en inglés "Chain of Responsability") é un padrón de deseño [1]que permite xestionar unha petición a máis dun obxecto mediante o encadeamento de receptores, que se pasan a petición ó longo da cadea ata que un dos obxectos manipula dita petición.
Un padrón de cadea de responsabilidade é a miúdo utilizado no contexto de interfaces gráficas de usuario onde un obxecto pode conter varios outros obxectos. Segundo o ambiente de ventás xera eventos, os obxectos ou os manexan ou los pasan.
Motivación
[editar | editar a fonte]- Supoñamos un servizo de axuda sensible ó contexto para unha interface gráfica de usuario. O usuario pode obter información de axuda en calquera parte da mesma simplemente pulsando co rato sobre ela. A axuda proporcionada depende da parte da interface que se selecciona así como do seu contexto. Se non existe información de axuda específica para esa parte da interface o sistema de axuda debería mostrar un mensaxe de axuda más xeral sobre o contexto inmediato.
- Se o obxecto "actual" seleccionado da cadea ten información específica debe presentala e manexar a petición; en caso contrario, debe enviar a petición (mensaxe) ó seu sucesor na cadea de responsabilidade.
- O problema é que o obxecto que en última instancia proporciona a axuda non coñece explicitamente o obxecto que inicia a petición de axuda. Necesitamos un modo de desacoplar o botón que da lugar á petición de axuda dos obxectos que poderían proporcionar dita información. O padrón Cadea de Responsabilidade define como facer isto: a idea é desacoplar ós emisores e ós receptores dándolle a varios obxectos a posibilidade de tratar unha petición. Esta petición pasará a través da cadea de obxectos ata que sexa procesada por un deles.
Se un usuario solicita axuda sobre un botón denominado "Imprimir". O botón encóntrase nunha instancia de DialogoDeImpresion. O seguinte diagrama de interacción mostra como a petición de axuda se reenvía a través da cadea.
Nese caso a petición non é procesada nin por unBotonDeImpresion nin por unDialogoDeImpresion; detense en unhaAplicacion, quen pode procesala ou ignorala. O cliente que deu orixe á petición non ten ningunha referencia directa ó obxecto que finalmente a satisfai.
Para reenviar a petición ó longo da cadea e para garantir que os receptores permanecen implícitos, cada obxecto da cadea comparte unha interface común para procesar peticións e para acceder ó seu sucesor na cadea. Por exemplo, neste sistema de axuda podería definirse unha clase ManexadorDeAxuda.
Aplicabilidade
[editar | editar a fonte]- Cando hai máis dun obxecto que pode manexar unha petición, pero non se sabe a priori cal deles o ten que facer.
- Se non se desexa identificar explicitamente quen é o receptor da petición.
- Cando os obxectos que poden manexar a petición varían dinamicamente.
Estrutura
[editar | editar a fonte]Participantes
[editar | editar a fonte]- Manexador : A interface que define o método usado para pasar unha mensaxe ó seguinte handler. A mensaxe é normalmente unha chamada a un método. Ademais, frecuentemente define tamén o enlace ó sucesor na cadea.
- Manexador concreto : Unha clase que implementa a interface Handler e mantén unha referencia ó seguinteHandler. Esta referencia pode ser asignada no construtor da clase ou a través dun método setter. A implementación do método de manexo de mensaxes pode chamar a un método para manexar as peticións das que é responsable ou, en caso contrario, se non pode xestionar unha delas delega a petición no seu sucesor.
- Cliente : Envía unha petición a algún Manexador Concreto da cadea.
Colaboracións
[editar | editar a fonte]- Cando un cliente inicia unha petición, esta propágase a través da cadea ata que un Manexador Concreto asume a responsabilidade de xestionala.
Consecuencias
[editar | editar a fonte]- Reduce o acoplamento de obxectos: tanto o manexador como o cliente non coñecen a estrutura da cadea en si. Ademais, coñécese unicamente como chegar ó primeiro elo da cadea, pero non se sabe a implementacion que hai de por medio.
- Flexibilidade engadida á hora de engadir responsabilidades a obxectos: por exemplo, no caso de ter un departamento de recepción de documentos que está moi ocupado atendendo a varios clientes á vez, pódese facer que a secretaría reciba algúns dos documentos e que o porteiro faga o mesmo.
- A Cadea de Responsabilidades ofrece unha gran flexibilidade no procesamento de eventos para unha aplicación, xa que domina o manexo de eventos complexos dividindo as responsabilidades a través dun número de elementos simples, permitindo a un grupo de clases comportarse como un todo.
- A recepción da petición non está garantida: ó non haber un receptor explícito para as mensaxes, non se garante que esta chegue nin tampouco se garante que cando chegue se procese de maneira adecuada (inconveniente).
Implementación
[editar | editar a fonte]Cadea de sucesores:
- Definir novos enlaces (normalmente no Manexador, pero tamén podería ser nos obxector ManexadorConcreto).
- Usar enlaces existentes (outras asociacións existentes). Por exemplo, no padrón Composición pode existir xa un enlace ó pai que pode utilizarse para definir a cadea de responsabilidade sen necesidade de engadir outra asociación.
- Conexión de sucesores. Se non hai referencias preexistentes para definir unha cadea, entón teremos que introducilas nosoutros mesmos. Neste caso, o Manexador define a interface e ademais encárgase de manter o sucesor. Isto permite que o Manexador proporcione unha implementación predeterminada de ManexarPetición que reenvíe a petición ó sucesor (se hai algún). Se unha subclase de ManexadorConcreto non está interesada en dita petición, non ten que redefinir a operación de reenvío.
Representación das peticións
- un método por cada petición. Isto resulta adecuado e seguro, pero só se pode reenviar o conxunto prefixado de peticións que define a clase Manexador.
- único método parametrizado para distinguir distintas peticións. Isto permite un número arbitrario de peticións pero emisor e receptor deben poñerse de acordo sobre como codificar a petición.
padróns relacionados
[editar | editar a fonte]Este padrón pódese aplicar conxuntamente co padrón Composite. Neste, os pais dos compoñentes poden actuar como sucesores.
Exemplo de implementación
[editar | editar a fonte]public class Cliente {
public static void main(String argv[]) {
Unidade smith = new Coronel("Smith", null);
Unidade truman = new Coronel("Truman", "Tomar posición inimiga");
Unidade ryan = new Soldado("Ryan");
Unidade rambo = new Soldado("Rambo");
System.out.println(rambo.orde()); // rambo ->
rambo.establecerMando(truman);
System.out.println(rambo.orde()); // rambo -> truman
ryan.establecerMando(rambo);
System.out.println(ryan.orde()); // ryan -> rambo -> truman
}
}
/**
* A clase Unidade representa a clase abstracta manexadora da cadea de responsabilidade.
* O servizo delegado na cadea é a solicitude dunha orde ó mando directo
*/
public abstract class Unidade {
/* No construtor, ademais dun nome para a unidade, iníciase a referencia que implementa a cadea de responsabilidade (_mando): en principio no hai sucesor */
public Unidade(String nome) {
_mando = null;
_nome = nome;
}
public String toString() { return _nome; }
// cambia o mando dunha unidade (modifica cadea de responsabilidade)
public void establecerMando(Unidade mando) { _mando = mando; }
/* comportamento por defecto da cadea: delegar no mando directo ou, se se alcanza o final da cadea, utilizar unha resolución por defecto (sen orde) */
public String orde() {
return (_mando != null ? _mando.orde() : "(sen orde)");
}
private Unidade _mando;
private String _nome;
}
/**
* A clase Coronel modifica lixeiramente o comportamento por defecto da cadea de
* responsabilidade: se o coronel ten unha orde específica, utiliza esta para resolver
* o servizo. Se non ten unha orde específica (_orde==null), emprega o comportamento
* convencional das unidades
*/
public class Coronel extends Unidade {
// inicia a parte de unidade e inicia o estado propio do Coronel (_orde)
public Coronel(String nome, String orde) {
super(nome);
_orde = orde;
}
/* refinamento do servizo que emprega a cadea de responsabilidade, resolvendo
localmente se ten ordes específicas ou comportándose convencionalmente en
caso contrario */
public String orde() { return (_orde != null ? _orde : super.orde()); }
public String toString() { return ("Coronel " + super.toString()); }
private String _orde;
}
/**
* Esta clase é unha extensión instanciable da superclase Unidade que respecta o
* comportamento por defecto da cadea de responsabilidade
*/
public class Soldado extends Unidade {
// o construtor só ten que iniciar a parte correspondente á superclase
public Soldado(String nome) {
super(nome);
}
public String toString() { return ("Soldado " + super.toString()); }
}
- ↑ "Libro moderno sobre patrones de diseño: Sumérgete en los patrones de diseño". refactoring.guru (en castelán). Consultado o 2023-08-04.