Files

202 lines
7.3 KiB
Markdown

---
title: Chain of responsibility
shortTitle: Chain of responsibility
category: Behavioral
language: es
tag:
- Gang of Four
- Decoupling
---
## También conocido como
* Chain of Command
* Chain of Objects
* Responsibility Chain
## Propósito
Evita acoplar el emisor de una petición a su receptor dando a más de un objeto la oportunidad de gestionar la petición. Encadena los objetos receptores y pasa la solicitud a lo largo de la cadena hasta que un objeto la gestione.
## Explicación
Ejemplo real
> El Rey Orco da órdenes en voz alta a su ejército. El más cercano a reaccionar es el comandante, luego un oficial y después un soldado. El comandante, el oficial y el soldado forman una cadena de responsabilidad.
En palabras sencillas
> Ayuda a construir una cadena de objetos. Una solicitud entra por un extremo y sigue pasando de un objeto a otro hasta que encuentra un gestor adecuado.
Wikipedia dice
> En diseño orientado a objetos, el patrón de cadena de responsabilidad es un patrón de diseño que consiste en una fuente de objetos de comando y una serie de objetos de procesamiento. Cada objeto de procesamiento contiene lógica que define los tipos de objetos de comando que puede manejar; el resto se pasa al siguiente objeto de procesamiento de la cadena.
**Ejemplo programático**
Traduciendo nuestro ejemplo con los orcos de arriba. Primero, tenemos la clase `Request`:
```java
import lombok.Getter;
@Getter
public class Request {
private final RequestType requestType;
private final String requestDescription;
private boolean handled;
public Request(final RequestType requestType, final String requestDescription) {
this.requestType = Objects.requireNonNull(requestType);
this.requestDescription = Objects.requireNonNull(requestDescription);
}
public void markHandled() {
this.handled = true;
}
@Override
public String toString() {
return getRequestDescription();
}
}
public enum RequestType {
DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX
}
```
A continuación, mostramos la jerarquía del gestor de peticiones.
```java
public interface RequestHandler {
boolean canHandleRequest(Request req);
int getPriority();
void handle(Request req);
String name();
}
@Slf4j
public class OrcCommander implements RequestHandler {
@Override
public boolean canHandleRequest(Request req) {
return req.getRequestType() == RequestType.DEFEND_CASTLE;
}
@Override
public int getPriority() {
return 2;
}
@Override
public void handle(Request req) {
req.markHandled();
LOGGER.info("{} handling request \"{}\"", name(), req);
}
@Override
public String name() {
return "Orc commander";
}
}
// OrcOfficer and OrcSoldier are defined similarly as OrcCommander
```
El Rey Orco da las órdenes y forma la cadena.
```java
public class OrcKing {
private List<RequestHandler> handlers;
public OrcKing() {
buildChain();
}
private void buildChain() {
handlers = Arrays.asList(new OrcCommander(), new OrcOfficer(), new OrcSoldier());
}
public void makeRequest(Request req) {
handlers
.stream()
.sorted(Comparator.comparing(RequestHandler::getPriority))
.filter(handler -> handler.canHandleRequest(req))
.findFirst()
.ifPresent(handler -> handler.handle(req));
}
}
```
La cadena de responsabilidad en acción.
```java
var king=new OrcKing();
king.makeRequest(new Request(RequestType.DEFEND_CASTLE,"defend castle"));
king.makeRequest(new Request(RequestType.TORTURE_PRISONER,"torture prisoner"));
king.makeRequest(new Request(RequestType.COLLECT_TAX,"collect tax"));
```
La salida de la consola.
```
Orc commander handling request "defend castle"
Orc officer handling request "torture prisoner"
Orc soldier handling request "collect tax"
```
## Diagrama de clases
![alt text](./etc/chain-of-responsibility.urm.png "Diagrama de clases de la cadena de responsabilidad")
## Aplicabilidad
Utilice Cadena de Responsabilidad cuando
* Más de un objeto puede gestionar una petición, y el gestor no se conoce a priori. El gestor debe determinarse automáticamente.
* Se desea enviar una petición a uno de varios objetos sin especificar explícitamente el receptor.
* El conjunto de objetos que pueden gestionar una solicitud debe especificarse dinámicamente.
## Usos conocidos
* Burbujeo de eventos en frameworks GUI donde un evento puede ser manejado en múltiples niveles de la jerarquía de un componente UI.
* Frameworks de middleware en los que una petición pasa a través de una cadena de objetos de procesamiento.
* Marcos de trabajo de registro donde los mensajes pueden pasar a través de una serie de registradores, cada uno posiblemente manejándolos de manera diferente.
* [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29)
* [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html)
* [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-)
## Consecuencias
Ventajas:
* Acoplamiento reducido. El emisor de una petición no necesita conocer el manejador concreto que procesará la petición.
* Mayor flexibilidad a la hora de asignar responsabilidades a los objetos. Se pueden añadir o cambiar responsabilidades para gestionar una petición cambiando los miembros y el orden de la cadena.
* Permite establecer un gestor por defecto si no hay ningún gestor concreto que pueda gestionar la solicitud.
Desventajas:
* Puede ser difícil depurar y entender el flujo, especialmente si la cadena es larga y compleja.
* La petición puede quedar sin gestionar si la cadena no incluye un gestor "catch-all".
* Pueden surgir problemas de rendimiento debido a la posibilidad de pasar por varios gestores antes de encontrar el correcto, o no encontrarlo en absoluto.
## Patrones Relacionados
* [Comando](https://java-design-patterns.com/patterns/command/): puede ser usado para encapsular una petición como un objeto, que puede ser pasado a lo largo de la cadena.
* [Composite](https://java-design-patterns.com/patterns/composite/): la Cadena de Responsabilidad se aplica a menudo junto con el patrón Composite.
* [Decorator](https://java-design-patterns.com/patterns/decorator/): los decoradores pueden encadenarse de forma similar a las responsabilidades en el patrón Cadena de responsabilidad.
## Créditos
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
* [Pattern-Oriented Software Architecture, Volume 1: A System of Patterns](https://amzn.to/3PAJUg5)
* [Refactoring to Patterns](https://amzn.to/3VOO4F5)
* [Pattern languages of program design 3](https://amzn.to/4a4NxTH)