Chinaunix首页 | 论坛 | 博客
  • 博客访问: 242655
  • 博文数量: 164
  • 博客积分: 60
  • 博客等级: 民兵
  • 技术积分: 1129
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-09 21:55
文章分类

全部博文(164)

文章存档

2017年(2)

2015年(67)

2014年(95)

我的朋友

分类: Java

2015-03-31 14:15:07

转自:

1. 模式介绍

模式的定义

一个请求沿着一条“链”传递,直到该“链”上的某个处理者处理它为止。

模式的使用场景

一个请求可以被多个处理者处理或处理者未明确指定时。

2. UML类图




角色介绍

Client:客户端

Handler:抽象处理者

ConcreteHandler:具体处理者

3. 模式的简单实现

简单实现的介绍

责任链模式非常简单异常好理解,相信我它比单例模式还简单易懂,其应用也几乎无所不在,甚至可以这么说……从你敲代码的第一天起你就不知不觉用过了它最原始的裸体结构:分支语句:


点击(此处)折叠或打开

  1. public class SimpleResponsibility {
  2.     public static void main(String[] args) {
  3.         int request = (int) (Math.random() * 3);
  4.         switch (request) {
  5.         case 0:
  6.             System.out.println("SMBother handle it: " + request);
  7.             break;
  8.         case 1:
  9.             System.out.println("Aige handle it: " + request);
  10.             break;
  11.         case 2:
  12.             System.out.println("7Bother handle it: " + request);
  13.             break;
  14.         default:
  15.             break;
  16.         }
  17.     }
  18. }

谁敢说没用过上面这种结构体的站出来我保证不打屎他,没用过swith至少if-else用过吧,if-else都没用过你怎么知道github的……上面的这段代码其实就是一种最最简单的责任链模式,其根据request的值进行不同的处理。当然这只是个不恰当的例子来让大家尽快对责任链模式有个简单的理解,因为可能很多童鞋第一次听说这个模式,而人对未知事物总是恐惧的,为了消除大家的这种恐惧,我将大家最常见的code搬出来相信熟悉的代码对大家来说有一种亲切的感觉,当然我们实际应用中的责任链模式绝逼不是这么Mr.Simple,但是也不会复杂不到哪去。责任链模式,顾名思义,必定与责任Responsibility相关,其实质呢就像上面定义中说的那样一个请求(比如上面代码中的request值)沿着一条“链”(比如上面代码中我们的switch分支语句)传递,当某个处于“链”上的处理者(case定义的条件)处理它时完成处理。其实现实生活中关于责任者模式的例子数不胜数,最常见的就是工作中上下级之间的责任请求关系了。比如:

程序猿狗屎运被派出去异国出差一周,这时候就要去申请一定的差旅费了,你心里小算一笔加上各种车马费估计大概要个两三万,于是先向小组长汇报申请,可是大于一千块小组长没权利批复,于是只好去找项目主管,项目主管一看妈蛋这么狠要这么多我只能批小于五千块的,于是你只能再跑去找部门经理,部门经理看了下一阵淫笑后说没法批我只能批小于一万的,于是你只能狗血地去跪求老总,老总一看哟!小伙子心忒黑啊!老总话虽如此但还是把钱批给你了毕竟是给公司办事,到此申请处理完毕,你也可以屁颠屁颠地滚了。

如果把上面的场景应用到责任链模式,那么我们的request请求就是申请经费,组长主管经理老总们就是一个个具体的责任人他们可以对请求做出处理但是他们只能在自己的责任范围内处理该处理的请求,而程序猿只是个底层狗请求者向责任人们发起请求…………苦逼的猿。

实现源码

上面的场景我们可以使用使用如下的代码来模拟实现:

首先定义一个程序员类:


