设计模式:责任链模式

责任链模式  


一、 引言 
    初看责任链模式,心里不禁想起了一个以前听过的相声:看牙。说一个病人看牙的时候, 
医生不小心把拔下的一个牙掉进了病人嗓子里。各个科室的医生推卸责任,搞得病人因此楼 
上楼下的跑了不少冤枉路,最后无果而终。 
    责任链模式就是这种“推卸”责任的模式,你的问题在我这里能解决我就解决,不行就把 
你推给另一个对象。至于到底谁解决了这个问题了呢?我管呢! 


二、 定义与结构 
    从名字上大概也能猜出这个模式的大概模样——系统中将会存在多个有类似处理能力 
的对象。当一个请求触发后,请求将在这些对象组成的链条中传递,直到找到最合适的“责 
任”对象,并进行处理。 
     《设计模式》中给它的定义如下:使多个对象都有机会处理请求,从而避免请求的发送 
者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一 
个对象处理它为止。 
    呵呵,从定义上可以看出,责任链模式的提出是为了“解耦”,以应变系统需求的变更和 
不明确性。 
    下面是《设计模式》中给出的适用范围: 
1)  有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。 
2)  你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 
3)  可处理一个请求的对象集合应被动态指定。 


    责任链模式真的能给发送者和接收者之间解耦(这好像很神奇)吗?先来看下它的组成 
角色。这个问题我会在下面提及。 
    责任链模式由两个角色组成: 
1)  抽象处理者角色(Handler):它定义了一个处理请求的接口。当然对于链子的不同实现, 
    也可以在这个角色中实现后继链。 
2)  具体处理者角色(Concrete   Handler):实现抽象角色中定义的接口,并处理它所负责 
    的请求。如果不能处理则访问它的后继者。 
    至于类图不放也罢。毕竟就是一个继承或者实现。 


三、 纯与不纯 
    责任链模式的纯与不纯的区别,就像黑猫、白猫的区别一样。不要刻意的去使自己的代 
码来符合一个模式的公式。只要能够使代码降低耦合、提高重用,满足系统需求并能很好的 
适应变化就好了。正所谓:管它黑猫白猫,抓住老鼠就是好猫! 
    纯的责任链模式,规定一个具体处理者角色只能对请求作出两种动作:自己处理;传给 
下家。不能出现处理了一部分,把剩下的传给了下家的情况。而且请求在责任链中必须被处 
理,而不能出现无果而终的结局。 
    反之,则就是不纯的责任链模式。 
    不纯的责任链模式还算是责任链模式吗?比如一个请求被捕获后,每个具体处理者都尝 
试去处理它,不管结果如何都将请求再次转发。我认为这种方式的实现,算不算是责任链模 
式的一种倒不重要,重要的是我们也能从中体味到责任链模式的思想:通过将多个处理者之 
间建立联系,来达到请求与具体的某个处理者的解耦。 
    下面的例子就是采用了上面提到的“不纯的责任链模式”。 


四、 举例 
    这个例子来源于项目中我刚刚完成的一个小功能点——“代号自动生成器”。在项目中存 
在很多地方,比如:员工工号、档案代号,要求客户在使用时输入。而这些代号对于一个特 
定的企业或者类别,往往有一定的规则。因此可以让用户在系统参数中维护一定的规则,然 
后通过“代号自动生成器”来给用户生成代号。 
    根据初期需求,用户代号中往往存在以下几种变动元素:年份、月份、日期、流水号。 
