责任链

211 阅读6分钟

责任链是由很多责任节点串联起来的一条任务链条,其中每一个责任节点都是一个业务处理环节。责任链模式(Chain of Responsibility)允许业务请求者将责任链视为一个整体并对其发起请求,而不必关心链条内部具体的业务逻辑与流程走向,也就是说,请求者不必关心具体是哪个节点起了作用,总之业务最终能得到相应的处理。在软件系统中,当一个业务需要经历一系列业务对象去处理时,我们可以把这些业务对象串联起来成为一条业务责任链,请求者可以直接通过访问业务责任链来完成业务的处理,最终实现请求者与响应者的解耦。

工作流程拆分

报销审批流程。公司为了更高效、安全规范地把控审核工作,通常会将整个审批工作过程按负责人或者工作职责进行拆分,并组织好各个环节中的逻辑关系及走向,最终形成标准化的审批流程

审批流程需要依次通过财务专员、财务经理、财务总监的审批。如果申请金额在审批人的审批职权范围内则审批通过并终止流程,反之则会升级至更高层级的上级去继续审批,直至最终的财务总监,如果仍旧超出财务总监的审批金额则驳回申请,流程终止

我们思考一下该如何设计这个审批流程,如果将业务逻辑写在一个类中去完成,还不至于太烦琐,但是如果需要进一步修改审批流程,我们就必须不断地更改这段逻辑代码,导致可扩展性、可维护性变差,完全谈不上任何设计。因此,我们有必要首先按角色对业务进行拆分,将不同的业务代码放在不同的角色类中,如此达到职权分拆的目的,可维护性也能得到提高。

架构工作流

缺少架构的流程不是完备的工作流,否则申请人终将被淹没在一堆复杂的审批流程中。

我们可以发现审批人的业务之间有环环相扣的关联,对于超出审批人职权范围的申请会传递给上级,直到解决问题为止。这种传递机制就需要我们搭建一个链式结构的工作流,这也是责任链模式的精髓之所在。

审批人Approver

package Chain_Responsibility;

public abstract class Approver {
   protected String name;//抽象出审批人的姓名
   protected Approver nextApprover;//下一位审批人

   public Approver(String name){
      this.name = name;
   }

   protected Approver setNextApprover(Approver nextApprover){
      this.nextApprover = nextApprover;
      return this.nextApprover;//返回下一位审批人,使其支持链式编程
   }
   
   public abstract void approve(int amount);//抽象审批方法由具体审批人子类实现
}

我们用抽象类来定义审批人。由于审批人在无权审批时需要传递业务给其上级领导,因此我们在定义上级领导的引用nextApprover,与下一位审批人串联起来,同时将其注入。当然,每位审批人的角色不同,其审批逻辑也有所区别,所以我们在第15行对审批方法进行抽象,交由具体的子类审批角色去继承和实现。

财务专员类Staff

package Chain_Responsibility;

public class Staff extends Approver {
   public Staff(String name) {
      super(name);
   }

   @Override
   public void approve(int amount) {
      if (amount<=1000){
         System.out.println("审批通过");
      }else {
         System.out.println("无权审批,升级处理。[专员:"+name+"]");
         this.nextApprover.approve(amount);
      }
   }
}

财务经理类Manager

package Chain_Responsibility;

public class Manager extends Approver {
   public Manager(String name) {
      super(name);
   }

   @Override
   public void approve(int amount) {
      if (amount<=5000){
         System.out.println("审批通过。【经理:"+name+"】");
      }else {
         System.out.println("无权审批,升级处理。【经理:"+name+"】");
         this.nextApprover.approve(amount);
      }
   }
}

财务总监类CFO

package Chain_Responsibility;

public class CFO extends Approver {
   public CFO(String name) {
      super(name);
   }

   @Override
   public void approve(int amount) {
      if (amount<=10000){
         System.out.println("审批通过。【财务总监:"+name+"】");
      }else {
         System.out.println("驳回申请。【财务总监:"+name+"】");
      }
   }
}

客户端类Client

package Chain_Responsibility;