点击(此处)折叠或打开

  1. /**
  2.  * 程序猿类
  3.  *
  4.  * @author Aige{@link }
  5.  *
  6.  */
  7. public class ProgramApe {
  8.     private int expenses;// 声明整型成员变量表示出差费用
  9.     private String apply = "爹要点钱出差";// 声明字符串型成员变量表示差旅申请

  10.     /*
  11.      * 含参构造方法
  12.      */
  13.     public ProgramApe(int expenses) {
  14.         this.expenses = expenses;
  15.     }

  16.     /*
  17.      * 获取程序员具体的差旅费用
  18.      */
  19.     public int getExpenses() {
  20.         return expenses;
  21.     }

  22.     /*
  23.      * 获取差旅费申请
  24.      */
  25.     public String getApply() {
  26.         return apply;
  27.     }
  28. }

然后依次是各个大爷类:


点击(此处)折叠或打开

  1. /**
  2.  * 小组长类
  3.  *
  4.  * @author Aige{@link }
  5.  *
  6.  */
  7. public class GroupLeader {

  8.     /**
  9.      * 处理请求
  10.      *
  11.      * @param ape
  12.      * 具体的猿
  13.      */
  14.     public void handleRequest(ProgramApe ape) {
  15.         System.out.println(ape.getApply());
  16.         System.out.println("GroupLeader: Of course Yes!");
  17.     }
  18. }
  19. /**
  20.  * 项目主管类
  21.  *
  22.  * @author Aige{@link }
  23.  *
  24.  */
  25. public class Director {
  26.     /**
  27.      * 处理请求
  28.      *
  29.      * @param ape
  30.      * 具体的猿
  31.      */
  32.     public void handleRequest(ProgramApe ape) {
  33.         System.out.println(ape.getApply());
  34.         System.out.println("Director: Of course Yes!");
  35.     }
  36. }
  37. /**
  38.  * 部门经理类
  39.  *
  40.  * @author Aige{@link }
  41.  *
  42.  */
  43. public class Manager {
  44.     /**
  45.      * 处理请求
  46.      *
  47.      * @param ape
  48.      * 具体的猿
  49.      */
  50.     public void handleRequest(ProgramApe ape) {
  51.         System.out.println(ape.getApply());
  52.         System.out.println("Manager: Of course Yes!");
  53.     }
  54. }
  55. /**
  56.  * 老总类
  57.  *
  58.  * @author Aige{@link }
  59.  *
  60.  */
  61. public class Boss {
  62.     /**
  63.      * 处理请求
  64.      *
  65.      * @param ape
  66.      * 具体的猿
  67.      */
  68.     public void handleRequest(ProgramApe ape) {
  69.         System.out.println(ape.getApply());
  70.         System.out.println("Boss: Of course Yes!");
  71.     }
  72. }

好了,万事俱备只欠场景,现在我们模拟一下整个场景过程:


点击(此处)折叠或打开

  1. /**
  2.  * 场景模拟类
  3.  *
  4.  * @author Aige{@link }
  5.  *
  6.  */
  7. public class Client {
  8.     public static void main(String[] args) {
  9.         /*
  10.          * 先来一个程序猿 这里给他一个三万以内的随机值表示需要申请的差旅费
  11.          */
  12.         ProgramApe ape = new ProgramApe((int) (Math.random() * 30000));

  13.         /*
  14.          * 再来四个老大
  15.          */
  16.         GroupLeader leader = new GroupLeader();
  17.         Director director = new Director();
  18.         Manager manager = new Manager();
  19.         Boss boss = new Boss();

  20.         /*
  21.          * 处理申请
  22.          */
  23.         if (ape.getExpenses() <= 1000) {
  24.             leader.handleRequest(ape);
  25.         } else if (ape.getExpenses() <= 5000) {
  26.             director.handleRequest(ape);
  27.         } else if (ape.getExpenses() <= 10000) {
  28.             manager.handleRequest(ape);
  29.         } else {
  30.             boss.handleRequest(ape);
  31.         }
  32.     }
  33. }

运行一下,我的结果输出如下(注:由于随机值的原因你的结果也许与我不一样):

爹要点钱出差

Manager: Of course Yes!

