Chain of Responsibility
意图
十多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止
动机
来看一个某公司请假的流程,按照请假天数,如果不大于1天,可有mentor审批,大于1天不大于2天,由leader审批,大于2天不大于5天,有项目经理审批,若大于5天需有CTO审批,要是按照平时,我们会怎么写呢
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:06
*/
public class personalLeave {
public void sendRequestToSomeone(Integer days) {
if (days <= 1) {
this.handleByMentor(days);
} else if (days <= 2) {
this.handleByLeader(days);
} else if (days <= 5) {
this.handleByManager(days);
} else {
this.handleByCTO(days);
}
}
public void handleByMentor(Integer days) {
//代码省略
}
public void handleByLeader(Integer days) {
//代码省略
}
public void handleByManager(Integer days) {
//代码省略
}
public void handleByCTO(Integer days) {
//代码省略
}
}
这样的代码我们发现很多问题:
1、personalLeave类较为庞大,各个处理方法集中在一起,测试维护难度大
2、如果要加一个日期限制,比如说3-4天,或者换一个人对某一个档次进行审批,都需要修改源代码并严格测试,违反开闭原则
3、审批流程设置也缺乏灵活性,全有if、else组合实现,太复杂且易读性太差,每次修改都要修改大量源代码
那么职责链模式就是为了解决这一类问题而生的。
适用性
1、有多个对象那个可以处理一个请求,哪个对象处理该请求运行时自动确定
2、在不明确指定接受者的情况下,向多个对象中的一个提交一个请求
3、可处理一个请求的对象集合应该被动态指定
结构
Handler
定义一个处理请求的接口,一般为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象,作为其对下家的引用。通过该引用,处理者可以连成一条链。
实现后继链
Concretehandler
处理它所负责的请求,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;
可访问他的后继者
如果可处理该请求,就处理,否则将请求转发给他的后继者
Client
向链上的具体处理者对象提交请求
实现
还是请假系统,我们看使用责任链模式怎么写
请假请求
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:44
*/
public class LeaveRequest {
private double days;
private String reason;
public LeaveRequest(double days, String reason) {
this.days = days;
this.reason = reason;
}
public double getDays() {
return days;
}
public void setDays(double days) {
this.days = days;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}
抽象处理器
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:45
* 抽象的处理者
*/
public abstract class Handler {
protected Handler successor;
protected String name;
public Handler(String name) {
this.name = name;
}
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void processRequest(LeaveRequest leaveRequest);
}
具体的处理者
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:47
*/
public class MentorHandler extends Handler {
public MentorHandler(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest leaveRequest) {
if (leaveRequest.getDays() <= 1) {
System.out.println("导师" + this.name + "审批" + leaveRequest.getDays() + "天,原因是" + leaveRequest.getReason());
} else {
this.successor.processRequest(leaveRequest);
}
}
}
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:47
*/
public class LeaderHandler extends Handler {
public LeaderHandler(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest leaveRequest) {
if (leaveRequest.getDays() <= 2) {
System.out.println("直属领导" + this.name + "审批" + leaveRequest.getDays() + "天,原因是" + leaveRequest.getReason());
} else {
this.successor.processRequest(leaveRequest);
}
}
}
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:47
*/
public class ManagerHandler extends Handler {
public ManagerHandler(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest leaveRequest) {
if (leaveRequest.getDays() <= 5) {
System.out.println("项目经理" + this.name + "审批" + leaveRequest.getDays() + "天,原因是" + leaveRequest.getReason());
} else {
this.successor.processRequest(leaveRequest);
}
}
}
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:47
*/
public class CTOHandler extends Handler {
public CTOHandler(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest leaveRequest) {
System.out.println("CTO" + this.name + "审批" + leaveRequest.getDays() + "天,原因是" + leaveRequest.getReason());
}
}
客户端测试
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:54
*/
public class Client {
public static void main(String[] args) {
// 设置具体职位的处理人
Handler xfZhang, xqLu, yBi, yxZhou;
xfZhang = new MentorHandler("张小凡");
xqLu = new LeaderHandler("陆雪琪");
yBi = new ManagerHandler("碧瑶");
yxZhou = new CTOHandler("周一仙");
//设置每一个人的下一条链
xfZhang.setSuccessor(xqLu);
xqLu.setSuccessor(yBi);
yBi.setSuccessor(yxZhou);
//创建请假条
LeaveRequest lr1 = new LeaveRequest(1, "十万大山");
xfZhang.processRequest(lr1);
LeaveRequest lr2 = new LeaveRequest(2, "南疆");
xfZhang.processRequest(lr2);
LeaveRequest lr3 = new LeaveRequest(3, "青云山上");
xfZhang.processRequest(lr3);
LeaveRequest lr4 = new LeaveRequest(6, "游山玩水");
xfZhang.processRequest(lr4);
}
}
/**导师张小凡审批1.0天,原因是十万大山
直属领导陆雪琪审批2.0天,原因是南疆
项目经理碧瑶审批3.0天,原因是青云山上
CTO周一仙审批6.0天,原因是游山玩水
*/
可见很灵活,我们在客户端就可以设置每一条职责链,而不用每次去修改源代码,比如如果要加一个处理者,处理3天到5天之间的BigLeader类,可以这样很简单的实现
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:47
* 添加一个具体的处理类
*/
public class BigLeaderHandler extends Handler {
public BigLeaderHandler(String name) {
super(name);
}
@Override
public void processRequest(LeaveRequest leaveRequest) {
if (leaveRequest.getDays() <= 4) {
System.out.println("大直系领导" + this.name + "审批" + leaveRequest.getDays() + "天,原因是" + leaveRequest.getReason());
} else {
this.successor.processRequest(leaveRequest);
}
}
}
package chain;
/**
* @Author fitz.bai
* @Date 2018/9/4 11:54
*/
public class Client {
public static void main(String[] args) {
Handler xfZhang, xqLu, gKing, yBi, yxZhou;
xfZhang = new MentorHandler("张小凡");
xqLu = new LeaderHandler("陆雪琪");
// 添加处理类
gKing = new BigLeaderHandler("鬼王");
yBi = new ManagerHandler("碧瑶");
yxZhou = new CTOHandler("周一仙");
xfZhang.setSuccessor(xqLu);
// 设置责任链顺序
xqLu.setSuccessor(gKing);
gKing.setSuccessor(yBi);
yBi.setSuccessor(yxZhou);
LeaveRequest lr1 = new LeaveRequest(1, "十万大山");
xfZhang.processRequest(lr1);
LeaveRequest lr2 = new LeaveRequest(2, "南疆");
xfZhang.processRequest(lr2);
LeaveRequest lr3 = new LeaveRequest(3, "青云山上");
xfZhang.processRequest(lr3);
LeaveRequest lr4 = new LeaveRequest(6, "游山玩水");
xfZhang.processRequest(lr4);
LeaveRequest lr5 = new LeaveRequest(5, "游山玩水");
xfZhang.processRequest(lr5);
}
}
/**导师张小凡审批1.0天,原因是十万大山
直属领导陆雪琪审批2.0天,原因是南疆
大直系领导鬼王审批3.0天,原因是青云山上
CTO周一仙审批6.0天,原因是游山玩水
项目经理碧瑶审批5.0天,原因是游山玩水
*/
总结
优点
1、降低了系统的耦合度,一个对象无须知道是哪一个对象处理它,由客户端负责链的创建。
2、请求处理对象仅需维持一个指向其后继者的引用,不需要维持它对所有的候选处理者的引用,可简化对象的相互连接。
3、职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。
4、在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可。
缺点
1、不能保证一个请求一定会被处理,该请求可能一直到链的末端都找不到处理者处理;也可能因职责链没有被正确配置而得不到处理。
2、对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。
3、如果建链不当,可能会造成循环调用,将导致系统陷入死循环。