责任链模式

111 阅读6分钟

这篇文章我们讲一下“责任链模式”。

责任链模式的概念

首先我们确定一个事情,责任链模式是一种“行为型模式”。

它存在的意义就是允许我们将请求沿着处理者链进行发送。

处理者们收到请求后,每个处理者均可对请求进行处理,或者不处理而直接将其传递给这条链上的下个处理者去处理。同理,下个处理者也可以依照其内部的逻辑进行处理或向后传递,以此类推。

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

责任链模式的优缺点

责任链的优点如下:

  1. 责任链模式可以降低对象之间的耦合度,请求发送者和接受者不用耦合在一起。
  2. 责任链模式可以让一个对象不用知道到底是哪一个对象处理其请求的,也不用知道链的结构是什么;发送者和接收者也不用知道对方的明确信息。
  3. 责任链模式可以增强系统的扩展性。我们在开发中,可以根据需要,在这个链中增加新的请求处理类,这样是满足开闭原则的。
  4. 责任链模式可以增强给对象指派职责的灵活性。加入工作流程有了变化,那么就可以动态地改变链内的成员:可以新增、删除、改变顺序等。
  5. 责任链模式简化了处理对象之间的连接关系。每个对象只需保持一个指向其后继者的引用,不需关心其他处理者,这样就避免了使用众多的if else 判断。
  6. 责任链模式的处理链中的每个类只需要处理自己该处理的工作,如果不该处理,那么就将请求传递给下一个对象完成,各个类的职责很明确,符合单一职责原则。

责任链模式对应的缺点如下:

  1. 责任链模式不能保证每个请求一定被处理。因为接受请求的是由众多对象组成的一个链,所以就没有明确的接收者,以至于不能保证这个请求一定会被处理,结果就是请求可能一直传到链的末端都得不到处理。
  2. 对于比较长的责任链,一个请求的处理可能涉及多个处理对象,在流转的过程中,系统性能将受到一定影响。
  3. 责任链建立的合理性要根据需求来定,也就是需要靠客户端的要求来保证,增加了客户端的复杂性,可能会由于责任链的错误设置而导致系统出错,稍有不当也可能导致循环调用的情况出现。

在责任链模式中,责任链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。对于每个处理者,除了处理请求外,它们还负责沿着链传递请求。请求会在链上移动,直至所有处理者都对其进行处理。

另外,责任链中的某个处理者可以决定不再沿着链传递请求,这样就可直接取消所有后续处理步骤。

责任链模式的组成部分

首先我们来看责任链模式的类图:

image.png

我们可以看到,在责任链模式中只有两个角色

  • Handler:所有处理者类的接口
  • ConcreteHandler:具体的处理者类,实现Handler接口。有多少个处理者,就定义多少个这样的类。

在使用责任链模式的时候,我们需要着重思考的就是怎么将很多处理者对象连成一条链。我们通过代码来实际操作一下。

这里我们举例,某公司的报销流程,是首先需要自己提交申请,然后小组leader 审批,然后部门主管审批,然后hr 审批,最后到CEO 审批。

这一套流程就很适合使用责任链模式:在处理流程中,如果请求流转下去,需要所有处理者都参与处理,同时如果其中参与处理的某个处理者拒绝审批,那么就不用再将请求向下传递了。我们来看一下代码实现:

第一步

声明一个所有处理者都要实现的接口:

public interface PaymentHandler {

    void setNextHandler(PaymentHandler paymentHandler);

    boolean handle(Sting name, int amount);
}

在这个接口中,setNextHandler 方法就是用来设置下一个处理者的,也就是通过设置的这个处理者来讲请求向下传递。handle 方法就是用来处理请求的。

第二步

实现各个实际的处理者类。

首先是小组leader,内部逻辑就是如果觉得合适没问题就审批通过,然后将请求传递到后续处理者;如果觉得不合规,那么就可以直接拒绝,后续处理者就不用处理了,我们来看代码:

public class TeamLeaderPayment implements PaymentHandler {
    private PaymentHandler nextHandler;

    @Override
    public void setNextHandler(BudgetHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    @Override
    public boolean handle(String name, int amount) {
        Objects.requireNonNull(nextHandler);
        // 如果判断报销合理
        if (isLagal(amount)) {
            System.out.println(name + "的审批通过,流转到后续审批");
            return nextHandler.handle(name, amount);
        } else {
            return false;
        }
    }
}

后续的主管、hr、CEO 的实现都是类似或者说是相同的,这里就不一一列举了。(除了最后一级CEO 审批不需要再传入后续处理者)

这里我们约定它们对应的处理类分别为ManagerPaymentHRPaymentCEOPayment

第三步

客户端调用。

各个处理者类已经完成了声明,接下来就是需要在客户端调用中完成责任链的搭建:

public class DogWang2Cor {
    public void applyBudget() {
        GroupLeader leader = new GroupLeader();
        Manager manager = new Manager();
        CFO cfo = new CFO();

        leader.setNextHandler(manager);
        manager.setNextHandler(cfo);

        System.out.println(String.format("领导您好:由于开发需求,需要购买一台Mac笔记本电脑,预算为%d 望领导批准", 95000));
        if (leader.handle(95000)) {
            System.out.println("谢谢领导");
        } else {
            System.out.println("巧妇难为无米之炊,只能划船了...");
        }
    }
}

public static void main(String[] args) {
    // 实例化几个审批处理者
    TeamLeaderPayment teamLeaderPayment = new TeamLeaderPayment();
    ManagerPayment managerPayment = new ManagerPayment();
    HRPayment hrPayment = new HRPayment();
    CEOPayment ceoPayment = new CEOPayment();
    // 为几个处理者设置后续处理者
    teamLeaderPayment.setNextHandler(managerPayment);
    managerPayment.setNextHandler(hrPayment);
    hrPayment.setNextHandler(ceoPayment);
    
    if (teamLeaderPayment.handle("xiaoming", 200)) {
        System.out.println("审批成功");
    } else {
        System.out.println("审批失败");
    }
}

总结

通过上面的实现代码相信读者已经可以对“责任链模式”有一个清晰的认识了,责任链模式的实现其实并不困难,应用场景也比较直观。但是假如我们不知道这个模式的设计方法,可能在需求实现的过程中就会比较费事。所以说,多学习,多积累,说不定哪天这些知识就会派上用场。