是不是感觉有点懂了?当然上面的代码虽然在一定程度上体现了责任链模式的思想,但是确是非常terrible的。作为一个code新手可以原谅,但是对有一定经验的code+来说就不可饶恕了,很明显所有的老大都有共同的handleRequest方法而程序猿也有不同类型的,比如一个公司的php、c/c++、Android、IOS等等,所有的这些共性我们都可以将其抽象为一个抽象类或接口,比如我们的程序猿抽象父类:


点击(此处)折叠或打开

  1. /**
  2.  * 程序猿抽象接口
  3.  *
  4.  * @author Aige{@link }
  5.  *
  6.  */
  7. public abstract class ProgramApes {
  8.     /**
  9.      * 获取程序员具体的差旅费用
  10.      *
  11.      * @return 要多少钱
  12.      */
  13.     public abstract int getExpenses();

  14.     /**
  15.      * 获取差旅费申请
  16.      *
  17.      * @return Just a request
  18.      */
  19.     public abstract String getApply();
  20. }
这时我们就可以实现该接口使用呆毛具现化一个具体的程序猿,比如Android猿:


点击(此处)折叠或打开

  1. /**
  2.  * Android程序猿类
  3.  *
  4.  * @author Aige{@link }
  5.  *
  6.  */
  7. public class AndroidApe extends ProgramApes {
  8.     private int expenses;// 声明整型成员变量表示出差费用
  9.     private String apply = "爹要点钱出差";// 声明字符串型成员变量表示差旅申请

  10.     /*
  11.      * 含参构造方法
  12.      */
  13.     public AndroidApe(int expenses) {
  14.         this.expenses = expenses;
  15.     }

  16.     @Override
  17.     public int getExpenses() {
  18.         return expenses;
  19.     }

  20.     @Override
  21.     public String getApply() {
  22.         return apply;
  23.     }
  24. }
同样的,所有的老大都有一个批复经费申请的权利,我们把这个权利抽象为一个IPower接口:


点击(此处)折叠或打开

  1. /**
  2.  * 老大们的权利接口
  3.  *
  4.  * @author Aige{@link }
  5.  *
  6.  */
  7. public interface IPower {
  8.     /**
  9.      * 处理请求
  10.      *
  11.      * @param ape
  12.      * 具体的猿
  13.      */
  14.     public void handleRequest(ProgramApe ape);
  15. }

然后让所有的老大们实现该接口即可其它不变,而场景类Client中也只是修改各个老大的引用类型为IPower而已,具体代码就不贴了,运行效果也类似。

然而上面的代码依然问题重重,为什么呢?大家想想,当程序猿发出一个申请时却是在场景类中做出判断决定的……然而这个职责事实上应该由老大们来承担并作出决定,上面的代码搞反了……既然知道了错误,那么我们就来再次重构一下代码:

把所有老大抽象为一个leader抽象类,在该抽象类中实现处理逻辑:


