拯救代码洪水:深入揭秘责任链模式的设计之道

2023-09-13 12:34:28 浏览数 (1)

将程序视点设为星标精品文章第一时间阅读

大家好,欢迎来到程序视点!我是小二哥。

今天和大家聊一聊软件设计中关系型模式的另一种强大模式:责任链模式(Chain of Responsibility)

简介

还是把这张概总图放这里。

责任链模式,是一种行为模式。先来看下它的定义。

避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

它描述的是请求发送者请求接受处理者之间的关系。

请求接受处理者不是一个对象,而是多个对象一起形成的链。

责任链模式,能够将多个对象组成一个链,并依次处理请求,直到有一个对象能够完全处理该请求为止。这里的每个对象被称为责任链的节点,每个节点都有两个基本操作处理请求将请求转发给下一个节点

示例

责任链模式是一种能够简化复杂逻辑处理的设计模式,常被用于处理请求、日志记录、异常捕获等场景。让我们一起来看看责任链模式是如何工作的,以及它为我们带来的便利。

让我们来看一看这个例子:请假条审批。

分析:假如规定请假小于或等于 2 天,主管可以批准;小于或等于 7 天,经理可以批准;小于或等于 10 天,总监可以批准;其他情况不予批准;

这个实例适合使用责任链模式实现。让我们一步一步的来看。

先准备好不同假期的批准对象。

主管准假

代码语言:javascript复制
public class SupervisorHandler {

    public boolean handler(int leaveDays){
      if(leaveDays <= 2) {
        System.out.println("小于或等于2-->主管准假!");
      }
      return leaveDays <= 2;
    }
}

经理准假

代码语言:javascript复制
public class ManagerHandler {

    public boolean handler(int leaveDays){
      if(leaveDays <= 7) {
        System.out.println("小于或等于7-->经理准假!");
      }
      return leaveDays <= 7;  
    }
}

总监准假

代码语言:javascript复制
public class DirectorHandler {

    public boolean handler(int leaveDays){
      if(leaveDays <= 10) {
        System.out.println("小于或等于10-->总监准假!");
      }
      return leaveDays <= 10;
    }
}

现在开始批假啦~

代码语言:javascript复制
public class HandlerClient {
    public static void main(String[] args) {

        SupervisorHandler supervisorHandler = new SupervisorHandler();//主管
        ManagerHandler managerHandler = new ManagerHandler();//经理
        DirectorHandler directorHandler = new DirectorHandler();//总监

        boolean isPermitted = supervisorHandler.handler();
        //主管批不了,才到经理批
        if(!isPermitted){
            isPermitted = managerHandler.handler();
            //经理批不了,才到总监批
            if(!isPermitted){
                isPermitted =directorHandler.handler();
                //总监批不了,那回去歇着~没法批了
                if(!isPermitted){
                  System.out.println("批不了~");
                }
            }
        }
    }
}

乍一看~代码执行也没有任何问题。但是这段代码扩展性非常不好,有很大的问题。问题主要如下:

1.假如现在要增加几个审批条件:小于或等于 15 天,CEO可以准假;小于或等于 30 天,总裁准假...随着条件增多,if条件的嵌套就增加啦~这样的代码非常糟糕!

2.上面准假的流程是我们来控制的,也就是每一步和下一步的审批逻辑是程序员自己来控制的。这里只有三、五个步骤,还比较好办。假如有10个审批步骤,现在要裁撤第3、第5、第6步骤,代码修改起来就非常麻烦--你必须修改整个流程。

如何接却上面的问题?在前面的简介中,我们说过: 每个对象被称为责任链的节点,每个节点都有两个基本操作处理请求将请求转发给下一个节点

我们之前只做了处理请求的操作,没有将请求转发给下一个节点的操作。补上就可以啦~

将请求转发给下一个节点,就是让每一个步骤都知道自己的下一个步骤是谁来处理!这样就形成了一条链--责任链的链呀!

修改如下:每一级领导在批假的时候,如果无权处理就将假条交给下一位具体处理者,直到最后;那就是每一级都需要知道自己的下一级。主管准假修改

代码语言:javascript复制
public class SupervisorHandler {
    private ManagerHandler next;
    public void setNext(ManagerHandler next)
    {
        this.next=next; 
    }
    public ManagerHandler getNext()
    { 
        return next; 
    } 
    public boolean handler(int leaveDays){
      if(leaveDays <= 2) {
        System.out.println("小于或等于2-->主管准假!");
      }
      return leaveDays <= 2;
    }
}

