zoukankan      html  css  js  c++  java
  • 【设计模式(13)】行为型模式之责任链模式

    个人学习笔记分享,当前能力有限,请勿贬低,菜鸟互学,大佬绕道

    如有勘误,欢迎指出和讨论,本文后期也会进行修正和补充


    前言

    在我上个公司,如果需要请假一天,只需要获取组长同意就可以了,通知一下人事就溜;但是如果长于1天不超过3天,那么需要跟项目经理说明情况,获得允许,同样需要告知人事部;长于3天则需要获得部门经理的同意,再告知人事;

    也就是说,如果要请假我得先知道这些规则,并且知道所有领导的姓名和练习方式,小公司还好,大公司这可就麻烦了。

    很多公司采取的方式是跟自己的直属上司汇报即可,比如我报备给组长,组长如果没权限就继续上报给项目经理,项目经理没权限就上报给经理,最终我得到答复即可。

    当然其实这样如果责任分配不合理,很容易出现踢皮球的问题,比如前段时间出现的新闻,如何证明我爸是我爸?


    在开发中,拦截器也是如此处理,拦截器会按照规则拦截请求,并将其按照设定好的指责链传递,由每个节点决定转发给下一层或者直接拒绝掉。

    同理还有JS的冒泡机制,触发的事件会从最里层逐步往上冒泡,因此我们可以对于一个事件针对不同情况处理。


    责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

    在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了


    1.介绍

    使用目的:将请求发送者与接收者解耦,发送者不需要知道实际处理流程。

    主要解决:一个发送者有多个接受者时,耦合度较高,扩展起来会很麻烦,灵活度极低

    如何解决:在拦截类中设定下个接受者。

    实现方法:拦截的类实现统一接口,并指定下一个接受者,收到请求后先处理,再判断是否传给下个接受者

    应用实例:

    • JS中的事件冒泡
    • servlet的拦截器
    • AOP切面拦截器

    优点:

    • 请求的发送者和接收者解耦,耦合度较低
    • 发送者不知道责任链内部逻辑,只需要调用接口即可,简化了使用流程
    • 允许动态的修改职责的顺序和内容,也能动态的新增职责节点,灵活度高

    缺点:

    • 不能保证请求一定被接收
    • 设计不当时可能出现死循环,即链变成环
    • 责任链组装过程在客户端中完成,增加了客户端的复杂性,也提高了出错的可能性

    使用场景:

    • 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
    • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
    • 可动态指定一组对象处理请求。

    2.结构

    职责链模式主要包含以下角色

    • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
    • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
    • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

    image-20201030121957438

    • 所有的具体处理者都需要实现抽象处理者
    • 抽象处理者会持有下一个抽象处理者对象

    3.实现步骤

    1. 定义抽象处理者

      abstract class Handler {
          public static final int LEVEL_1 = 1;
          public static final int LEVEL_2 = 2;
          public static final int LEVEL_3 = 3;
      
          private Handler next;
          private int level;
      
          public Handler(int level, Handler next) {
              this.level = level;
              this.next = next;
          }
      
          //处理请求的方法
          public void handleRequest(int level, String arg) {
              if (this.level == level) {
                  handle(arg);
              } else {
                  if (null != next) {
                      next.handleRequest(level, arg);
                  } else {
                      System.out.println("no suitable handle");
                  }
              }
          }
      
          //处理者自身方法
          public abstract void handle(String arg);
      }
      

    核心是handleRequest(int level, String arg)方法,需要决定是自行处理,或者传递到下一个处理者,或者终止

    1. 定义具体处理者

      //具体处理者角色1
      class ConcreteHandler1 extends Handler {
          public ConcreteHandler1(int level, Handler next) {
              super(level, next);
          }
      
          @Override
          public void handle(String arg) {
              System.out.println("ConcreteHandler1 handled this request!" + arg);
          }
      }
      
      //具体处理者角色2
      class ConcreteHandler2 extends Handler {
          public ConcreteHandler2(int level, Handler next) {
              super(level, next);
          }
      
          @Override
          public void handle(String arg) {
              System.out.println("ConcreteHandler2 handled this request!" + arg);
          }
      }
      
      //具体处理者角色2
      class ConcreteHandler3 extends Handler {
          public ConcreteHandler3(int level, Handler next) {
              super(level, next);
          }
      
          @Override
          public void handle(String arg) {
              System.out.println("ConcreteHandler3 handled this request!" + arg);
          }
      }
      
    2. 客户端组装责任链

      public static Handler getChain() {
          Handler concreteHandler1 = new ConcreteHandler1(1, null);
          Handler concreteHandler2 = new ConcreteHandler2(2, concreteHandler1);
          Handler concreteHandler3 = new ConcreteHandler3(3, concreteHandler2);
          return concreteHandler3;
      }
      

    完整代码

    package com.company.test.chainPattern;
    
    //抽象处理者角色
    abstract class Handler {
        public static final int LEVEL_1 = 1;
        public static final int LEVEL_2 = 2;
        public static final int LEVEL_3 = 3;
    
        private Handler next;
        private int level;
    
        public Handler(int level, Handler next) {
            this.level = level;
            this.next = next;
        }
    
        //处理请求的方法
        public void handleRequest(int level, String arg) {
            if (this.level == level) {
                handle(arg);
            } else {
                if (null != next) {
                    next.handleRequest(level, arg);
                } else {
                    System.out.println("no suitable handle");
                }
            }
        }
    
        //处理者自身方法
        public abstract void handle(String arg);
    }
    
    //具体处理者角色1
    class ConcreteHandler1 extends Handler {
        public ConcreteHandler1(int level, Handler next) {
            super(level, next);
        }
    
        @Override
        public void handle(String arg) {
            System.out.println("ConcreteHandler1 handled this request!" + arg);
        }
    }
    
    //具体处理者角色2
    class ConcreteHandler2 extends Handler {
        public ConcreteHandler2(int level, Handler next) {
            super(level, next);
        }
    
        @Override
        public void handle(String arg) {
            System.out.println("ConcreteHandler2 handled this request!" + arg);
        }
    }
    
    //具体处理者角色2
    class ConcreteHandler3 extends Handler {
        public ConcreteHandler3(int level, Handler next) {
            super(level, next);
        }
    
        @Override
        public void handle(String arg) {
            System.out.println("ConcreteHandler3 handled this request!" + arg);
        }
    }
    
    public class ChainPatternDemo {
        public static Handler getChain() {
            Handler concreteHandler1 = new ConcreteHandler1(1, null);
            Handler concreteHandler2 = new ConcreteHandler2(2, concreteHandler1);
            Handler concreteHandler3 = new ConcreteHandler3(3, concreteHandler2);
            return concreteHandler3;
        }
    
        public static void main(String[] args) {
            Handler handler = getChain();
    
            System.out.println("--------------------------- handle request level 1 ------------------------------");
            handler.handleRequest(Handler.LEVEL_1, " test round 1");
            System.out.println("--------------------------- handle request level 2 ------------------------------");
            handler.handleRequest(Handler.LEVEL_2, " test round 2");
            System.out.println("--------------------------- handle request level 3 ------------------------------");
            handler.handleRequest(Handler.LEVEL_3, " test round 3");
        }
    }
    

    运行结果

    image-20201030140622194

    4.示例

    模拟请假审批

    • 组长可审批1天以内请假
    • 项目经理可以审批3天以内请假
    • 部门经理可以审批7天以内请假
    package com.company.test.chainPattern;
    
    //抽象处理者角色
    abstract class LeaveHandler {
        public static final int DURATION_LEADER = 1;
        public static final int DURATION_PROJECT_MANAGER = 3;
        public static final int DURATION_DIVISION_MANAGER = 7;
    
        private LeaveHandler next;
        protected int days;
    
        public LeaveHandler(LeaveHandler next) {
            this.next = next;
        }
    
        //处理请求的方法
        public void handleRequest(int days, String arg) {
            if (days <= this.days) {
                handle(arg);
            } else {
                if (null != next) {
                    next.handleRequest(days, arg);
                } else {
                    System.out.println("无人受理请假申请!" + arg);
                }
            }
        }
    
        //处理者自身方法
        public abstract void handle(String arg);
    }
    
    //具体处理者角色1
    class LeaderHandler extends LeaveHandler {
        public LeaderHandler(LeaveHandler next) {
            super(next);
            this.days = LeaveHandler.DURATION_LEADER;
        }
    
        @Override
        public void handle(String arg) {
            System.out.println("Leader approved this request!" + arg);
        }
    }
    
    //具体处理者角色2
    class GroupManagerHandler extends LeaveHandler {
        public GroupManagerHandler(LeaveHandler next) {
            super(next);
            this.days = LeaveHandler.DURATION_PROJECT_MANAGER;
        }
    
        @Override
        public void handle(String arg) {
            System.out.println("Group manager approved this request!" + arg);
        }
    }
    
    //具体处理者角色2
    class DivisionManagerHandler extends LeaveHandler {
        public DivisionManagerHandler(LeaveHandler next) {
            super(next);
            this.days = LeaveHandler.DURATION_DIVISION_MANAGER;
        }
    
        @Override
        public void handle(String arg) {
            System.out.println("Division manager approved this request!" + arg);
        }
    }
    
    public class ChainPatternDemo2 {
        public static LeaveHandler getChain() {
            LeaveHandler divisionManagerHandler = new DivisionManagerHandler(null);
            LeaveHandler groupManagerHandler = new GroupManagerHandler(divisionManagerHandler);
            LeaveHandler leaderHandler = new LeaderHandler(groupManagerHandler);
            return leaderHandler;
        }
    
        public static void main(String[] args) {
            LeaveHandler handler = getChain();
    
            handler.handleRequest(1, " 请假1天");
            handler.handleRequest(2, " 请假2天");
            handler.handleRequest(3, " 请假3天");
            handler.handleRequest(10, " 请假10天");
        }
    }
    

    image-20201030173651638

    后记

    责任链模式将组装交给了客户端去处理,一方面提高了自由度,另一方面也提高了出错的可能性,比如自我嵌套会出现死循环,需要在组装责任链的时候谨慎操作。。。


    作者:Echo_Ye

    WX:Echo_YeZ

    Email :echo_yezi@qq.com

    个人站点:在搭了在搭了。。。(右键 - 新建文件夹)

  • 相关阅读:
    线程的五种状态
    ajax回调打开新窗体防止浏览器拦截有效方法
    mysql 如果字段为null自动返回需要的信息sql
    String 与 StringBuffer的区别
    Windows Git中文文件名乱码
    定义函数指针
    hello world
    C++析构函数调用异常问题研究
    企业开发的时候,有可能碰到的问题
    jmap
  • 原文地址:https://www.cnblogs.com/silent-bug/p/13903653.html
Copyright © 2011-2022 走看看