点击(此处)折叠或打开

  1. **
  2.  * 领导人抽象类
  3.  *
  4.  * @author Aige{@link https://github.com/AigeStudio}
  5.  *
  6.  */
  7. public abstract class Leader {
  8.     private int expenses;// 当前领导能批复的金额
  9.     private Leader mSuperiorLeader;// 上级领导

  10.     /**
  11.      * 含参构造方法
  12.      *
  13.      * @param expenses
  14.      * 当前领导能批复的金额
  15.      */
  16.     public Leader(int expenses) {
  17.         this.expenses = expenses;
  18.     }

  19.     /**
  20.      * 回应程序猿
  21.      *
  22.      * @param ape
  23.      * 具体的程序猿
  24.      */
  25.     protected abstract void reply(ProgramApe ape);

  26.     /**
  27.      * 处理请求
  28.      *
  29.      * @param ape
  30.      * 具体的程序猿
  31.      */
  32.     public void handleRequest(ProgramApe ape) {
  33.         /*
  34.          * 如果说程序猿申请的money在当前领导的批复范围内
  35.          */
  36.         if (ape.getExpenses() <= expenses) {
  37.             // 那么就由当前领导批复即可
  38.             reply(ape);
  39.         } else {
  40.             /*
  41.              * 否则看看当前领导有木有上级
  42.              */
  43.             if (null != mSuperiorLeader) {
  44.                 // 有的话简单撒直接扔给上级处理即可
  45.                 mSuperiorLeader.handleRequest(ape);
  46.             } else {
  47.                 // 没有上级的话就批复不了老……不过在这个场景中总会有领导批复的淡定
  48.                 System.out.println("Goodbye my money......");
  49.             }
  50.         }
  51.     }

  52.     /**
  53.      * 为当前领导设置一个上级领导
  54.      *
  55.      * @param superiorLeader
  56.      * 上级领导
  57.      */
  58.     public void setLeader(Leader superiorLeader) {
  59.         this.mSuperiorLeader = superiorLeader;
  60.     }
  61. }
这么一来,我们的领导老大们就有了实实在在的权利职责去处理底层苦逼程序猿的请求。OK,接下来要做的事就是让所有的领导继承该类:


点击(此处)折叠或打开

  1. /**
  2.  * 小组长类
  3.  *
  4.  * @author Aige{@link }
  5.  *
  6.  */
  7. public class GroupLeader extends Leader {

  8.     public GroupLeader() {
  9.         super(1000);
  10.     }

  11.     @Override
  12.     protected void reply(ProgramApe ape) {
  13.         System.out.println(ape.getApply());
  14.         System.out.println("GroupLeader: Of course Yes!");
  15.     }
  16. }
  17. /**
  18.  * 项目主管类
  19.  *
  20.  * @author Aige{@link }
  21.  *
  22.  */
  23. public class Director extends Leader{
  24.     public Director() {
  25.         super(5000);
  26.     }

  27.     @Override
  28.     protected void reply(ProgramApe ape) {
  29.         System.out.println(ape.getApply());
  30.         System.out.println("Director: Of course Yes!");
  31.     }
  32. }
  33. /**
  34.  * 部门经理类
  35.  *
  36.  * @author Aige{@link }
  37.  *
  38.  */
  39. public class Manager extends Leader {
  40.     public Manager() {
  41.         super(10000);
  42.     }

  43.     @Override
  44.     protected void reply(ProgramApe ape) {
  45.         System.out.println(ape.getApply());
  46.         System.out.println("Manager: Of course Yes!");
  47.     }
  48. }
  49. /**
  50.  * 老总类
  51.  *
  52.  * @author Aige{@link }
  53.  *
  54.  */
  55. public class Boss extends Leader {
  56.     public Boss() {
  57.         super(40000);
  58.     }

  59.     @Override
  60.     protected void reply(ProgramApe ape) {
  61.         System.out.println(ape.getApply());
  62.         System.out.println("Boss: Of course Yes!");
  63.     }
  64. }

最后,更新我们的场景类,将其从责任人的角色中解放出来:


点击(此处)折叠或打开

  1. **
  2.  * 场景模拟类
  3.  *
  4.  * @author Aige{@link https://github.com/AigeStudio}
  5.  *
  6.  */
  7. public class Client {
  8.     public static void main(String[] args) {
  9.         /*
  10.          * 先来一个程序猿 这里给他一个三万以内的随机值表示需要申请的差旅费
  11.          */
  12.         ProgramApe ape = new ProgramApe((int) (Math.random() * 30000));

  13.         /*
  14.          * 再来四个老大
  15.          */
  16.         Leader leader = new GroupLeader();
  17.         Leader director = new Director();
  18.         Leader manager = new Manager();
  19.         Leader boss = new Boss();

  20.         /*
  21.          * 设置老大的上一个老大
  22.          */
  23.         leader.setLeader(director);
  24.         director.setLeader(manager);
  25.         manager.setLeader(boss);

  26.         // 处理申请
  27.         leader.handleRequest(ape);
  28.     }
  29. }

总结

OK,这样我们就将请求和处理分离开来,对于程序猿来说,不需要知道是谁给他批复的钱,而对于领导们来说,也不需要确切地知道是批给哪个程序猿,只要根据自己的责任做出处理即可,由此将两者优雅地解耦。


阅读(732) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~