24种设计模式--责任链模式【Chain ofResponsibility Pattern】

  中国古代对妇女制定了“三从四德”的道德规范,“三从”是指“未嫁从父、既嫁从夫、夫死从子”,也就是说一个女性,在没有结婚的时候要听从于父亲,结了婚后听从于丈夫,丈夫死了还要听儿子的,举个例子来说,一个女的要出去逛街,同样这样的一个请求,在她没有出嫁前她必须征得父亲的同意,出嫁之后必须获得丈夫的许可,那丈夫死了怎么办?一般都是男的比女的死的早,还要问问儿子是否允许自己出去逛街,估计你下边马上要问要是没有儿子怎么办?请示小叔子、侄子等等,在父系社会中,妇女只占从属地位,现在想想中国的妇女还是比较悲惨的,逛个街还要请示来请示去,而且作为父亲、丈夫、儿子只有两种选择:要不承担起责任来告诉她允许或不允许逛街,要不就让她请示下一个人,这是整个社会体系的约束,应用到我们项目中就是业务规则,那我们来看怎么把“三从”通过我们的程序来实现,需求很简单:通过程序描述一下古代妇女的“三从”制度,好我们先看类图:

  非常简单的类图,这个实现也非常简单,我们先看 IWomen 接口:

 1 package com.pattern.chainOfResponsibility;
 2
 3 /**
 4  * 古代悲哀女性的总称
 5  * @author http://www.cnblogs.com/initial-road/
 6  *
 7  */
 8 public interface IWomen {
 9
10     // 获得个人状况
11     public int getType();
12
13     //获得个人请示,你要干什么?出去逛街?约会?还是看电影
14     public String getRequest();
15
16 }

  女性就两个参数,一个是当前的个人状况,是结婚了呢还是没结婚,丈夫有没有去世,另外一个是要请示的内容,要出去逛街呀还是吃饭,我们看实现类:

 1 package com.pattern.chainOfResponsibility;
 2
 3 /**
 4  * 古代女性的总称
 5  * @author http://www.cnblogs.com/initial-road/
 6  *
 7  */
 8 public class Women implements IWomen{
 9
10     // 通过一个int类型的参数来描述妇女的个人状况
11     private int type = 0;
12
13     // 妇女的请示
14     private String request = "";
15
16     // 构造函数传递过来请求
17     public Women(int _type, String _request){
18         this.type = _type;
19         this.request = _request;
20     }
21
22     // 获得妇女的请求
23     public String getRequest() {
24         return this.request;
25     }
26
27     // 获得自己的状况
28     public int getType() {
29         return this.type;
30     }
31
32 }

  我们使用数字来代表女性的不同状态,1 是未结婚,2 是已经结婚的,而且丈夫建在,3 是丈夫去世了的。我们再来看有处理权的人员接口:

 1 package com.pattern.chainOfResponsibility;
 2
 3 /**
 4  * 父系关系,那就是男性有至高权利,handler控制权
 5  * @author http://www.cnblogs.com/initial-road/
 6  *
 7  */
 8 public interface IHandler {
 9
10     // 一个女性(女儿,妻子或者是母亲)要求逛街,你要处理这个请求
11     public void handleMessage(IWomen women);
12
13 }
14
15 // 父亲、丈夫、儿子都是这个 IHandler 接口的实现者:
16
17 package com.pattern.chainOfResponsibility;
18
19 /**
20  * 父亲
21  * @author http://www.cnblogs.com/initial-road/
22  *
23  */
24 public class Father implements IHandler {
25
26     // 未出嫁女儿来请求父亲
27     public void handleMessage(IWomen women) {
28         System.out.println("女儿的请求是:" + women.getRequest());
29         System.out.println("父亲的答复是: 同意");
30     }
31
32 }
33
34
35 package com.pattern.chainOfResponsibility;
36
37 /**
38  * 丈夫类
39  * @author http://www.cnblogs.com/initial-road/
40  *
41  */
42 public class Husband implements IHandler {
43
44     // 妻子向丈夫请示
45     public void handleMessage(IWomen women) {
46         System.out.println("妻子的请示是:" + women.getRequest());
47         System.out.println("丈夫的答复是: 同意");
48     }
49
50 }
51
52
53 package com.pattern.chainOfResponsibility;
54
55 /**
56  * 儿子类
57  * @author http://www.cnblogs.com/initial-road/
58  *
59  */
60 public class Son implements IHandler {
61
62     // 目前向儿子请示
63     public void handleMessage(IWomen women) {
64         System.out.println("母亲的请示是:" + women.getRequest());
65         System.out.println("儿子的答复是: 同意");
66     }
67
68 }

  这三个类非常非常的简单,就一个方法,处理女儿、妻子、母亲提出的请求,再来看 Client 是怎么组装的:

 1 package com.pattern.chainOfResponsibility;
 2
 3 import java.util.ArrayList;
 4 import java.util.Random;
 5
 6 /**
 7  * 我们后人来看这样的社会道德
 8  * @author http://www.cnblogs.com/initial-road/
 9  *
10  */
11 public class Client {
12
13     public static void main(String[] args) {
14         // 随机挑选几个女性
15         Random rand = new Random();
16         ArrayList<IWomen> arrayList = new ArrayList<IWomen>();
17         for(int i=0;i<5;i++){
18             arrayList.add(new Women(rand.nextInt(4), "我要出去逛街"));
19         }
20
21         // 定义三个请示对象
22         IHandler father = new Father();
23         IHandler husband = new Husband();
24         IHandler son = new Son();
25
26         for(IWomen women : arrayList){
27             // 未结婚少女,请示父亲
28             if(women.getType() == 1){
29                 System.out.println("\n-----女儿向父亲请示-----\n");
30                 father.handleMessage(women);
31             }else if(women.getType() == 2){
32                 System.out.println("\n-----妻子向丈夫请示-----\n");
33                 husband.handleMessage(women);
34             }else if(women.getType() == 3){
35                 System.out.println("\n-----母亲向儿子请示-----\n");
36                 son.handleMessage(women);
37             }else {
38                 // 暂时啥也不做
39             }
40         }
41
42     }
43
44 }

  首先是通过随机方法产生了 5 个古代妇女的对象,她们是如何就逛街这件事去请示的(由于是随机的,您看到得结果可能和这里有所不同)。

  “三从四德”的旧社会规范已经完整的表现出来了,你看谁向谁请示都定义出来了,但是你是不是发现这个程序写的有点不舒服?有点别扭?有点想重构它的感觉?那就对了!这段代码有以下几个问题:

  失去面向对象的意义。对女儿提出的请示,应该在父亲类中做出决定,父亲这个类应该是知道女儿的请求应该自己处理,而不是在 Client 类中进行组装出来,也就是说原本应该是父亲这个类做的事情抛给了其他类进行处理;

  迪米特法则相违背。我们在 Client 类中写了 if…eles 的判断条件,你看这个条件体内都是一个接口IHandler 的三个实现类,谁能处理那个请求,怎么处理,直接在实现类中定义好不就结了吗?你的类我知道的越少越好,别让我猜测你类中的逻辑,想想看,把这段 if…else 移动到三个实现类中该怎么做?

  耦合过重。这是什么意思呢,我们要根据 Women 的 type 来决定使用 IHandler 的那个实现类来处理请求,我问你,如果 IHanlder 的实现类继续扩展怎么办?修改 Client 类?与开闭原则违背喽!

  异常情况没有考虑。妻子只能向丈夫请示吗?如果妻子向自己的父亲请示了,父亲应该做何处理?我们的程序上可没有体现出来。

  既然有这么多的问题,那我们要想办法来解决这些问题,我们可以抽象成这样一个结构,女性的请求先发送到父亲类,父亲类一看是自己要处理的,就回应处理,如果女儿已经出嫁了,那就要把这个请求转发到女婿来处理,那女婿一旦去天国报道了,那就由儿子来处理这个请求,类似于这样请求:

  父亲、丈夫、儿子每个节点有两个选择:要么承担责任,做出回复;要么把请求转发到后序环节。结构分析的已经很清楚了,那我们看怎么来实现这个功能,先看类图:

  从类图上看,三个实现类 Father、Husband、Son 只要实现构造函数和父类的中抽象方法就可以了,具体怎么处理这些请求,都已经转移到了Hanlder 抽象类中,我们来看 Hanlder 怎么实现:

 1 package com.pattern.chainOfResponsibility.advance;
 2
 3 import com.pattern.chainOfResponsibility.IWomen;
 4
 5 /**
 6  * 父系社会,那就是男性有至高权利,handler控制权
 7  * @author http://www.cnblogs.com/initial-road/
 8  *
 9  */
