设计模式之禅【责任链模式】

真刀实枪之责任链模式

  • “三从四德”--古代妇女的枷锁

    • 三从:未嫁从父、既嫁从夫、夫死从子
      • 也就是说,一位女性在结婚之前要听从父亲,在结婚之后要听从丈夫的,如果丈夫死了还要听从儿子的。
    • 看下类图
    • 代码

      • IWomen

        package com.peng.zrl;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月21日
         * @description
         */
        public interface IWomen {
            // 获得个人的状况
            public int getType();
        
            // 获得个人请示
            public String getRequest();
        }
        
      • Women

        package com.peng.zrl;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月21日
         * @description
         */
        public class Women implements IWomen {
            // 妇女个人状况
            private int type = 0;
            // 妇女的请示
            private String request = "";
        
            public Women(int type, String request) {
                super();
                this.type = type;
                this.request = request;
            }
        
            /*
             * 1-未出嫁 2-出嫁 3-夫死
             */
            @Override
            public int getType() {
                return this.type;
            }
        
            @Override
            public String getRequest() {
                return this.request;
            }
        
        }
        
      • IBandler

        package com.peng.zrl;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月21日
         * @description
         */
        public interface IHandler {
            // 女性的要求,处理函数
            public void HandleMessage(IWomen iwomen);
        }
        
      • Father

        package com.peng.zrl;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月21日
         * @description
         */
        public class Father implements IHandler {
        
            @Override
            public void HandleMessage(IWomen iwomen) {
                // 女子的请示
                System.out.println("女子向父亲请示:" + iwomen.getRequest());
                // 父亲的答复是同意
                System.out.println("父亲的答复是:同意!");
            }
        
        }
        
      • Hasband

        package com.peng.zrl;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月21日
         * @description
         */
        public class Husband implements IHandler {
        
            @Override
            public void HandleMessage(IWomen iwomen) {
                // 女子的请示
                System.out.println("女子向丈夫请示:" + iwomen.getRequest());
                // 父亲的答复是同意
                System.out.println("丈夫的答复是:同意!");
            }
        
        }
        
      • Son

        package com.peng.zrl;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月21日
         * @description
         */
        public class Son implements IHandler {
        
            @Override
            public void HandleMessage(IWomen iwomen) {
                // 女子的请示
                System.out.println("女子向儿子请示:" + iwomen.getRequest());
                // 父亲的答复是同意
                System.out.println("儿子的答复是:同意!");
            }
        
        }
        
      • Client

        package com.peng.zrl;
        
        import java.util.ArrayList;
        import java.util.Random;
        import java.util.concurrent.Future;
        
        /**
         * @author kungfu~peng
         * @data 2017年11月21日
         * @description
         */
        public class Client {
            public static void main(String[] args) {
                // 随机挑选几个女性
                Random random = new Random();
                ArrayList<IWomen> lists = new ArrayList<IWomen>();
                for (int i = 0; i < 10; i++) {
                    lists.add(new Women(random.nextInt(3) + 1, "我要去逛街!!"));
                }
        
                // 定义三个请示对象
                Father man1 = new Father();
                Husband man2 = new Husband();
                Son man3 = new Son();
        
                // 逛街请示
                for (IWomen iWomen : lists) {
                    if (iWomen.getType() == 1) {// 向父亲请示
                        man1.HandleMessage(iWomen);
                    } else if (iWomen.getType() == 2) {// 向丈夫请示
                        man2.HandleMessage(iWomen);
                    } else if (iWomen.getType() == 3) {// 向儿子请示
                        man3.HandleMessage(iWomen);
        
                    }
                }
            }
        }
        
      • 执行结果(因为随机,执行结果不唯一)
        女子向儿子请示:我要去逛街!!
        儿子的答复是:同意!
        女子向丈夫请示:我要去逛街!!
        丈夫的答复是:同意!
        女子向父亲请示:我要去逛街!!
        父亲的答复是:同意!
        女子向儿子请示:我要去逛街!!
        儿子的答复是:同意!
        女子向丈夫请示:我要去逛街!!
        丈夫的答复是:同意!
        女子向父亲请示:我要去逛街!!
        父亲的答复是:同意!
        女子向父亲请示:我要去逛街!!
        父亲的答复是:同意!
        女子向丈夫请示:我要去逛街!!
        丈夫的答复是:同意!
        女子向父亲请示:我要去逛街!!
        父亲的答复是:同意!
        女子向父亲请示:我要去逛街!!
        父亲的答复是:同意!
        
    • 有没有感觉有点别扭--虽然不迷信,但不符合正常的逻辑...还有以下几个问题:
      1. 职责界定不清晰:对女儿约束--应该在Father中来做,而不是在Client做;对妻子的约束--应该在Husband中来做,而不是在Client中做;对母亲的约束--应该在Son做,而不是在Client来做
      2. 代码臃肿:if-else太多
      3. 耦合过程:根据Women的type来决定使用IHandler的那个实现类来处理请求,这样导致IHandler做扩展的时候,就必须修改Client,违反了开闭原则
      4. 异常情况欠考虑:逻辑的错误--起死回生了
    • 有了问题那就解决吧--请示出去,答复是唯一的。过程如下

      • 女子的请求先发给父亲,如果女子结婚了就交给女子的丈夫处理;如果女子的丈夫去世,就交给其儿子处理,如下顺序处理图
      • 父亲、丈夫、儿子,每个节点有两个选择:要么承担责任,做出回应;要么把请求转发给后续环节。类图重写修正,如图:
      • 代码

        • IWomen

          package com.peng.zrl;
          
          /**
           * @author kungfu~peng
           * @data 2017年11月21日
           * @description
           */
          public interface IWomen {
              // 获得个人的状况
              public int getType();
          
              // 获得个人请示
              public String getRequest();
          }
          
        • Women

          package com.peng.zrl;
          
          /**
           * @author kungfu~peng
           * @data 2017年11月21日
           * @description
           */
          public class Women implements IWomen {
              // 妇女个人状况
              private int type = 0;
              // 妇女的请示
              private String request = "";
          
              public Women(int type, String request) {
                  super();
                  this.type = type;
                  // 为了便于显示,这里做了处理
                  switch (this.type) {
                  case 1:
                      this.request = "女儿的请求:" + request;
                      break;
                  case 2:
                      this.request = "妻子的请求:" + request;
                      break;
                  case 3:
                      this.request = "母亲的请求:" + request;
                      break;
          
                  }
              }
          
              /*
               * 1-未出嫁 2-出嫁 3-夫死
               */
              @Override
              public int getType() {
                  return this.type;
              }
          
              @Override
              public String getRequest() {
                  return this.request;
              }
          
          }
          
        • Handler

          package com.peng.zrl;
          
          /**
           * @author kungfu~peng
           * @data 2017年11月21日
           * @description
           */
          public abstract class Handler {
              public final static int FATHER_LEVEL_REQUEST = 1;
              public final static int HUSBAND_LEVEL_REQUEST = 2;
              public final static int SON_LEVEL_REQUEST = 3;
          
              // 能处理的级别
              private int level = 0;
          
              // 责任传递,下一个责任人是谁
              private Handler nextHandler;
          
              // 自己能处理那些请求
              public Handler(int level) {
                  this.level = level;
              }
          
              // 女性的要求,处理函数
              public final void HandleMessage(IWomen iwomen) {
                  if (iwomen.getType() == this.level) {
                      this.response(iwomen);// 自己处理请求
                  } else {
                      if (this.nextHandler != null) {
                          // 交给下一个处理者
                          this.nextHandler.HandleMessage(iwomen);
                      } else {
                          // 没后续人处理了,不用处理了
                          System.out.println("~~~~~~。。没地方请示,你自己决定吧!");
                      }
                  }
              }
          
              public void setNextHandler(Handler handler) {
                  this.nextHandler = handler;
              }
          
              // 有请示,回应
              protected abstract void response(IWomen iwomen);
          }
          
        • Father

          package com.peng.zrl;
          
          /**
           * @author kungfu~peng
           * @data 2017年11月21日
           * @description
           */
          public class Father extends Handler {
          
              public Father() {
                  super(Handler.FATHER_LEVEL_REQUEST);
              }
          
              @Override
              protected void response(IWomen iwomen) {
                  System.out.println("女儿向父亲请示:");
                  System.out.println(iwomen.getRequest());
                  System.out.println("父亲的回答是:同意!");
              }
          
          }
          
        • Husband

          package com.peng.zrl;
          
          /**
           * @author kungfu~peng
           * @data 2017年11月21日
           * @description
           */
          public class Husband extends Handler {
              public Husband() {
                  super(Handler.HUSBAND_LEVEL_REQUEST);
              }
          
              @Override
              protected void response(IWomen iwomen) {
                  System.out.println("妻子向丈夫请示:");
                  System.out.println(iwomen.getRequest());
                  System.out.println("丈夫的回答是:同意!");
              }
          }
          
        • Son

          package com.peng.zrl;
          
          /**
           * @author kungfu~peng
           * @data 2017年11月21日
           * @description
           */
          public class Son extends Handler {
          
              public Son() {
                  super(Handler.SON_LEVEL_REQUEST);
              }
          
              @Override
              protected void response(IWomen iwomen) {
                  System.out.println("母亲向儿子请示:");
                  System.out.println(iwomen.getRequest());
                  System.out.println("儿子的回答是:同意!");
              }
          }
          
        • Client

          package com.peng.zrl;
          
          import java.util.ArrayList;
          import java.util.Random;
          
          /**
           * @author kungfu~peng
           * @data 2017年11月21日
           * @description
           */
          public class Client {
              public static void main(String[] args) {
                  // 随机挑选几个女性
                  Random random = new Random();
                  ArrayList<IWomen> lists = new ArrayList<IWomen>();
                  for (int i = 0; i < 10; i++) {
                      lists.add(new Women(random.nextInt(4) + 1, "我要去逛街!!"));// 注意这里的随机数为[1,4]之间的整数,1,2,3可处理,4将自由处理
                  }
          
                  // 定义三个请示对象
                  Father man1 = new Father();
                  Husband man2 = new Husband();
                  Son man3 = new Son();
          
                  // 设置请示顺序
                  man1.setNextHandler(man2);
                  man2.setNextHandler(man3);
                  // 遍历
                  for (IWomen iWomen : lists) {
                      man1.HandleMessage(iWomen);
                      System.out.println("_____________________");
                      System.out.println("————————歇一会儿———————");
                      System.out.println("_____________________");
                  }
              }
          }
          
        • 结果(由于随机数,结果不唯一)
          妻子向丈夫请示:
          妻子的请求:我要去逛街!!
          丈夫的回答是:同意!
          _____________________
          ————————歇一会儿———————
          _____________________
          ~~~~~~。。没地方请示,你自己决定吧!
          _____________________
          ————————歇一会儿———————
          _____________________
          母亲向儿子请示:
          母亲的请求:我要去逛街!!
          儿子的回答是:同意!
          _____________________
          ————————歇一会儿———————
          _____________________
          ~~~~~~。。没地方请示,你自己决定吧!
          _____________________
          ————————歇一会儿———————
          _____________________
          母亲向儿子请示:
          母亲的请求:我要去逛街!!
          儿子的回答是:同意!
          _____________________
          ————————歇一会儿———————
          _____________________
          ~~~~~~。。没地方请示,你自己决定吧!
          _____________________
          ————————歇一会儿———————
          _____________________
          ~~~~~~。。没地方请示,你自己决定吧!
          _____________________
          ————————歇一会儿———————
          _____________________
          妻子向丈夫请示:
          妻子的请求:我要去逛街!!
          丈夫的回答是:同意!
          _____________________
          ————————歇一会儿———————
          _____________________
          ~~~~~~。。没地方请示,你自己决定吧!
          _____________________
          ————————歇一会儿———————
          _____________________
          妻子向丈夫请示:
          妻子的请求:我要去逛街!!
          丈夫的回答是:同意!
          _____________________
          ————————歇一会儿———————
          _____________________
          
        • 上述代码中,从父亲开始,匹配则进行处理,不匹配交给其丈夫;丈夫进行匹配,匹配则进行处理,不匹配交给其儿子;儿子进行匹配,匹配则进行处理,不匹配则自由处理;
        • 这里是确定有父亲,丈夫,儿子-----实际生活中,记得加判断是否已婚!!

