1. 职责链模式(Chain of Responsibility Pattern)
在职责链模式中,多个处理器依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。
1.1. 模式架构
- 抽象处理者(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后继连接(链上的每个处理者都有一个成员变量来保存对于下一处理者的引用) 。
- 具体处理者(Concrete Handler):实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 请求者(Client):创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
1.2. 示例实现代码
Trouble类是表示发生问题的类,number是问题编号。通过getNumber来获取问题编号。
问题的大小从升序排序为:1 < 2 < 3 < 4
处理者处理问题的能力升序排序为:HandlerA < HandlerB < HandlerC < HandlerD
public class Trouble {
private String number;//问题编号
public Trouble(String number) {
this.number = number;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public String toString() {
return "Trouble{" +
"number='" + number + '\'' +
'}';
}
}
抽象处理者(Handler):
Handler
public abstract class Handler{
//处理器执行链路
protected Handler successor = null;
//设置下一个处理请求的处理者对象
public void setSuccessor(Handler successor){
this.successor = successor;
}
//处理的方法,具体处理者需根据不同需求进行实现
public abstract void handle(Trouble trouble);
}
具体处理者(Concrete Handler):
HandlerA
public class HandlerA extends Handler {
//具体处理者的实现方法
@Override
public void handle(Trouble trouble) {
System.out.print("HandlerA 执行代码逻辑! 处理: " +
trouble.getNumber());
trouble.setNumber(trouble.getNumber().replace("1", ""));
System.out.println(",处理完的结果为:" + trouble.getNumber());
if (successor != null) {
successor.handle(trouble);
}else {
System.out.println("执行终止");
}
}
}
HandlerB
public class HandlerB extends Handler {
//具体处理者的实现方法
@Override
public void handle(Trouble trouble) {
System.out.print("HandlerB 执行代码逻辑! 处理: " +
trouble.getNumber());
trouble.setNumber(trouble.getNumber().replace("2", ""));
System.out.println(",处理完的结果为:" + trouble.getNumber());
if (successor != null) {
successor.handle(trouble);
}else {
System.out.println("执行终止");
}
}
}
HandlerC
public class HandlerC extends Handler {
//具体处理者的实现方法
@Override
public void handle(Trouble trouble) {
System.out.print("HandlerC 执行代码逻辑! 处理: " +
trouble.getNumber());
trouble.setNumber(trouble.getNumber().replace("3", ""));
System.out.println(",处理完的结果为:" + trouble.getNumber());
if (successor != null) {
successor.handle(trouble);
}else {
System.out.println("执行终止");
}
}
}
HandlerD
public class HandlerD extends Handler {
//具体处理者的实现方法
@Override
public void handle(Trouble trouble) {
System.out.print("HandlerD 执行代码逻辑! 处理: " +
trouble.getNumber());
trouble.setNumber(trouble.getNumber());
System.out.println(",处理完的结果为:" + trouble.getNumber());
if (successor != null) {
successor.handle(trouble);
}else {
System.out.println("执行终止");
}
}
}
请求者(Client):
public class Client {
public static void main(String[] args) {
//包含1234的问题
Trouble trouble = new Trouble("1234");
//包含123的问题
Trouble trouble2 = new Trouble("123");
Handler h1 = new HandlerA();
Handler h2 = new HandlerB();
Handler h3 = new HandlerC();
//设置处理器执行链路
h1.setSuccessor(h2);
h2.setSuccessor(h3);
//执行
h1.handle(trouble);
}
}
执行结果:
HandlerA 执行代码逻辑! 处理: 1234,处理完的结果为:234
HandlerB 执行代码逻辑! 处理: 234,处理完的结果为:34
HandlerC 执行代码逻辑! 处理: 34,处理完的结果为:4
执行终止
在以上示例代码中,Handler抽象类定义了处理的抽象方法和后续的执行连接处理对象,而HandlerA~D是对应不同的具体处理类,每个类可以解决不同级别的问题,请求者可以设置执行链路,当一个含有不同等级的问题要处理时,会根据执行链路进行执行,若当前处理类无法处理该问题,则让下一个处理对象判断是否能处理,执行全部处理完毕。
1.3. 优缺点
优点:
- 降低耦合度:请求者不需要知道是哪个具体的处理者处理请求,降低了发送者和接收者之间的耦合度。
- 灵活性增强:可以动态地增加或修改处理请求的链条,更容易地根据需要改变处理流程。
- 简化对象:每个具体处理者只需关注自己责任范围内的处理逻辑,符合单一职责原则。
缺点:
- 请求不一定被处理:如果请求到达链条末端仍然没有处理者能够处理,可能会导致请求未被处理的情况。
- 性能问题:请求可能会经过多个处理者才能被处理,特别是在链条较长时,可能会影响性能。
- 调试复杂:链条中每个具体处理者的执行顺序不确定,难以调试。
在生活中比较常见的应用模式有:
1、在运行时需要动态使用多个关联对象来处理同一次请求时,比如各种流程执行:请假流程、员工入职流程。
2、需要动态更换处理对象时。比如,工单处理系统、网关 API 过滤规则系统等。
3、电商网站活动方式,一般分为满减送、限时折扣、包邮活动,拼团等可以采用策略模式
职责链模式常被用在框架开发中,用来实现框架的过滤器、拦截器功能,让框架的使用者在不修改源码的情况下,添加新的过滤拦截功能。