设计模式之职责链模式
职责链模式--导读
现如今程序员的工作越来越苦逼,前段时间的“996”工作模式备受诟病,连很多大佬也受到牵连。就现如今的工作模式请假也是必然,各个公司也都有他们的假批模式。比如说3天以内由部门负责人进行审批,3天到5天由行政部门审批,假期小于10天由总经理审批,如果超过10天则不予审批,这是我们可能会跟据逻辑得到如下代码:
public void define() { int dayOff=3; if(dayOff<3) { System.out.println("部门经理审批"); }else if(dayOff<5) { System.out.println("行政部门审批"); }else if(dayOff<10){ System.out.println("总经理审批"); }else{
System.out.println("不予审批");
}
}
这段代码虽然可以解决这个问题,但是一旦这个处理过程很复杂时,这个选择结构势必会很长,而且还必须修改源码,这不符合开闭原则,如果逻辑非常复杂的话还有可能产生牵一发而动全身的问题所以这段程序的可用价值不高。但是我们对这样的模式又有需求,我们应该如何解决呢?
职责链模式--定义
因为处理流程中可能会随需求的变化而进行改变,那么我们为什么不动态的设置整个处理流程呢,当需要在两处理流程之间新加一个处理流程只需要新建这个处理过程,然后动态的加进去即可,这样就使得系统的灵活性更高,于是我们引入职责链模式;
避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。这便是职责链模式。职责链模式是一种对象行为型模式。
在职责链模式中最关键的一点就是客户提交请求后,请求沿着链往下传递直到有一个处理者处理它,在这里客户无需关心它的请求是哪个处理者来处理,反正总有一个处理者会处理它的请求。
在这里客户端和处理者都没有对方明确的信息,同时处理者也不知道职责链中的结构。所以职责链可以简化对象的相互连接,他们只需要保存一个指向其后续者的引用,而不需要保存所有候选者的引用。
在职责链模式中我们可以随时随地的增加或者更改一个处理者,甚至可以更改处理者的顺序,增加了系统的灵活性。处理灵活性是增加了,但是有时候可能会导致一个请求无论如何也得不到处理,它会被放置在链末端,这个既是职责链的优点也是缺点。
职责链模式--结构
以下是UML结构图:
● Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象(如结构图中的successor),作为其对下家的引用。通过该引用,处理者可以连成一条链。
● ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。
在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
职责链模式--代码实现
Manager.java一个抽象的管理者的类,定义所有管理者所有需要操作的方法,并且还要定义一个抽象对象用于保存下一层处理对象的引用,具体代码如下:package Response_Chain; /** * 管理者的抽象类 * @author xyxy001 * */ public abstract class Manager { //管理者的职务 protected String name; //下层处理者 protected Manager sucessor; public Manager(String name){ this.name=name; } //设置下一层传递者 public void setSuccessor(Manager manager){ this.sucessor=manager; } //具体处理事务的方法 public abstract void processRequest(LeaveNote note); }
ChairMan.java董事长,处理请假关系的最后一层关系:
package Response_Chain; /** * 董事长 * @author xyxy001 * */ public class ChairMan extends Manager{ public ChairMan(String name) { super(name); } @Override public void processRequest(LeaveNote note) { System.out.println(note.getName()+"你小子不想干了是吧,就想以"+note.getReason()+"这破理由请假"+note.getDays()+"天"); System.out.println("滚回"+note.getLoc()+"部接着工作去"); } }
DepartmentManager.java部门经理:
package Response_Chain; public class DepartmentManager extends Manager { public DepartmentManager(String name) { super(name); } public void processRequest(LeaveNote note) { if(note.getDays()<3) { System.out.println(note.getLoc()+"的"+note.getName()+"的"+note.getReason()+"合情合理"); System.out.println("部门经理"+this.name+"准你请假"+note.getDays()+"天"); }else{ this.sucessor.processRequest(note); } } }
ExecutiveDepartment.java行政部门:
package Response_Chain; public class ExecutiveDepartment extends Manager{ public ExecutiveDepartment(String name) { super(name); // TODO Auto-generated constructor stub } @Override public void processRequest(LeaveNote note) { if(note.getDays()<5) { System.out.println(note.getLoc()+"的"+note.getName()+"的"+note.getReason()+"合情合理"); System.out.println("行政部门管理"+this.name+"准你请假"+note.getDays()+"天"); }else{ this.sucessor.processRequest(note); } } }
GeneralManager.java总经理
package Response_Chain; /** * 模拟总经理对请假的处理 * @author xyxy001 * */ public class GeneralManager extends Manager{ public GeneralManager(String name) { super(name); } @Override public void processRequest(LeaveNote note) { if(note.getDays()<10) { System.out.println(note.getLoc()+"的"+note.getName()+"的"+note.getReason()+"合情合理"); System.out.println("总经理"+this.name+"准你请假"+note.getDays()+"天"); }else{ this.sucessor.processRequest(note); } } }
LeaveNote.java请假条类:
package Response_Chain; /** * 具体的请加条 * @author xyxy001 * */ public class LeaveNote { //请假者的名字 private String name; //请假人的单位 private String loc; //请假的天数 private int days; private String reason; public LeaveNote(String name,String loc,int day,String reason){ this.days=day; this.loc=loc; this.reason=reason; this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLoc() { return loc; } public void setLoc(String loc) { this.loc = loc; } public int getDays() { return days; } public void setDays(int days) { this.days = days; } public String getReason() { return reason; } public void setReason(String reason) { this.reason = reason; } }
client.java模拟用户请假:
package Response_Chain; public class client { public static void main(String[] args) { //创建管理者 DepartmentManager dm=new DepartmentManager("混元霹雳手成昆"); ExecutiveDepartment ed=new ExecutiveDepartment("杨左使杨逍"); GeneralManager gm=new GeneralManager("金毛狮王谢逊"); ChairMan cm=new ChairMan("明教教主张无忌"); //公司动态设置职责链 dm.setSuccessor(ed); ed.setSuccessor(gm); gm.setSuccessor(cm); //现如今由销售人员,周芷若请假6天,回家看望母亲,所以创建请假条 LeaveNote note=new LeaveNote("周芷若","销售部门",7,"回家探望母亲"); //现在将将请假条交给自己的上级 dm.processRequest(note); } }
如果我们在需要新加额外处理情况,比如说我要在总经理和董事长之间新加一个总裁他用来处理8天以内的假期,我们只需要新加一个节点如下:
package Response_Chain; public class President extends Manager{ public President(String name) { super(name); } @Override public void processRequest(LeaveNote note) { if(note.getDays()<10) { System.out.println(note.getLoc()+"的"+note.getName()+"的"+note.getReason()+"合情合理"); System.out.println("总裁"+this.name+"准你请假"+note.getDays()+"天"); }else{ this.sucessor.processRequest(note); } } }
只需要重新设置职责链即可
package Response_Chain; public class client { public static void main(String[] args) { //创建管理者 DepartmentManager dm=new DepartmentManager("混元霹雳手成昆"); ExecutiveDepartment ed=new ExecutiveDepartment("杨左使杨逍"); GeneralManager gm=new GeneralManager("金毛狮王谢逊"); ChairMan cm=new ChairMan("明教教主张无忌"); President pd=new President("老婆张敏"); //重新添加设置职责链 dm.setSuccessor(ed); ed.setSuccessor(gm); gm.setSuccessor(pd); pd.setSuccessor(cm); //现如今由销售人员,周芷若请假6天,回家看望母亲,所以创建请假条 LeaveNote note=new LeaveNote("周芷若","销售部门",9,"回家探望母亲"); //现在将将请假条交给自己的上级 dm.processRequest(note); } }
职责链模式--拓展
职责链模式可分为纯的职责链模式和不纯的职责链模式两种:
(1) 纯的职责链模式
一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况。而且在纯的职责链模式中,要求一个请求必须被某一个处理者对象所接收,不能出现某个请求未被任何一个处理者对象处理的情况。在前面的采购单审批实例中应用的是纯的职责链模式。
(2)不纯的职责链模式
在一个不纯的职责链模式中允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。不纯的责任链最具有代表性的例子就是商场中的打折,超过指定部分的重量就打折,没超过的部分按原价进行处理。
职责链模式--优缺点
1.优点
职责链模式的主要优点如下:
(1) 职责链模式使得一个对象无须知道是其他哪一个对象处理其请求,对象仅需知道该请求会被处理即可,接收者和发送者都没有对方的明确信息,且链中的对象不需要知道链的结构,由客户端负责链的创建,降低了系统的耦合度。
(2) 请求处理对象仅需维持一个指向其后继者的引用,而不需要维持它对所有的候选处理者的引用,可简化对象的相互连接。
(3) 在给对象分派职责时,职责链可以给我们更多的灵活性,可以通过在运行时对该链进行动态的增加或修改来增加或改变处理一个请求的职责。
(4) 在系统中增加一个新的具体请求处理者时无须修改原有系统的代码,只需要在客户端重新建链即可,从这一点来看是符合“开闭原则”的。
2.缺点
职责链模式的主要缺点如下:
(1) 由于一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理;一个请求也可能因职责链没有被正确配置而得不到处理。
(2) 对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。
(3) 如果建链不当,可能会造成循环调用,将导致系统陷入死循环。
职责链模式--使用场景
在以下情况下可以考虑使用职责链模式:
(1) 有多个对象可以处理同一个请求,具体哪个对象处理该请求待运行时刻再确定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的。
(2) 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
(3) 可动态指定一组对象处理请求,客户端可以动态创建职责链来处理请求,还可以改变链中处理者之间的先后次序。