定义
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,而是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又 把责任向下传的情况。
在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的责任链模式里面,一个请求可以最终不被任何接收端对象所接收。
纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。有些人认为不纯的责任链根本不是责任链模式,这也许是有道理的。但是在实际的系统里,纯的责任链很难找到。如果坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大意义了。
UML
抽象处理者(Handler)角色:定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。这个角色通常由一个Java抽象类或者Java接口实现。上图中Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。
具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。
实例
Tomcat里边的管道模式(Pipeline);Servlet的Filter,Struts2的interceptor。上边的这些可以说都是使用了责任链模式的抽象,或者说变种,下面我们就来看一下"原生态"的责任链模式。
public abstract class Handler { /** * 持有后继的责任对象 */ protected Handler successor; /** * 示意处理请求的方法,虽然这个示意方法是没有传入参数的 * 但实际是可以传入参数的,根据具体需要来选择是否传递参数 */ public abstract void handleRequest(); /** * 取值方法 */ public Handler getSuccessor() { return successor; } /** * 赋值方法,设置后继的责任对象 */ public void setSuccessor(Handler successor) { this.successor = successor; } } //具体处理角色 public class ConcreteHandler extends Handler { /** * 处理方法,调用此方法处理请求 */ @Override public void handleRequest() { /** * 判断是否有后继的责任对象 * 如果有,就转发请求给后继的责任对象 * 如果没有,则处理请求 */ if(getSuccessor() != null) { System.out.println("放过请求"); getSuccessor().handleRequest(); }else { System.out.println("处理请求"); } } } //客户端 public class Client { public static void main(String[] args) { //组装责任链 Handler handler1 = new ConcreteHandler(); Handler handler2 = new ConcreteHandler(); handler1.setSuccessor(handler2); //提交请求 handler1.handleRequest(); } }
如果你的请假时间小于0.5天,那么只需要向leader打声招呼就OK了。
如果0.5<请假天数<=3天,需要先leader打声招呼,要不然leader不知你跑哪里,然后部门经理直接签字。
如果3<请假天数 天,需要先leader打声招呼,然后到部门经理签字,最好总经经理确认签字,
当你看到这情况后你心里是不是已经有了自己的想法了?写一系列的if语句来一条条的判断.但这样的写法虽然可以实现目前的需求,可如果当流程改了呢?我请假超过3天,告诉leader和总经理签字就可以,那你又得一步一步修改程序。如果if语句的条数发生变化的话我们还必须在代码中添加必要的if判断,这对于程序的维护来说是相当麻烦的.如果我们使用职责链模式的话就可以相当简单了.
优点
可以降低系统的耦合度;
简化对象的相互连接(因为它不需要知道链的结构);
同时增强给对象指派职责的灵活性,增加新的请求处理类也很方便(动态的改变链内的成员或调动他们的次序);
缺点
缺点在于不能保证请求一定被接收,且对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便(可能不容易观察运行时的特征)。
使用场景
• 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
• 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
•可动态指定一组对象处理请求。
经常被使用在窗口系统中,处理鼠标和键盘之类的事件。