Loading... # 设计模式(二十一)——职责链模式 ## 参考 > 大话设计模式  ——  程杰 著 ## 目录 [设计模式(一)——简单工厂模式](https://www.princelei.club/archives/67.html) [设计模式(二)——策略模式](https://www.princelei.club/archives/68.html) [设计模式(三)——设计原则](https://www.princelei.club/archives/116.html) [设计模式(四)——装饰模式](https://www.princelei.club/archives/117.html) [设计模式(五)——代理模式](https://www.princelei.club/archives/119.html) [设计模式(六)——工厂方法模式](https://www.princelei.club/archives/132.html) [设计模式(七)——原型模式](https://www.princelei.club/archives/133.html) [设计模式(八)——模板方法模式](https://www.princelei.club/archives/134.html) [设计模式(九)——外观模式](https://www.princelei.club/archives/135.html) [设计模式(十)——建造者模式](https://www.princelei.club/archives/136.html) [设计模式(十一)——观察者模式](https://www.princelei.club/archives/137.html) [设计模式(十二)——抽象工厂模式](https://www.princelei.club/archives/138.html) [设计模式(十三)——状态模式](https://www.princelei.club/archives/139.html) [设计模式(十四)——适配器模式](https://www.princelei.club/archives/140.html) [设计模式(十五)——备忘录模式](https://www.princelei.club/archives/141.html) [设计模式(十六)——组合模式](https://www.princelei.club/archives/147.html) [设计模式(十七)——迭代器模式](https://www.princelei.club/archives/148.html) [设计模式(十八)——单例模式](https://www.princelei.club/archives/157.html) [设计模式(十九)——桥接模式](https://www.princelei.club/archives/159.html) [设计模式(二十)——命令模式](https://www.princelei.club/archives/160.html) [设计模式(二十一)——职责链模式](https://www.princelei.club/archives/161.html) [设计模式(二十二)——中介者模式](https://www.princelei.club/archives/162.html) [设计模式(二十三)——享元模式](https://www.princelei.club/archives/163.html) [设计模式(二十四)——解释器模式](https://www.princelei.club/archives/173.html) [设计模式(二十五)——访问者模式](https://www.princelei.club/archives/174.html) ## 何为职责链模式 - 职责链模式(Chain of Responsibility):使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 ## 示例 员工请假、加薪领导审批 ``` /** * 申请 */ public class Request { //申请类别 private String requestType; //申请内容 private String requestContent; //数量 private int num; public String getRequestType() { return requestType; } public void setRequestType(String requestType) { this.requestType = requestType; } public String getRequestContent() { return requestContent; } public void setRequestContent(String requestContent) { this.requestContent = requestContent; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } } ``` ``` /** * 管理者 */ public abstract class Manager { protected String name; //管理者上级 protected Manager superior; public Manager(String name){ this.name = name; } //设置管理者的上级 public void setSuperior(Manager superior) { this.superior = superior; } //申请请求 public abstract void requestApplication(Request request); } ``` ``` /** * 经理 */ public class CommonManager extends Manager { public CommonManager(String name) { super(name); } @Override public void requestApplication(Request request) { if (request.getRequestType().equals("请假") && request.getNum() <= 2) { System.out.println(name + ":" + request.getRequestContent() + " 数量" + request.getNum() + " 被批准"); } else { if (superior != null) { superior.requestApplication(request); } } } } ``` ``` /** * 总监 */ public class Majordomo extends Manager { public Majordomo(String name) { super(name); } @Override public void requestApplication(Request request) { if (request.getRequestType().equals("请假") && request.getNum() <= 5) { System.out.println(name + ":" + request.getRequestContent() + " 数量" + request.getNum() + " 被批准"); } else { if (superior != null) { superior.requestApplication(request); } } } } ``` ``` /** * 总经理(全部都要处理) */ public class GeneralManager extends Manager{ public GeneralManager(String name) { super(name); } @Override public void requestApplication(Request request) { if(request.getRequestType().equals("请假")){ //总经理可准许下属任意天的假期 System.out.println(name + ":" + request.getRequestContent() + " 数量" + request.getNum() + " 被批准"); }else if(request.getRequestType().equals("加薪")&&request.getNum()<=500){ //加薪在500以内,没有问题 System.out.println(name + ":" + request.getRequestContent() + " 数量" + request.getNum() + " 被批准"); }else if(request.getRequestType().equals("加薪")&&request.getNum()>500){ //超过500,就要考虑一下了 System.out.println(name + ":" + request.getRequestContent() + " 数量" + request.getNum() + " 再说吧"); } } } ``` ``` /** * 客户端 */ public class MainClass { public static void main(String[] args) { Manager jingli = new CommonManager("经理"); Manager zongjian = new Majordomo("总监"); Manager zongjingli = new GeneralManager("总经理"); //设置上级,完全可以根据实际需求来更改,经理也可以直接越级上报总经理 jingli.setSuperior(zongjian); zongjian.setSuperior(zongjingli); Request request = new Request(); request.setRequestType("请假"); request.setRequestContent("小菜请假"); request.setNum(1); jingli.requestApplication(request); //客户端的申请都是由“经理”发起,但实际谁来决策由具体管理类来处理,客户端不知道 Request request2 = new Request(); request2.setRequestType("请假"); request2.setRequestContent("小菜请假"); request2.setNum(4); jingli.requestApplication(request2); Request request3 = new Request(); request3.setRequestType("加薪"); request3.setRequestContent("小菜请求加薪"); request3.setNum(500); jingli.requestApplication(request3); Request request4 = new Request(); request4.setRequestType("加薪"); request4.setRequestContent("小菜请求加薪"); request4.setNum(1000); jingli.requestApplication(request4); } } ``` 输出: ``` 经理:小菜请假 数量1 被批准 总监:小菜请假 数量4 被批准 总经理:小菜请求加薪 数量500 被批准 总经理:小菜请求加薪 数量1000 再说吧 ``` ## 职责链的好处 当客户提交一个请求时,请求是沿链传递直至有一个ConcreteHandler对象负责处理它。这就使得接受者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,他们仅需保持一个指向其后继者的引用,而不需保持它所有的候选者的引用。由于是在客户端定义链的结构,可以随时地增加或修改处理一个请求的结构。增强了给对象指派职责的灵活性。不过也要当心,一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理,这就很糟糕了,需要事先考虑全面。 ## 与状态模式的区别 - 状态模式是让各个状态对象自己知道其下一个处理的对象是谁,即在编译时便设定。相当于If ,else-if,else-if……, 设计思路是把逻辑判断转移到各个State类的内部实现(相当于If,else If),执行时客户端通过调用环境—Context类的方法来间接执行状态类的行为,客户端不直接和状态交互。 - 职责链模式中的各个对象并不指定其下一个处理的对象到底是谁,只有在客户端才设定某个类型的链条,请求发出后穿越链条,直到被某个职责类处理或者链条结束。本质相当于swich-case,设计思路是把各个业务逻辑判断封装到不同职责类,且携带下一个职责的对应引用,但不像状态模式那样需要明确知道这个引用指向谁,而是在环境类设置链接方式或者过程。使用时,向链的第一个子类的执行方法传递参数就可以。客户端去通过环境类调用责任链,全自动运转起来。 既然他们都可以解决逻辑判断的分支过多的问题,那么,是不是责任链模式比状态模式好呢?   职责链模式过于灵活,在客户端使用时,需要环境去确定下一个对象是谁,一系列的set操作……在多次设置的时候很容易出问题,而且状态模式是一个对象的内在状态发生改变(一个对象,相对比较稳定,处理完一个对象下一个对象的处理一般都已确定),而职责链模式是多个对象之间的改变(多个对象之间的话,就会出现某个对象不存在的情景,就像之前讲状态模式时的公司请假系统,可能存在不同级别,不同类型员工请假流程不一样,此时用状态模式不太好),这也说明他们两个模式处理的情况不同。 Last modification:June 11th, 2020 at 06:21 pm © 允许规范转载