1. 责任链模式
计算机软件是用来处理信息的,有多种不同的方式来组织和处理信息。当我们讨论面向对象编程时,应该赋予一个类单一的职责,从而使得类容易维护和扩展。设想一个场景,需要对一批从客户端来的数据进行多种不同的操作,我们会使用多个不同的类负责不同的操作,而不是使用一个类集成所有的操作,这样做能够让代码松耦合且简洁。这些类被称为处理器,第一个处理器会接收请求,如果它需要执行操作则会进行一次数据处理,如果不需要则会将请求传递给第二个处理器,依次类推直至走完整个链,这就是责任链模式。
责任链模式优点:
- 降低了对象之间的耦合度。
- 增强了系统的可扩展性,根据需要可以增加处理器,满足开闭原则。
- 增强了指派职责的灵活性,当工作流发生变化时,可以动态改变链内的处理器的次序,或者动态新增、删除职责。
- 责任分担,每个类只需要处理自己该处理的工作,不需要处理的请求传递给下一个处理器,符合单一职责原则。
责任链模式缺点:
- 不能保证每个请求一定被处理,因为一个请求并没有明确的处理者,该请求可能一直到链的末端都得不到处理。
- 对于较长的责任链,请求处理可能涉及多个处理对象,系统性能将受到一定影响。
- 一定要避免出现死循环情况。
责任链模式结构如下:
- 客户端(Client):客户端是使用责任链模式的应用程序的主要结构,它的职责是实例化一个处理器链,然后在责任链的头部处理器处发起请求。
- 抽象处理器(Handler):处理器的抽象基类或接口,提供给具体处理器继承或实现。
- 具体处理器(Handler1、Handler2):实现了处理器接口的具体处理器,内部维持一个引用,指向链中的下一个处理器。
2. 责任链案例
在学校的请假需求中,规定学生请假小于2天,班主任可以予以审批,请假天数超过2天小于7天班主任需要交给系主任进行审批,但请假天数超过7天是需要交由校长进行审批,通过程序实现如下:
新建抽象处理者类,这里使用接口和抽象类,接口名为Handler,定义处理器行为,内容如下:
public interface Handler {
/**
* 设置下一个处理者
* @param handler 处理者
*/
void setNextHandler(Handler handler);
/**
* 获取下一个处理者
* @return 处理者
*/
Handler getNextHandler();
/**
* 处理请假请求
* @param holiday 请假天数
*/
void handleRequset(Integer holiday);
}
由于每个处理器都会设置下一级处理器,在抽象类中实现设置下一级处理器公共方法,类名为AbstractHandler,内容如下:
public abstract class AbstractHandler implements Handler {
/**
* 下一个处理者
*/
protected Handler nextHandler;
@Override
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
@Override
public Handler getNextHandler() {
return this.nextHandler;
}
}
新建班主任处理者类继承抽象处理者类,实现请求处理方法,类名称为ChargeThacherHandler,内容如下:
public class ChargeThacherHandler extends AbstractHandler {
@Override
public void handleRequset(Integer holiday) {
if (holiday <= 2){
System.out.println(String.format("班主任:请假%d天,审批通过", holiday));
} else {
System.out.println("班主任:请假天数超出我的审批范围,交由下级审批");
getNextHandler().handleRequset(holiday);
}
}
}
新建系主任处理者类继承抽象处理者类,实现请求处理方法,类名称为DeanHandler,内容如下:
public class DeanHandler extends AbstractHandler{
@Override
public void handleRequset(Integer holiday) {
if (holiday <= 7){
System.out.println(String.format("系主任:请假%d天,审批通过", holiday));
} else {
System.out.println("系主任:请假天数超出我的审批范围,交由下级审批");
getNextHandler().handleRequset(holiday);
}
}
}
新建王校长处理者类继承抽象处理者类,实现请求处理方法,类名称为HeadMasterHandler,内容如下:
public class HeadMasterHandler extends AbstractHandler {
@Override
public void handleRequset(Integer holiday) {
if (holiday <= 10){
System.out.println(String.format("王校长:请假%d天,审批通过", holiday));
} else {
System.out.println("王校长:请假天数太长,不予以批准。");
}
}
}
新建客户端类进行责任链的设置并发起请假请求,类名称为Client,内容如下:
public class Client {
public static void main(String[] args) {
// 组装责任链
Handler chargeThacherHandler = new ChargeThacherHandler();
Handler deanHandler = new DeanHandler();
Handler headMasterHandler = new HeadMasterHandler();
// 班主任的下一级是系主任
chargeThacherHandler.setNextHandler(deanHandler);
// 系主任的下一级是王校长
deanHandler.setNextHandler(headMasterHandler);
// 提出请假请求
// 请求休假1天
chargeThacherHandler.handleRequset(1);
System.out.println("-------------------------------------------");
// 请求休假5天
chargeThacherHandler.handleRequset(5);
System.out.println("-------------------------------------------");
// 请求休假8天
chargeThacherHandler.handleRequset(8);
System.out.println("-------------------------------------------");
// 请求休假20天
chargeThacherHandler.handleRequset(20);
}
}
不同的请假请求依次传递给合适的角色审批,各个角色职责单一。
3. 责任链应用
- 事件处理器:JS的点击事件通过冒泡的方式依次传递。
- 过滤器链和拦截器链:Java的Servlet规范中的过滤器链和Spring MVC以及Struts中的拦截器链。