10 public abstract class Handler {
11
12     // 能处理的级别
13     private int level = 0;
14
15     // 责任传递,下一个责任人是谁
16     private Handler nextHandler;
17
18     // 每个类都要说明一下自己能处理那些请求
19     public Handler(int _level){
20         this.level = _level;
21     }
22
23     // 一个女性(女儿,妻子或者是母亲)要求逛街,你要处理这个请求
24     public final void handleMessage(IWomen women){
25         if(women.getType() == this.level){
26             this.response(women);
27         }else{
28             if(this.nextHandler != null){    // 有后续环节,才把请求往后传送
29                 this.nextHandler.response(women);
30             }else{
31                 // 已经没有后续处理人了,不用处理了
32                 System.out.println("-----没地方请示了,不做处理了!-----\n");
33             }
34         }
35     }
36
37     /**
38      * 如果你属于你处理的返回,你应该让她找下一个环节的人,比如
39      * 女儿出嫁了,还向父亲请示是否可以逛街,那父亲就应该告诉女儿,应该找丈夫请示
40      */
41     public void setNext(Handler _handler){
42         this.nextHandler = _handler;
43     }
44
45     // 有请示那当然要回应
46     public abstract void response(IWomen women);
47 }

  有没有看到,其实在这里也用到模版方法模式,在模版方法中判断请求的级别和当前能够处理的级别,如果相同则调用基本方法,做出反馈;如果不相等,则传递到下一个环节,由下一环节做出回应。基本方法 response 要各个实现类都要实现,我们来看三个实现类:

 1 package com.pattern.chainOfResponsibility.advance;
 2
 3 import com.pattern.chainOfResponsibility.IWomen;
 4
 5 /**
 6  * 父亲
 7  * @author http://www.cnblogs.com/initial-road/
 8  *
 9  */
