mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 04:17:17 +00:00
181 lines
6.3 KiB
Markdown
181 lines
6.3 KiB
Markdown
# 责任链模式
|
||
|
||
> 经常变化的产品需求该怎么设计?一个人关于需求变更问题的解决方案
|
||
|
||
|
||
|
||
## 定义
|
||
责任链模式的英文翻译是 Chain Of Responsibility Design Pattern。在 GoF 的《设计模式》中,它是这么定义的:
|
||
> Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
|
||
|
||
翻译成中文就是:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止
|
||
|
||
在职责链模式中,多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。
|
||
|
||
有些抽象,可以类比下 Node 的洋葱模型,是不是形象多了
|
||
|
||
|
||
## 实现
|
||
|
||
### 方法1
|
||
Handler 是所有处理器类的抽象父类,handle() 是抽象方法。每个具体的处理器类(HandlerA、HandlerB)的 handle() 函数的代码结构类似,如果它能处理该请求,就不继续往下传递;如果不能处理,则交由后面的处理器来处理(也就是调用 successor.handle())。
|
||
HandlerChain 是处理器链,从数据结构的角度来看,它就是一个记录了链头、链尾的链表。其中,记录链尾是为了方便添加处理器。
|
||
|
||
```
|
||
public abstract class Handler {
|
||
protected Handler successor = null;
|
||
public void setSuccessor(Handler successor) {
|
||
this.successor = successor;
|
||
}
|
||
public abstract void handle();
|
||
}
|
||
public class HandlerA extends Handler {
|
||
@Override
|
||
public boolean handle() {
|
||
boolean handled = false;
|
||
//...
|
||
if (!handled && successor != null) {
|
||
successor.handle();
|
||
}
|
||
}
|
||
}
|
||
|
||
public class HandlerB extends Handler {
|
||
@Override
|
||
public void handle() {
|
||
boolean handled = false;
|
||
//...
|
||
if (!handled && successor != null) {
|
||
successor.handle();
|
||
}
|
||
}
|
||
}
|
||
public class HandlerChain {
|
||
private Handler head = null;
|
||
private Handler tail = null;
|
||
public void addHandler(Handler handler) {
|
||
handler.setSuccessor(null);
|
||
if (head == null) {
|
||
head = handler;
|
||
tail = handler;
|
||
return;
|
||
}
|
||
tail.setSuccessor(handler);
|
||
tail = handler;
|
||
}
|
||
public void handle() {
|
||
if (head != null) {
|
||
head.handle();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 使用举例
|
||
public class Application {
|
||
public static void main(String[] args) {
|
||
HandlerChain chain = new HandlerChain();
|
||
chain.addHandler(new HandlerA());
|
||
chain.addHandler(new HandlerB());
|
||
chain.handle();
|
||
}
|
||
}
|
||
```
|
||
|
||
问题分析:上面的代码实现不够优雅。处理器类的 handle() 函数,不仅包含自己的业务逻辑,还包含对下一个处理器的调用,也就是代码中的 successor.handle()。一个不熟悉这种代码结构的程序员,在添加新的处理器类的时候,很有可能忘记在 handle() 函数中调用 successor.handle(),这就会导致代码出现 bug
|
||
|
||
我们对代码进行重构,**利用模板模式,将调用 successor.handle() 的逻辑从具体的处理器类中剥离出来,放到抽象父类中**。这样具体的处理器类只需要实现自己的业务逻辑就可以了。重构之后的代码如下所示
|
||
|
||
```
|
||
public abstract class Handler {
|
||
protected Handler successor = null;
|
||
public void setSuccessor(Handler successor) {
|
||
this.successor = successor;
|
||
}
|
||
public final void handle() {
|
||
boolean handled = doHandle();
|
||
if (successor != null && !handled) {
|
||
successor.handle();
|
||
}
|
||
}
|
||
protected abstract boolean doHandle();
|
||
}
|
||
public class HandlerA extends Handler {
|
||
@Override
|
||
protected boolean doHandle() {
|
||
boolean handled = false;
|
||
//...
|
||
return handled;
|
||
}
|
||
}
|
||
|
||
public class HandlerB extends Handler {
|
||
@Override
|
||
protected boolean doHandle() {
|
||
boolean handled = false;
|
||
//...
|
||
return handled;
|
||
}
|
||
}
|
||
// HandlerChain和Application代码不变
|
||
```
|
||
### 方法2
|
||
我们再来看第二种实现方式,代码如下所示。这种实现方式更加简单。HandlerChain 类用数组而非链表来保存所有的处理器,并且需要在 HandlerChain 的 handle() 函数中,依次调用每个处理器的 handle() 函数。
|
||
|
||
```
|
||
public interface IHandler {
|
||
boolean handle();
|
||
}
|
||
public class HandlerA implements IHandler {
|
||
@Override
|
||
public boolean handle() {
|
||
boolean handled = false;
|
||
//...
|
||
return handled;
|
||
}
|
||
}
|
||
public class HandlerB implements IHandler {
|
||
@Override
|
||
public boolean handle() {
|
||
boolean handled = false;
|
||
//...
|
||
return handled;
|
||
}
|
||
}
|
||
public class HandlerChain {
|
||
private List<IHandler> handlers = new ArrayList<>();
|
||
public void addHandler(IHandler handler) {
|
||
this.handlers.add(handler);
|
||
}
|
||
public void handle() {
|
||
for (IHandler handler : handlers) {
|
||
|
||
boolean handled = handler.handle();
|
||
if (handled) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 使用举例
|
||
public class Application {
|
||
public static void main(String[] args) {
|
||
HandlerChain chain = new HandlerChain();
|
||
chain.addHandler(new HandlerA());
|
||
chain.addHandler(new HandlerB());
|
||
chain.handle();
|
||
}
|
||
}
|
||
```
|
||
在 GoF 给出的定义中,如果处理器链上的某个处理器能够处理这个请求,那就不会继续往下传递请求。实际上,职责链模式还有一种变体,那就是请求会被所有的处理器都处理一遍,不存在中途终止的情况。
|
||
|
||
|
||
|
||
## 使用场景
|
||
|
||
在之前的文章利用[责任链模式设计了一套校验器](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/Chapter1%20-%20iOS/1.110.md)
|
||
|
||
- Node 的洋葱模型
|
||
- Redux 中间件思想都是责任链的使用场景
|
||
- iOS 事件传递机制、响应链
|