责任链的定义

  • Avoid coupling the sender of a request to its receiver by gaving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.(使用多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系,将这些对象连接成一条链,并沿着这条链一直传递该请求,直到有对象处理它为止)
  • 重点在链上,在链上传递请求,返回相应的结果
  • 类图
  • 解释
    1. Level--处理级别
    2. Request封装请求
    3. Response封装结果
  • 代码

    • Handler

      package zrl2;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月21日
       * @description
       */
      public abstract class Handler {
          private Handler nextHandler;
      
          // 每个处理者必须对请求做出处理
          public final Response handleMessage(Request request) {
              Response response = null;
              // 判断自己的处理级别
              if (this.getHandlerLevel().equals(request.getRequestLevel())) {// 级别相同
                  response = this.echo(request);
              } else {// 级别不同,进行传递
                      // 判断是否有下一个传递者
                  if (null != this.nextHandler) {// 有下一个对象
                      response = this.nextHandler.echo(request);
                  } else {// 没有下一个对象,结束传递
                      // 没有适当的处理者,自行处理
                  }
              }
              return response;
          }
      
          // 设置下一个处理者
          public void setNextHandler(Handler handler) {
              this.nextHandler = handler;
          }
      
          protected abstract Response echo(Request request);
      
          // 处理级别
          public abstract Level getHandlerLevel();
      }
      
    • ConcreteHandler1

      package zrl2;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月21日
       * @description
       */
      public class ConcreteHandler1 extends Handler {
      
          //定义自己的处理逻辑
          @Override
          protected Response echo(Request request) {
              return null;
          }
      
          //定义自己的 处理级别
          @Override
          public Level getHandlerLevel() {
              return null;
          }
      
      }
      
    • ConcreteHandler2

          package zrl2;
      
          /**
           * @author kungfu~peng
           * @data 2017年11月21日
           * @description
           */
          public class ConcreteHandler2 extends Handler {
      
              //定义自己的处理逻辑
              @Override
              protected Response echo(Request request) {
                  return null;
              }
      
              //定义自己的 处理级别
              @Override
              public Level getHandlerLevel() {
                  return null;
              }
      
          }
      
    • ConcreteHandler3

      package zrl2;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月21日
       * @description
       */
      public class ConcreteHandler3 extends Handler {
      
          //定义自己的处理逻辑
          @Override
          protected Response echo(Request request) {
              return null;
          }
      
          //定义自己的 处理级别
          @Override
          public Level getHandlerLevel() {
              return null;
          }
      
      }
      
    • Level

      package zrl2;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月21日
       * @description
       */
      public class Level {
          // 请求级别
      }
      
    • Request

      package zrl2;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月21日
       * @description
       */
      public class Request {
          // 请求的等级
          public Level getRequestLevel() {
              return null;
          }
      }
      
    • Response

      package zrl2;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月21日
       * @description
       */
      public class Response {
          // 处理者返回的数据
      }
      
    • Client

      package zrl2;
      
      /**
       * @author kungfu~peng
       * @data 2017年11月21日
       * @description
       */
      public class Client {
          public static void main(String[] args) {
              // 声明所有的处理节点
              Handler h1 = new ConcreteHandler1();
              Handler h2 = new ConcreteHandler2();
              Handler h3 = new ConcreteHandler3();
              // 设置链的顺序
              h1.setNextHandler(h2);
              h2.setNextHandler(h3);
              // 提交请求,返回结果
              Response response = h1.handleMessage(new Request());
          }
      }
      
    • 抽象处理者的三个职责
      1. 请求处理--handleMessage
      2. 链的编排方法--setNextHandler
      3. 具体的处理任务方法echo和处理级别getHandlerLevel
    • 补充:一般会有一个封装类将责任模式进行封装,也就是代替Client类,直接返回链中的第一个处理者,具体链的设置不需要高层确定关系,这样可以简化高层模块的调用,减少模块间的耦合,提高系统的灵活性