10 public class Father extends Handler {
11
12     // 父亲只处理女儿的请求
13     public Father() {
14         super(1);
15     }
16
17     // 父亲的答复
18     public void response(IWomen women) {
19         System.out.println("-----女儿向父亲请示-----");
20         System.out.println(women.getRequest());
21         System.out.println("父亲的答复是: 同意\n");
22     }
23
24 }
25
26
27 package com.pattern.chainOfResponsibility.advance;
28
29 import com.pattern.chainOfResponsibility.IWomen;
30
31 /**
32  * 丈夫类
33  * @author http://www.cnblogs.com/initial-road/
34  *
35  */
36 public class Husband extends Handler {
37
38     // 丈夫只处理妻子的请求
39     public Husband() {
40         super(2);
41     }
42
43     // 丈夫请示的答复
44     public void response(IWomen women) {
45         System.out.println("-----妻子向丈夫请示-----");
46         System.out.println(women.getRequest());
47         System.out.println("丈夫的答复是: 同意\n");
48     }
49
50 }
51
52
53 package com.pattern.chainOfResponsibility.advance;
54
55 import com.pattern.chainOfResponsibility.IWomen;
56
57 /**
58  * 儿子类
59  * @author http://www.cnblogs.com/initial-road/
60  *
61  */
62 public class Son extends Handler {
63
64     // 儿子只处理母亲的请求
65     public Son() {
66         super(3);
67     }
68
69     // 儿子的答复
70     public void response(IWomen women) {
71         System.out.println("-----母亲向儿子请示-----");
72         System.out.println(women.getRequest());
73         System.out.println("儿子的答复是: 同意\n");
74     }
75
76 }

  这三个类都很简单,构造方法那是你必须实现的,父类已经定义了,子类不实现编译不通过,通过构造方法我们设置了各个类能处理的请求类型,Father 只能处理请求类型为 1(也就是女儿)的请求; Husband只能处理请求类型类 2(也就是妻子)的请求;儿子只能处理请求类型为 3(也就是目前)的请求。

  Women 类的接口没有任何变化,实现类少有变化,看代码:

 1 package com.pattern.chainOfResponsibility.advance;
 2
 3 import com.pattern.chainOfResponsibility.IWomen;
 4
 5 /**
 6  * 古代女性的总称
 7  * @author http://www.cnblogs.com/initial-road/
 8  *
 9  */
