Chain of Responsibility
定义
将链中每一个节点都看作一个对象,每个节点处理的请求均不同,且内部自动维护下一个节点对象。当一个请求从链式的首端发出时,会沿着责任链预设的路径依次传递到每一个节点对象,直至被链中的某个对象处理为止
应用场景
1.程序需要使用不同方式处理不同种类请求,而且请求类型和顺序预先未知
该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。
2.必须按顺序执行多个处理者
无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。
3.所需处理者及其顺序必须在运行时进行改变
如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。
实现方式
1.声明处理者接口并描述请求处理方法的签名。
确定客户端如何将请求数据传递给方法。 最灵活的方式是将 请求转换为对象, 然后将其以参数的形式传递给处理函数。
2.为了在具体处理者中消除重复的样本代码, 你可以根据处理 者接口创建抽象处理者基类。
该类需要有一个成员变量来存储指向链上下个处理者的引用。 你可以将其设置为不可变类。 但如果你打算在运行时对链进 行改变, 则需要定义一个设定方法来修改引用成员变量的值。
为了使用方便, 你还可以实现处理方法的默认行为。 如果还 有剩余对象, 该方法会将请求传递给下个对象。 具体处理者 还能够通过调用父对象的方法来使用这一行为。
3.依次创建具体处理者子类并实现其处理方法。 每个处理者在 接收到请求后都必须做出两个决定:
◦ 是否自行处理这个请求。
◦ 是否将该请求沿着链进行传递。
4.客户端可以自行组装链,或者从其他对象处获得预先组装好的链。 在后一种情况下,你必须实现工厂类以根据配置或环境设置来创建链。
5.客户端可以触发链中的任意处理者, 而不仅仅是第一个。 请 求将通过链进行传递, 直至某个处理者拒绝继续传递, 或者 请求到达链尾。
6.由于链的动态性, 客户端需要准备好处理以下情况:
◦ 链中可能只有单个链接。
◦ 部分请求可能无法到达链尾。
◦ 其他请求可能直到链尾都未被处理。
优缺点
优点:
1.你可以控制请求处理的顺序。
2.单一职责原则。 你可对发起操作和执行操作的类进行解耦。
3.开闭原则。可以在不更改现有代码的情况下在程序中新增处理者
缺点:
1.部分请求可能未被处理
结构
UML图
classDiagram
Client-->Handler
BaseHandler..|>Handler
BaseHandler o--|>Handler
ConcreteHandlers --|>BaseHandler
class Handler{
<<interface>>
+setNext(h:Handler)
+handle(request)
}
class BaseHandler{
-next:Handler
+setNext(h:Handler)
+handle(request)
}
class ConcreteHandlers{
...
+handle(request)
}
参与者
1.处理者(Handler)声明了所有具体处理者的通用接口。该接 口通常仅包含单个方法用于请求处理, 但有时其还会包含一 个设置链上下个处理者的方法。
2.基础处理者(Base Handler)是一个可选的类,你可以将所 有处理者共用的样本代码放置在其中。
通常情况下, 该类中定义了一个保存对于下个处理者引用的 成员变量。 客户端可通过将处理者传递给上个处理者的构造 函数或设定方法来创建链。 该类还可以实现默认的处理行为: 确定下个处理者存在后再将请求传递给它。
3.具体处理者(Concrete Handlers)包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及 是否沿着链传递请求。
处理者通常是独立且不可变的, 需要通过构造函数一次性地 获得所有必要地数据。
4.客户端(Client)可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非 必须是第一个处理者。
通用写法
public abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(String request);
}
public class ConcreteHandlerA extends Handler{
@Override
public void handleRequest(String request) {
if ("requestA".equals(request)){
System.out.println(this.getClass().getSimpleName()+"deal with request:"+request);
return;
}
if (this.nextHandler != null){
this.nextHandler.handleRequest(request);
}
}
}
public class ConcreteHandlerB extends Handler{
@Override
public void handleRequest(String request) {
if ("requestB".equals(request)){
System.out.println(this.getClass().getSimpleName()+"deal with request:"+request);
return;
}
if (this.nextHandler != null){
this.nextHandler.handleRequest(request);
}
}
}
public class Client {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setNextHandler(handlerB);
handlerA.handleRequest("requestB");
}
}