责任链模式的应用

  • 责任链优点
    1. 将请求和处理分开--两者解耦,提高系统的灵活性
  • 责任链缺点
    1. 性能问题:每个请求都是从链头到链尾
    2. 调试不方便:采用了类似递归的方式,调用的时候逻辑可能比较复杂
  • 注意事项
    1. 责任链中的节点数量需要控制,避免出现超长的链的情况,一般的做法是在Handler中设置在一个最大节点数量,在setNext方法中判断是否已经超过其阈值,超过则不允许该链的建立,避免无意识的破坏系统性能

最佳实践

  • 结合模板方法,各个实现类只关注自己的业务逻辑就行了---符合单一职责原则
  • 责任链模式屏蔽了请求的处理过程,只要把请求发送给第一个处理者,最终返回一个结果,不用关心到底是谁来处理的--责任链模式的核心
  • 责任链模式可以作为一种补救模式--一个请求一个处理者的项目要发展,处理者的数量增加,这时候在第一个后面增加处理者,形成处理链,即形如责任链模式
  • 例如登录界面的普通用户和vip用户的具体处理过程【统一入口,责任链中判断任务的具体处理】

声明

  • 摘自秦小波《设计模式之禅》第2版;
  • 仅供学习,严禁商业用途;
  • 代码手写,没有经编译器编译,有个别错误,自行根据上下文改正。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乘风御浪云帆之上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值