23种设计模式之责任链模式
参考资料
- Java设计模式:23种设计模式全面解析(超级详细)
- 韩顺平老师的Java设计模式(图解+框架源码剖析)
- 秦小波老师的《设计模式之禅》
下文如有错漏之处,敬请指正
一、简介
定义
把请求从链中的一个对象传递给下一个对象,直到请求被响应为止。通过这种方式将请求的发送者和请求的处理者实现解耦。
特点
- 责任链模式是一种(对象)行为型模式
通用类图
主要角色:
-
Handler
抽象处理者角色
定义一个处理请求的接口,包含抽象处理方法和一个后继处理者(即下一个处理者)。
-
ConcreteHandler
具体处理者角色
实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继处理者。
-
Client
客户类
创建并构建处理链的顺序,并向链头的具体处理者对象提交请求,不关心处理细节和请求的传递过程。
优点
- 降低了对象之间的耦合度。该模式使得一个对象无须知道是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
- 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
- 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
- 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
- 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
缺点
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
应用场景
- 有多个对象可以处理一个请求,哪个对象处理该请求由运行时自动确定。
- 可动态指定一组对象处理请求,或添加新的处理者。
- 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。
二、责任链模式
需求:
某所大学的学生想要请假,辅导员可以批准2天以内的请假,系主任可以批准5天以内、院长可以批准10天以内的,校长可以批准30天以内的,使用责任链模式实现该功能。
抽象处理者:
package chainOfResponsibility;
public abstract class Handler {
// 下一个处理者
private Handler nextHandler;
// 设获取下一个处理者
public Handler getNextHandler() {
return nextHandler;
}
// 设置下一个处理者
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
// 每一个处理者都必须实现处理任务
public abstract void handleRequest(int request);
// 交给下一个处理者执行
public final void handleNext(int request) {
// 判断是否有下一个处理者
if (this.getNextHandler() != null) {
// 有,交给下一个处理者
this.getNextHandler().handleRequest(request);
} else {
// 没有,则终止责任链的传递
System.out.println("你的请假天数太多,不予批准!");
}
}
}
具体处理者:
package chainOfResponsibility;
public class CounselorHandler extends Handler {
@Override
public void handleRequest(int request) {
// 判断当前处理者是否可以处理该请求
if (request <= 2) {
System.out.println("辅导员批准了你的" + request + "天请假!");
} else {
// 当前处理者不可以处理,传递给下一个处理者
super.handleNext(request);
}
}
}
package chainOfResponsibility;
public class DepartmentHeadHandler extends Handler {
@Override
public void handleRequest(int request) {
if (request <= 5) {
System.out.println("系主任批准了你的" + request + "天请假!");
} else {
super.handleNext(request);
}
}
}
package chainOfResponsibility;
public class DeanHandler extends Handler {
@Override
public void handleRequest(int request) {
if(request<=10){
System.out.println("院长批准了你的"+request+"天请假!");
}else {
super.handleNext(request);
}
}
}
package chainOfResponsibility;
public class PresidentHandler extends Handler {
@Override
public void handleRequest(int request) {
if (request <= 30) {
System.out.println("校长批准了你的" + request + "天请假!");
} else {
super.handleNext(request);
}
}
}
Client:
package chainOfResponsibility;
import javafx.scene.input.DataFormat;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Client {
public static void main(String[] args) {
// 声明所有的处理节点
Handler counselor = new CounselorHandler();
Handler departmentHead = new DepartmentHeadHandler();
Handler dean = new DeanHandler();
Handler president = new PresidentHandler();
// 设置责任链的顺序
counselor.setNextHandler(departmentHead);
departmentHead.setNextHandler(dean);
dean.setNextHandler(president);
// 模拟用户提交请假请求
counselor.handleRequest(1);
counselor.handleRequest(5);
counselor.handleRequest(8);
counselor.handleRequest(20);
counselor.handleRequest(50);
/**
* 输出结果:
* 辅导员批准了你的1天请假!
* 系主任批准了你的5天请假!
* 院长批准了你的8天请假!
* 校长批准了你的20天请假!
* 你的请假天数太多,不予批准!
*/
}
}
如果需要增加一个副校长可以批准学生20天以内的请假时,只需要增加一个Handler的子类,并修改责任链的关系,对原有代码结构没有影响,符合开闭原则。
三、总结
- 通过责任链模式,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程。
- 责任链模式可以结合模板方法模式,父类实现请求的传递的功能,子类实现请求的处理功能,符合单一职责原则和迪米特原则。