注意这里一个问题:SupervisorHandler 的下一级是 ManagerHandler,那 ManagerHandler 的下一级是 DirectorHandler,总不能每一级的下一级都用不同的类型吧?它们都是处理请假的!我们要抽象出来!

抽象出批假处理类--一个领导类,每一级具体的批假类都实现它

代码语言:javascript复制
abstract class LeaderHander
{
    private LeaderHander next;
    public void setNext(LeaderHander next)
    {
        this.next=next; 
    }
    public LeaderHander getNext()
    { 
        return next; 
    }   
    //处理请求的方法
    public abstract void handler(int LeaveDays);       
}

ps:我们这里的 hander 方法不用有返回值,因为我们的判断逻辑放在批假类内部了,不需要在外部用 true or false 来判断往不往下一级走,而是在链上的每一级自己决定往不往下一步走!

主管最终修改类

代码语言:javascript复制
public class SupervisorHandler extends LeaderHander {
    public void handler(int leaveDays){
      if(leaveDays <= 2) {
        System.out.println("主管准假"   leaveDays   "天!");
      } else {
      if(getNext() != null) {
            getNext().handler(leaveDays);             
        }else{
              System.out.println("请假天数太多,没有人批准该假条!");
        }
    } 
  }
}

经理最终修改类

代码语言:javascript复制
public class ManagerHandler extends LeaderHander {
  public boolean handler(int leaveDays){
    if(leaveDays <= 7) {
      System.out.println("经理准假"   leaveDays   "天!");
    } else {
      if(getNext() != null) {
            getNext().handler(leaveDays);             
        }else{
              System.out.println("请假天数太多,没有人批准该假条!");
        }
    } 
  }
}

总监最终修改类

代码语言:javascript复制
public class DirectorHandler extends LeaderHander {
  public boolean handler(int leaveDays){
    if(leaveDays <= 10) {
      System.out.println("总监准假"   leaveDays   "天!");
    } else {
      if(getNext() != null) {
            getNext().handler(leaveDays);             
        }else{
              System.out.println("请假天数太多,没有人批准该假条!");
        }
    } 
  }
}

现在再来测试下:

代码语言:javascript复制
public class LeaveApprovalTest{
  public static void main(String[] args){
    //组装责任链 
    LeaderHander supervisorHandler=new SupervisorHandler();
    LeaderHander managerHandler=new ManagerHandler();
    LeaderHander directorHandler=new DirectorHandler();

    supervisorHandler.setNext(managerHandler);
    managerHandler.setNext(directorHandler);

    //处理请假审批 
    teacher1.handleRequest(8);
  }
}

ps:我们组装了一个责任链:supervisorHandler --》managerHandler --》 directorHandler,然后把要处理的请求给到链上任意节点即可!最重要的是,我们处理请假审批时,再也没有 if 条件嵌套啦!

现在我们增加一个CEO准假类:

代码语言:javascript复制
public class CEOHandler extends LeaderHander {
  public boolean handler(int leaveDays){
    if(leaveDays <= 10) {
      System.out.println("CEO准假"   leaveDays   "天!");
    } else {
      if(getNext() != null) {
            getNext().handler(leaveDays);             
        }else{
              System.out.println("请假天数太多,没有人批准该假条!");
        }
    } 
  }
}

要使用这个类,把它加到链上去就可以啦!

代码语言:javascript复制
LeaderHander ceoHandler=new CEOHandler();
directorHandler.setNext(ceoHandler);

每个节点都准备好了,这个责任链想怎么串就怎么串!扩展性好多啦~

小结

责任链模式的好处在于,它将条件判断的逻辑分散到了各个节点中,使得代码更加清晰、可扩展和易于维护。非常适用于需要按照一定规则依次处理请求的场景。

来看下责任链模式的优缺点:

优点

  • 降低了对象之间的耦合度。 该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
  • 增强了给对象指派职责的灵活性。 当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
  • 责任链简化了对象之间的连接。 每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
  • 责任分担。 每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

主要缺点

  • 不能保证每个请求一定被处理。 由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
  • 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  • 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

好了,最后希望通过这篇能让你对责任链模式有个初步的了解,并在实际开发中灵活应用。如果您有任何问题或意见,请随时留言讨论。谢谢!

0 人点赞