Java设计模式学习记录-责任链模式
前言
已经把五个创建型设计模式和七个结构型设计模式介绍完了,从这篇开始要介绍行为型设计模式了,第一个要介绍的行为型设计模式就是责任链模式(又称职责链模式)。
责任链模式
概念介绍
责任链模式是为了避免请求的发送者和接收者之间的耦合关系,使多个接收对象都有机会处理请求。将这些对象练成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。当然责任链中也有可能没有可以处理该请求的对象,这种情况是允许发生的。
举例
还是以前的规律,先举出具体的代码例子,然后再分析。拿前阵子在我老东家发生的一件事情来说,同事小王要结婚了,所以要请假回家筹备婚礼,但是公司有明确的规章制度,请假需要提前申请,并且每一级的领导能够审批的假期天数也不一样,部门经理可以审批1到2天的假期,技术总监能够审批3到5天的假期,大于5天的就要找CEO审批了,如果CEO审批通过了才可以休息5天以上的假期,小王筹备婚礼和渡蜜月总共要请10个工作日的假期。
用代码来实现这个过程就是下面👇这个样子的。
先创建请假条类
/** * 请假条 */ @Data @AllArgsConstructor public class Leave { /* 部门 */ private String department; /* 员工名称 */ private String name; /* 请假天数 */ private double days; /* 请假事由 */ private String cause; }
然后创建审批人的抽象类
/** * 审批人 */ public abstract class Approver { /* 审批人名称 */ String name; /* 下一个审批人 */ Approver nextApprover; public Approver(String name){ this.name = name; } /** * 设置下一个审批人 * @param approver */ public void setNextApprover(Approver approver){ this.nextApprover = approver; } /** * 审批 * @param leave */ public abstract void approval(Leave leave); }
部门经理
/** * 部门经理 */ public class Manager extends Approver { /** * 设置名称 * @param name 领导名称 */ public Manager(String name) { super(name); } /** * 审批 * @param leave 请假条 */ @Override public void approval(Leave leave) { if(leave.getDays()<3){ System.out.println("请假小于3天,算临时休息,批准了。"); System.out.println("部门经理审批通过---------审批流程over。"); }else{ if(Objects.nonNull(nextApprover)){ System.out.println("部门经理批准不了这么多天的假期,需要上级审批。"); this.nextApprover.approval(leave); }else{ System.out.println(name+"的领导不在,等着吧。"); } } } }
技术总监
/** * 技术总监 */ public class TechnicalDirector extends Approver { /** * 设置名称 * @param name 领导名称 */ public TechnicalDirector(String name) { super(name); } /** * 审批 * @param leave 请假条 */ @Override public void approval(Leave leave) { if(leave.getDays()<5){ System.out.println("请假小于5天,算有事休息,批准了。"); System.out.println("技术总监审批通过---------审批流程over。"); }else{ if(Objects.nonNull(nextApprover)){ System.out.println("技术总监批准不了这么多天的假期,需要上级审批。"); this.nextApprover.approval(leave); }else{ System.out.println(name+"的领导不在,等着吧。"); } } } }
CEO
/** * CEO */ public class CEO extends Approver { /** * 设置名称 * @param name 领导名称 */ public CEO(String name) { super(name); } /** * 审批 * @param leave 请假条 */ @Override public void approval(Leave leave) { if(leave.getDays()>5&&leave.getDays()<=10){ System.out.println("情况特殊,批准了。"); System.out.println("CEO审批通过---------审批流程over。"); }else{ System.out.println(name+"说请假的时间太长了不批,最好别一次性请这么久。"); } } }
测试类
public class Client { public static void main(String[] args) { //写请假条 Leave leave = new Leave("技术部","小王",6.0,"结婚"); //创建审批节点 Approver zhangge = new Manager("张哥"); Approver laozhao = new TechnicalDirector("老赵"); Approver lizong = new CEO("李总"); //将审批节点串起来 zhangge.setNextApprover(laozhao); laozhao.setNextApprover(lizong); //开始审批 zhangge.approval(leave); } }
运行结果
部门经理批准不了这么多天的假期,需要上级审批。
技术总监批准不了这么多天的假期,需要上级审批。
情况特殊,批准了。
CEO审批通过---------审批流程over。
通过运行结果,我们可以看出来,当请假天数为10天时,部门经理和技术总监都已经处理不了了,然后抛给了CEO,通过CEO特批小王的婚假请求才算了审批完成。这个例子就是用到了我们今天说的责任链模式,下面继续分析责任链模式。
责任链模式分析
责任链的结构图
主要涉及到的角色
抽象处理者(Handler)角色:抽象处理者用于定义出一个处理请求的接口,如果需要,接口可以定义出一个方法,以返回对下一个处理对象的引用。上面例子中的Approver就是代表的这个角色。
具体处理者(ConcreteHandler)角色:处理接到的请求,可以选择将请求处理掉,或者将请求传递给下家。上面的例子中的Manager和TechnicalDirector以及CEO就是代表的这个角色。
责任链模式总结
纯的责任链模式和不纯的责任链模式
- 纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一个是承担责任;二是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又把责任向下传的情况。在一个纯的责任链中,一个请求必须被某一个处理者对象所接受。
- 不纯的责任链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。例如JavaScript中的事件冒泡。
责任链模式的优点
1、请求不需要指出被哪个对象处理了,这样的效果是请求者和接收者之间的解耦,而且链中的对象也不需要清楚其他链的结构,也降低了耦合。
2、请求处理对象仅需要维护一个指向其后继者的的引用,而不需要维护所有的处理对象,简化了对象之间的相互连接。
3、在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。
4、新增一个请求处理对象,不需要改动现有代码,只需要重新设置连接即可,符合“开闭原则”。
责任链模式的缺点
1、如果一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理;一个请求也可能因职责链没有被正确配置而得不到处理。
2、 对于比较长的职责链,请求的处理可能涉及到多个处理对象,不仅增加了代码的复杂性并且系统性能也将受到一定影响,而且在进行代码调试时不太方便。
3、若建链不当,可能会造成循环调用,将导致系统陷入死循环。
适用场景
1、有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的。
2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3、可动态指定一组对象处理请求,客户端可以动态创建职责链来处理请求,还可以改变链中处理者之间的先后次序。
其实在我们日常开发中也会有适用到责任链模式的场景,try/catch、servlet(各个servelt互相调用)、以及filter等
想了解更多的设计模式请查看Java设计模式学习记录-GoF设计模式概述。
现在是不是行业不景气呢?怎么最近连面试机会都少了?
作者:纪莫
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。
欢迎扫描二维码关注公众号:Jimoer
文章会同步到公众号上面,大家一起成长,共同提升技术能力。
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。
您的鼓励是博主的最大动力!