本文参考:
https://www.cnblogs.com/aeolian/p/8888958.html
https://www.cnblogs.com/fengyumeng/p/10839570.html
定义
责任链模式(Chain of Responsibility Pattern)是一种常见的行为模式。
责任链模式英文原话是: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 object and pass the request along the chain until an object handles it.
翻译:使多个对象都有处理请求的机会,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象串成一条链,并沿着这条链一直传递该请求,直到有对象处理它为止。
责任链模式的重点在“链上”,由一条链去处理相似的请求,在链中决定谁来处理这个请求,并返回相应的结果。
角色:
抽象处理者(Handler)角色:该角色对请求进行抽象,并定义一个方法来设定和返回对下一个处理者的引用。
具体处理者(Concrete Handler):该角色接到请求后,可以选择将请求处理掉,或者将请求传给下一个处理者。由于具体处理者持有对下一个处理者的引用,因此,如果需要,处理者可以访问下一个处理者。
简单实例
如果在公司里,因为病假要请一个月的假需要经过组长、经理等好几轮的审核签字,这跟咱们的责任链模式非常相似,现以请假为例:
角色1:请假条,其实可以理解成请假人,因为请假条上自然有请假人信息。
角色2:领导人,小组长、部门经理、总经理都是审批人。
动作:领导人审批请假条。
流程如下:
请假条抽象:
public interface ILeave {
String getName();//请假人姓名
int getNum();//请假天数
String getContent();//请假条内容
}
请假条实现:
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;
}
public String getName() {
return name;
}
public int getNum() {
return num;
}
public String getContent() {
return content;
}
}
领导人抽象:
public interface IHandler {
void handleLeave(ILeave leave);//处理请假条
}
领导人实现:
public class GroupLeader implements IHandler {
@Override
public void handleLeave(ILeave leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("小组长审批:同意。");
}
}
public class Manager implements IHandler {
@Override
public void handleLeave(ILeave leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("部门经理审批:同意。");
}
}
public class BigManager implements IHandler {
@Override
public void handleLeave(ILeave leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("总经理审批:同意。");
}
}
客户端实现:
public static void main(String[] args) {
//请假条来一张
ILeave leave = new Leave("小花",5,"身体不适");
//小组长第一个审批
IHandler groupLeader = new GroupLeader();
groupLeader.handleLeave(leave);
if(leave.getNum() >= 3){
IHandler manager = new Manager();
manager.handleLeave(leave);
}
if(leave.getNum() >= 7){
IHandler bigManager = new BigManager();
bigManager.handleLeave(leave);
}
}
输出:
小花请假5天,身体不适。
小组长审批:同意。
小花请假5天,身体不适。
部门经理审批:同意。
这个程序是有问题,如果公司修改请假制度,一个月以上的请假需要老板审核签字,就得在客户端实现方法再写个if语句,这显然是有问题的。正确的逻辑应该是什么样的呢? 应该是小花递了请假条之后,就只需要等结果即可,而不是找了这个审批,回来后又跑去找那个审批。
优化:
请假条抽象:
public interface ILeave {
String getName();//请假人姓名
int getNum();//请假天数
String getContent();//请假条内容
}
请假条:
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;
}
public String getName() {
return name;
}
public int getNum() {
return num;
}
public String getContent() {
return content;
}
}
领导人抽象:
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);
}
领导人实例:
public class GroupLeader extends Handler {
public GroupLeader() {
//小组长处理1-3天的请假
super(Handler.NUM_ONE, Handler.NUM_THREE);
}
@Override
protected void handleLeave(ILeave leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("小组长审批:同意。");
}
}
public class Manager extends Handler {
public Manager() {
//部门经理处理3-7天的请假
super(Handler.NUM_THREE, Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(ILeave leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("部门经理审批:同意。");
}
}
public class BigManager extends Handler {
public BigManager() {
//部门经理处理7天以上的请假
super(Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(ILeave leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("总经理审批:同意。");
}
}
客户端:
public static void main(String[] args) {
//请假条来一张
ILeave leave = new Leave("小花",5,"身体不适");
//各位领导
Handler groupLeader = new GroupLeader();
Handler manager = new Manager();
Handler bigManager = new BigManager();
groupLeader.setNextHandler(manager);//小组长的领导是部门经理
manager.setNextHandler(bigManager);//部门经理的领导是总经理
//之所以在这里设置上级领导,是因为可以根据实际需求来更改设置,如果实战中上级领导人都是固定的,则可以移到领导实现类中。
//提交申请
groupLeader.submit(leave);
}
输出:
小花请假5天,身体不适。
小组长审批:同意。
小花请假5天,身体不适。
部门经理审批:同意。
优点
- 责任链模式将请求和处理分开,请求者不知道是谁处理的,处理者可以不用知道请求的全貌。
- 提高系统的灵活性。
缺点
- 降低程序的性能。每个请求都是从链头遍历到链尾,当链比较长的时候,性能会大幅下降。
- 不易于调试。由于该模式采用了类似递归的方式,调试的时候逻辑比较复杂。
应用场景
责任链模式是一种常见的模式,Struts2的核心控件FilterDispatcher是一个Servlet过滤器,该控件就是采用责任链模式,可以对用户请求进行层层过滤处理。责任链模式在实际项目中的使用比较多,其典型的应用场景如下:
- 一个请求需要一系列的处理工作。
- 业务流的处理,例如文件审批。
- 对系统进行扩展补充。