参考资料1:http://c.biancheng.net/design_pattern/
参考资料2:https://refactoringguru.cn/design-patterns/catalog
1. 介绍
1.1 简介
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链
。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
1.2 优缺
- 意图
避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
- 主要解决
责任链上的处理者负责处理请求,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递,所以责任链将请求的发送者和请求的处理者解耦了。
- 何时使用
在处理消息的时候以过滤很多道。
- 如何解决
拦截的类都实现统一接口。
- 关键代码
Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
- 应用实例
- 红楼梦中的”击鼓传花”。
- JS 中的事件冒泡。
- JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。
- 优点
- 降低耦合度。它将请求的发送者和接收者解耦。
- 简化了对象。使得对象不需要知道链的结构。
- 增强给对象指派责任的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
- 增加新的请求处理类很方便。
- 缺点
- 不能保证请求一定被接收。
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
- 可能不容易观察运行时的特征,有碍于除错。
- 使用场景
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可动态指定一组对象处理请求。
1.3 模式结构
责任链模式主要包含以下角色:
抽象处理者(Handler)
角色-核心
:定义一个处理请求的抽象类或接口,包含抽象处理方法和一个后继连接。
具体处理者(Concrete Handler)
角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
客户类(Client)
角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
结构图:
责任链图:
2. 实现
以请假的审批流程为例。
我是小赵,我就是其中的小组长之一,我有七个手下。
今天,手下小明来找我请假
,说他家里出了点状况,需要请一个月的假。
我只是小组长
,我完字 → 就叫他去找部门经理
,部门经理签字 → 又让他去找总经理
,总经理最终签字。
这个假才算请完。
后来才知道:
- 3天以下的假小组长1个人签字即可
- 3-7天的假需要小组长、部门经理2个人签字
- 7以上的假小组长、部门经理签完字后,还需要总经理总共3个人签字
企业中非常常见。
角色1:请假条,其实可以理解成请假人,因为请假条上自然有请假人信息。
角色2:领导人,小组长、部门经理、总经理都是审批人。
动作:领导人审批请假条。
请假条接口:
1 2 3 4 5 6 7 8 9 10 11
|
public interface ILeave { String getName(); int getNum(); String getContent(); }
|
请假条:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import com.demo.designmode.chain.ILeave;
public class Leave implements ILeave { private String name; private int num; private String content;
public Leave(String name, int num, String content) { this.name = name; this.num = num; this.content = content; }
@Override public String getName() { return name; }
@Override public int getNum() { return num; }
@Override public String getContent() { return content; } }
|
处理者抽象类
——责任链模式的核心:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
public abstract class Handler { protected final static int NUM_ONE = 1; protected final static int NUM_THREE = 3; protected final static int NUM_SEVEN = 7; private int numStart = 0; private int numEnd = 0; private Handler nextHandler;
public Handler(int numStart) { this.numStart = numStart; }
public Handler(int numStart, int numEnd) { this.numStart = numStart; this.numEnd = numEnd; }
public void setNextHandler(Handler nextHandler) { this.nextHandler = nextHandler; }
public final void submit(ILeave leave) { if (0 == this.numStart) { return; }
if (leave.getNum() >= this.numStart) { this.handleLeave(leave);
if (null != this.nextHandler && leave.getNum() > numEnd) { this.nextHandler.submit(leave); } } }
protected abstract void handleLeave(ILeave leave); }
|
小组长:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import com.demo.designmode.chain.Handler; import com.demo.designmode.chain.ILeave;
public class GroupLeader extends Handler { public GroupLeader() { super(Handler.NUM_ONE, Handler.NUM_THREE); }
@Override public void handleLeave(ILeave leave) { System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。"); System.out.println("小组长审批:同意。"); } }
|
部门经理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import com.demo.designmode.chain.Handler; import com.demo.designmode.chain.ILeave;
public class Manager extends Handler { public Manager() { super(Handler.NUM_THREE, Handler.NUM_SEVEN); }
@Override public void handleLeave(ILeave leave) { System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。"); System.out.println("部门经理审批:同意。"); } }
|
总经理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import com.demo.designmode.chain.Handler; import com.demo.designmode.chain.ILeave;
public class BigManager extends Handler { public BigManager() { super(Handler.NUM_SEVEN); }
@Override public void handleLeave(ILeave leave) { System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。"); System.out.println("总经理审批:同意。"); } }
|
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import com.demo.designmode.chain.impl.BigManager; import com.demo.designmode.chain.impl.GroupLeader; import com.demo.designmode.chain.impl.Leave; import com.demo.designmode.chain.impl.Manager;
public class StartClass { public static void main(String[] args) { ILeave leave = new Leave("小明", 8, "身体不适");
Handler groupLeader = new GroupLeader(); Handler manager = new Manager(); Handler bigManager = new BigManager();
groupLeader.setNextHandler(manager); manager.setNextHandler(bigManager);
groupLeader.submit(leave); } }
|
3. 应用场景
- 有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定。
- 可动态指定一组对象处理请求,或添加新的处理者。
- 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
4. 模式扩展
- 纯的职责链模式:一个请求必须被某一个处理者对象所接收,且一个具体处理者对某个请求的处理只能采用以下两种行为之一:自己处理(承担责任);把责任推给下家处理。
- 不纯的责任链模式:允许出现某一个具体处理者对象在承担了请求的一部分责任后又将剩余的责任传给下家的情况,且一个请求可以最终不被任何接收端对象所接收。