由于需求比较简单,因此考虑到用户可能存在其他变动元素,所以我打算在“被第一颗子弹 
击中”后重构一下现有的结构。下面就是我在头脑中演绎过的使用责任链模式的重构。 
    这里只用来说明下责任链模式的结构和使用,因此不体现功能细节。 


    //这是抽象处理者角色 


    public interface CodeAutoParse { 


      //这里就是统一的处理请求使用的接口 


       String[] generateCode(String moduleCode, int number, String rule,String[] target) 
            throws BaseException; 
    } 


    //这个为处理日期使用的具体处理者 


    public class DateAutoParse implements CodeAutoParse{ 
       //获取当前时间 


       private final Calendar currentDate = Calendar.getInstance(); 


         //这里用来注入下一个处理者,系统中采用Spring Bean 管理 


         private CodeAutoParse theNextParseOfDate; 


         public void setTheNextParseOfDate(CodeAutoParse theNextParseOfDate){ 
        this.theNextParseOfDate = theNextParseOfDate ; 
       } 


       /* 
        *实现的处理请求的接口 
       *这个接口首先判断用户定义的格式是否有流水号,有则解析,没有则跳过 
       *下传到下一个处理者 


      */ 
       public String[] generateCode(String moduleCode, int number, String rule, String[] 
    target) 
            throws BaseException { 
            //这里省略了处理的业务 


            …… 
            if(theNextParseOfDate != null) 

                return theNextParseOfDate.generateCode(moduleCode , number , rule, 
target) 
            else 
                return target; 
    } 


    其它具体处理者也是如此的结构,每一个里面都设置有一个用来存放下一个处理者的引 
用,不管你有没有下一个处理者。 
    其实责任链模式本身的结构和使用都没有什么,就是一个继承或者实现。在处理请求的 
时候,按照规定去调用下一个处理者。但是怎么来维护这样一条链子呢? 
     《设计模式》一书中仅仅说必须自己引入它,可以参考使用list 或者 map 来进行注册。 
而在上面我使用spring 来管理具体处理者角色的引入。当有了新的处理者需要添加的时候, 
仅仅需要修改下配置文件。 


五、 其他 
    责任链模式优点,上面已经体现出来了。无非就是降低了耦合、提高了灵活性。但是责 

任链模式可能会带来一些额外的性能损耗,因为它每次执行请求都要从链子开头开始遍历。 

下载:

http://download.csdn.net/detail/undoner/5335717

深入浅出设计模式-中文版



1.简述职责链的优缺点;

优点如下:

1)降低耦合度

在职责链模式里面,请求者并不知道接收者是谁,也不知道具体如何处理,请求者只是负责向职责链发出请求就可以了。而每个职责对象也不用管请求者或者是其它的职责对象,只负责处理自己的部分,其它的就交由其它的职责对象去处理。也就是说,请求者和接收者是完全解耦的。 

2)可简化对象的相互连接

3)增强给对象指派职责的灵活性

职责链模式会把功能处理分散到单独的职责对象里面,然后在使用的时候,可以动态组合职责形成职责链,从而可以灵活的给对象分配职责,也可以灵活的实现和改变对象的职责。

(4)增加新的请求处理类很方便

缺点如下:

1)不能保证请求一定被接收

职责链模式的每个职责对象只负责自己处理的那一部分,因此可能会出现某个请求,把整个链传递完了,都没有职责对象处理它。这就需要在使用职责链模式的时候注意,需要提供默认的处理,并且注意构建的链的有效性。 

2)系统性能将受到一定影响,而且在进行代码调试时不太方便;可能会造成循环调用

2.简述职责链模式的使用范围

有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。

在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。

可动态指定一组对象处理请求。

3. 简要分析职责链的本质

1)分离职责 

分离职责是前提,只有先把复杂功能分开,拆分成很多的步骤和小的功能处理,然后才能合理规划和定义职责类,可以有很多的职责类来负责处理某一个功能,让每个职责类负责处理功能的某一个方面,在运行期间进行动态组合,形成一个处理的链,把这个链运行完,那么功能也就处理完了

2)动态组合才是职责链模式的精华所在,因为要实现请求对象和处理对象的解耦,请求对象不知道谁才是真正的处理对象,因此要动态的把可能的处理对象组合起来,由于组合的方式是动态的,这就意味着可以很方便的修改和添加新的处理对象,从而让系统更加灵活和具有更好的扩展性。

    这么做还会有一个潜在的优点,就是可以增强职责功能的复用性。如果职责功能是很多地方都可以使用的公共功能,那么它可以应用在多个职责链中复用。



posted on 2013-05-08 09:36  吴一达  阅读(157)  评论(0编辑  收藏  举报

导航