从击鼓传花谈起
击鼓传花是一种热闹而又紧张的饮酒游戏。在酒宴上宾客依次坐定位置,由一人击鼓,击鼓的地方与传花的地方是分开的,以示公正。开始击鼓时,花束就开始依次传递,鼓声一落,如果花束在某人手中,则该人就得饮酒。
假比说,贾母、贾赦、贾政、贾宝玉和贾环是五个参加击鼓传花游戏的传花者,他们组成一个环链。击鼓者将花传给贾母,开始传花游戏。花由贾母传给贾赦,由贾赦传给贾政,由贾政传给贾宝玉,又由贾宝玉传给贾环,由贾环传回给贾母,如此往复(见下图)。当鼓声停止时,手中有花的人就得执行酒令。
击鼓传花便是责任链模式的应用。在责任链模式里,很多的对象由每一个对象对其下家的引用而联接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
责任链可能是一条直线、一个环链甚至一个树结构的一部分。
责任链模式的结构
责任链模式是一种对象的行为模式,它所涉及到的角色如下:
第一、抽象处理者(Handler)角色、定义出一个处理请求的接口;如果需要,接口可以定义出一个方法,以返回对下家的引用。下图给出了一个示意性的类图:
图2、抽象处理者角色。
在图中的积累关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。
第二、具体处理者(ConcreteHandler)角色、处理接到请求后,可以选择将请求处理掉,或者将请 求传给下家。下图给出了一个示意性的类图。
图3、具体处理者角色。
上图中的示意性的具体处理者ConcreteHandler类只有handleRequest()一个方法。
责任链模式的静态类结构可见下图:
图4、责任链模式的类图定义。
纯的与不纯的责任链模式
一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,二是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又把责任向下传的情况。
在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接受;在一个不纯的责任链模式里面,一个请求可以最终不被任何接受端对象所接受。
纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。有些人认为不纯的责任链根本不是责任链模式,这也许是有道理的;但是在实际的系统里,纯的责任链很难找到;如果坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大的意义了。
责任链模式要求链上所有的对象都继承自一个共同的父类
在什么情况下使用责任链模式
在下面的情况下使用责任链模式:
第一、系统已经有一个由处理者对象组成的链。这个链可能由复合模式给出,
第一、当有多于一个的处理者对象会处理一个请求,而且在事先并不知道到底由哪一个处理者对象处理一个请求。这个处理者对象是动态确定的。
第二、当系统想发出一个请求给多个处理者对象中的某一个,但是不明显指定是哪一个处理者对象会处理此请求。
第三、当处理一个请求的处理者对象集合需要动态地指定时。
使用责任链模式的长处和短处
责任链模式减低了发出命令的对象和处理命令的对象之间的耦合,它允许多与一个的处理者对象根据自己的逻辑来决定哪一个处理者最终处理这个命令。换言之,发出命令的对象只是把命令传给链结构的起始者,而不需要知道到底是链上的哪一个节点处理了这个命令。
显然,这意味着在处理命令上,允许系统有更多的灵活性。哪一个对象最终处理一个命令可以因为由那些对象参加责任链、以及这些对象在责任链上的位置不同而有所不同。
责任链模式的实现
链结构的由来
值得指出的是,责任链模式并不创建出责任链。责任链的创建必须有系统的其它部分完成。
责任链模式减低了请求的发送端和接收端之间的耦合,使多个对象都有机会处理这个请求。一个链可以是一条线,一个树,也可以是一个环。链的拓扑结构可以是单连通的或多连通的,责任链模式并不指定责任链的拓扑结构。但是责任链模式要求在同一个时间里,命令只可以被传给一个下家(或被处理掉);而不可以传给多于一个下家。在下面的图中,责任链是一个树结构的一部分。
图9、责任链是系统已有的树结构的一部分。图中有阴影的对象给出了一个可能的命令传播路径。
责任链的成员往往是一个更大的结构的一部分。比如在前面所讨论的《红楼梦》中击鼓传花的游戏中,所有的成员都是贾府的成员。如果责任链的成员不存在,那么为了使用责任链模式,就必须创建它们;责任链的具体处理者对象可以是同一个具体处理者类的实例。
在Java的1.0版的AWT事件处理模型里,责任链便是视窗上的部件的容器等级结构。
在下面会谈到的Internet Explorer的DHTML的DOM事件处理模型里,责任链则是DOM等级结构本身。
命令的传递
在一个责任链上传递的可能不只有一个命令,而是数个命令。这些命令可以采取抽象化层、具体化层的多态性实现方式,见下图,从而可以将命令对象与责任链上的对象之间的责任分隔开,并将命令对象与传播命令的对象分隔开。
图10、多个命令在责任链上的传播。
例子:
FilterChain管理整个Filter,并且自己也继承Filter,这样就可以附加其他FilterChain
public class FilterChain implements Filter { List<Filter> filters = new ArrayList<Filter>(); private int index = 0; public FilterChain addFilter(Filter f) { filters.add(f); return this; }
public void doFilter(Request request, Response response, FilterChain chain) { if(index == filters.size()) return; Filter f = filters.get(index); index ++; f.doFilter(request, response, chain); } } public class HTMLFilter implements Filter { public void doFilter(Request request, Response response, FilterChain chain) { request.setRequestStr(request.getRequestStr().replace('<', '[')); request.setRequestStr(request.getRequestStr().replace('>', ']') + "---HTMLFilter()"); chain.doFilter(request, response, chain); response.setResponseStr(response.getResponseStr() + "---HTMLFilter()"); } }
本文借鉴。
出处:yesky责任编辑:方舟
版权声明:欢迎转载,希望在你转载的同时,添加原文地址,谢谢配合