10 public class Women implements IWomen {
11
12     // 通过一个int类型的参数来描述妇女的个人状况
13     private int type = 0;
14
15     // 妇女的请示
16     private String request = "";
17
18     // 构造函数传递过来请求
19     public Women(int _type, String _request){
20         this.type = _type;
21         switch(this.type){
22         case 1:
23             this.request = "女儿的请求是:" + _request;
24             break;
25         case 2:
26             this.request = "妻子的请求是:" + _request;
27             break;
28         case 3:
29             this.request = "母亲的请求是:" + _request;
30             break;
31         }
32     }
33
34     // 获得妇女的请求
35     public String getRequest() {
36         return this.request;
37     }
38
39     // 获得自己的状况
40     public int getType() {
41         return this.type;
42     }
43
44 }

  就是为了展示结果清晰一点,Women 类做了一点改变。我们再来看 Client 类是怎么描述古代这一个礼节的:

 1 package com.pattern.chainOfResponsibility.advance;
 2
 3 import java.util.ArrayList;
 4 import java.util.Random;
 5 import com.pattern.chainOfResponsibility.IWomen;
 6
 7 /**
 8  * 我们后人来看这样的社会道德
 9  * @author http://www.cnblogs.com/initial-road/
10  *
11  */
12 public class Client {
13
14     public static void main(String[] args) {
15         // 随机挑选几个女性
16         Random rand = new Random();
17         ArrayList<IWomen> arrayList = new ArrayList<IWomen>();
18
19         for(int i=0;i<5;i++){
20             arrayList.add(new Women(rand.nextInt(4), "我要出去逛街"));
21         }
22
23         // 定义三个请示对象
24         Handler father = new Father();
25         Handler husband = new Husband();
26         Handler son = new Son();
27
28         // 设置提示顺序
29         father.setNext(husband);
30         husband.setNext(son);
31
32         for(IWomen women : arrayList){
33             father.handleMessage(women);
34         }
35     }
36
37 }

  结果也正确,业务调用类 Client 也不用去做判断到底是需要谁去处理,而且 Handler 抽象类的子类以后可以继续增加下去,只是我们这个传递链增加而已,调用类可以不用了解变化过程,甚至是谁在处理这个请求都不用知道。

  以上讲解的就是责任链模式,你看 Father、Husband、Son 这三个类的处理女性的请求时是不是在传递呀,每个环节只有两个选项:要么承担责任做出回应,要么向下传递请求,最终会有环节做出回应,通用类图如下:

  在通用类图中 Handler 是一个接口或者是抽象类,每个实现类都有两个方法 HandlerRequest 是处理请求,setNext 是设置当前环节怎么把不属于自己处理的请求扔给谁,对于这个类图我觉得需要改变,融合进来模版方法模式,类图如下:

  想想单一职责法则和迪米特法则吧,通过融合模版方法模式,各个实现类只要关注的自己业务逻辑就成了,至于说什么事要自己处理,那就让父类去决定好了,也就是说父类实现了请求传递的功能,子类实现请求的处理,符合单一职责法则,各个类只作一个动作或逻辑,也就是只有一个原因引起类的改变,我 建议大家在使用的时候用这种方法,好处是非常明显的了,子类的实现非常简单,责任链的建立也非常的灵活。

时间: 2024-11-24 14:06:53

24种设计模式--责任链模式【Chain ofResponsibility Pattern】的相关文章

[设计模式] 责任链模式 Chain of Responsibility

转    http://blog.csdn.net/wuzhekai1985   http://www.jellythink.com/archives/878 向项目经理提交了休假申请,我的项目经理向项目主管提交了我的休假申请,项目主管向部门经理提交了我的休假申请:最后,部门经理同意了我的休假申请.是的,一个简单的休假申请,需要这么复杂的流程,这也是一个公司保证它正常运行的必要.如果部门经理休假了,那么我的休假申请由谁审批呢?这个时候由项目主管代替部门经理进行审批.一个休假申请的审批制度有着严格

24种设计模式--中介者模式【Mediator Pattern】