public class Client {
   public static void main(String[] args) {
      Approver flightJohn = new Staff("张飞");
      flightJohn.setNextApprover(new Manager("关羽")).setNextApprover(new CFO("刘备"));
      flightJohn.approve(1000);
      flightJohn.approve(4000);
      flightJohn.approve(9000);
      flightJohn.approve(88000);
   }
}

总结

至此,以责任链模式为基础架构的工作流搭建完成,各审批角色只需要定义其职权范围内的工作,再依靠高层抽象实现角色责任的链式结构,审批逻辑得以拆分、串联,让业务申请在责任链上逐级传递。如此一来,申请人再也不必关心业务处理细节与结果了,彻底将工作流或业务逻辑抛开,轻松地将申请递交给责任链入口即可得到最终结果。下面我们来看责任链模式的类结构

Handler(业务处理者):所有业务处理节点的顶层抽象,定义了抽象业务处理方法handle()并留给子类实现,其实体方法setSuccessor()(注入继任者)则用于责任链的构建。对应本章例程中的审批人Approver。

ConcreteHandler1、ConcreteHandler2……(业务处理者实现类):实际业务处理的实现类,可以有任意多个,每个都实现了handle()方法以处理自己职权范围内的业务,职权范围之外的事则传递给下一位继任者(另一个业务处理者)。对应本章例程中的财务专员类Staff、财务经理类Manager、财务总监类CFO。

Client(客户端):业务申请人,只需对业务链条的第一个入口节点发起请求即可得到最终响应。

责任链模式的本质是处理某种连续的工作流,并确保业务能够被传递至相应的责任节点上得到处理。当然,责任链也不一定是单一的链式结构,我们甚至可以让一位审批人将业务传递给多位审批人,或是加入更复杂的业务逻辑以完善工作流,最终使不同的业务有不同的传递方向。不管是何种形式的呈现,读者都要能够根据具体的业务场景,更灵活、恰当地运用责任链模式,而不是照本宣科、生搬硬套。

对责任链模式的应用让我们一劳永逸,之后我们便可以泰然自若地应对业务需求的变更,方便地对业务链条进行拆分、重组,以及对单独节点的增、删、改。结构松散的业务处理节点让系统具备更加灵活的可伸缩性、可扩展性。责任链模式让申请方与处理方解耦,申请人可以彻底从业务细节中解脱出来,无论多么复杂的审批流程,都只需要简单的等待,让业务在责任链上飞一会儿。

Go版本代码

package chainresponsibility

import "fmt"

type Handler interface {
    Approve(int)
}

type Apporver struct {
    Name string
    next Handler
}

func (a *Apporver) SetNextApprover(handler Handler) {
    a.next = handler
}

type Staff struct {
    Apporver
}

func (s *Staff) Approve(amount int) {
    if amount <= 1000 {
        fmt.Println("审批通过。【专员" + s.Name + "】")
    } else {
        fmt.Println("无权审批,升级处理。【专员:" + s.Name + "】")
        if s.next != nil {
            s.next.Approve(amount)
        }
    }
}

type Manager struct {
    Apporver
}

func (m *Manager) Approve(amount int) {
    if amount <= 5000 {
        fmt.Println("审批通过。【经理" + m.Name + "】")
    } else {
        fmt.Println("无权审批,升级处理。【经理" + m.Name + "】")
        m.next.Approve(amount)
    }
}

type CFO struct {
    Apporver
}

func (c *CFO) Approve(amount int) {
    if amount <= 10000 {
        fmt.Println("审批通过。【财务总监" + c.Name + "】")
    } else {
        fmt.Println("驳回申请。【财务总监:" + c.Name + "】")
    }
}
package main

import chainresponsibility "desginPatterns/chain_responsibility"

func main() {
    staff := &chainresponsibility.Staff{
        Apporver: chainresponsibility.Apporver{Name: "张飞"},
    }
    manager := &chainresponsibility.Manager{
        Apporver: chainresponsibility.Apporver{Name: "关羽"},
    }
    cfo := &chainresponsibility.CFO{
        Apporver: chainresponsibility.Apporver{Name: "刘备"},
    }
    staff.SetNextApprover(manager)
    manager.SetNextApprover(cfo)

    staff.Approve(1000)
    staff.Approve(4000)
    staff.Approve(9000)
    staff.Approve(88000)
}