各位好,大家都是来自五湖四海,都要生存,于是都找了个靠山——公司,给你发薪水的地方,那公司就要想尽办法盈利赚钱,盈利方法则不尽相同,但是作为公司都有相同三个环节:采购.销售和库存,这个怎么说呢?比如一个软件公司,要开发软件,需要开发环境吧, Windows 操作系统,数据库产品等,这你得买吧,那就是采购,开发完毕一个产品还要把产品推销出去,推销出去了大家才有钱赚,不推销出去大家都去喝西北风呀,既然有产品就必然有库存,软件产品也有库存,你总要拷贝吧,虽然是不需要占用库房空间,那也是要占用光盘或硬盘

[设计模式-行为型]责任链模式(Chain of Responsibility)

概括 名称 Chain of Responsibility 结构 动机 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 适用性 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定. 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求. 可处理一个请求的对象集合应被动态指定. 解析 形象比喻: 晚上去上英语课, 为了好开溜坐到了最后一排, 哇, 前面坐了好几个漂亮的MM 哎

设计模式-责任链模式

1 模式动机 为了降低系统的耦合度,将事件请求者和接收者解耦,我们可以使用命令模式来设计系统.通过增加不同的命令对象,不仅可以解耦,也可以有效解决发送和接收处理速度不一样的问题. 2 模式定义 责任链模式(Chain of Responsibility Pattern):将多个对象连成一条链,沿着这条链传递请求,直到有一个对象处理它为止,使得多个对象都有机会处理该请求. 3 模式分析 Handler处理者接口: 声明处理请求的接口. ConcreteHandler具体处理者类: 实现处理请求的接

java 设计模式 -- 责任链模式

设计模式 – 责任链模式 介绍: 责任链模式是一种动态行为模式,有多个对象,每一个对象分别拥有其下家的引用.连起来形成一条链.待处理对象则传到此链上,在此链进行传递,且待处理对象并不知道此会被链上的哪个对象处理,这使得我们能够动态的添加链上的对象而且分配责任. 纯责任链和非纯责任链 责任链分为两种.纯责任链和非纯责任链. 纯责任链是待处理对象request在处理对象handler链上传递,每一个处理对象handler处理request的一部分,到终于处理完毕.非纯责任链则是待处理对象reques

[设计模式] 责任链模式之变种 - 责任链子

今天看到 wikipedia 的责任链模式,好奇之下搜寻相关文章,此文章主要参考 91大的 [.NET]重构之路系列v11 –用责任链模式打破讨厌的switch case 的变种作法,所以跟原本的责任链模式的设计思路不太相同,但结果相同, 所以阅读前,建议先看完91大的文章后,在来看这篇会比较能感觉出差异. ?这边先引用91大文章结尾结论中的补充来复习一下责任链的重点, 20120415 补充:责任链的用意在于把每个角色的职责分清楚,每个对象只需要做好自己的事,透过责任链的方式来组合,并完成使用

责任链模式-Chain of Responsibility(Java实现), 例1

责任链模式-Chain of Responsibility, 例1 在这种模式中,通常每个接收者都包含对另一个接收者的引用.如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推. Trouble类 本类是:待责任链来处理的问题Trouble类. 本例子较简单, Trouble只有一个int型作为待处理的编号. public class Trouble { private int number; public Trouble(int number) { this.number

24天学会设计模式------责任链模式

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka/article/details/43210027 一.责任链模式(Chain of Responsibility Pattern) 1.简介 从名字上大概也能猜出这个模式的大概模样--系统中将会存在多个有类似处理能力的对象.当一个请求触发后,请求将在这些对象组成的链条中传递,直到找到最合适的"责任"对象,并进行处理.<设计模式>中给它的定义如下:使多个对象都有机会处理请

设计模式之二十:责任链模式(Chain of Responsibility)

感觉这个设计模式和组合模式一样是一种非常巧妙的设计模式,在须要使用它的地方假设不使用这样的设计模式代码会变的非常复杂,可是这样的设计模式的基本原理又是非常easy的. 责任链模式: 通过使多个对象都有机会来处理请求的方式避免了请求的发送者和接收者之间的耦合.将接收者组织成链式的结构这样能够将请求沿着这条链进行传递,直到有接收者对它进行处理. UML类图: 主要包含: Handler:定义了一个处理请求的接口,实现了定义后继者的方法. ConcreteHandler:处理各自负责的请求,假设不能处