责任链模式


定义

什么是责任链模式?生活中我们经常遇到这样的问题,比如请假审批需要层层上报处理、遇到问题各个部门甩赖扯皮,像这种,在事情没有被处理之前,会经过一系列阶段,类似于“踢皮球”似的。同样地,当一个请求到达时,在程序无法直接决定由哪个对象负责处理时,客户的请求就会形成一种链式传递,在链上的各个处理对象如果无法直接决定是否由其处理时,就会将请求再传递至下一个链对象,直到请求被处理或者被丢弃等等。这种处理链我们形象称其为“责任链”。

责任链模式的定义是:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

使用实例

举个例子,初级、中级、高级开发工程师分别处理问题的能力不同,我们假设初级工程师只能处理难度级别为 1 的问题,中级工程师能处理难度为 1、2 的问题,高级工程师能处理难度级别为 1、2、3 的问题,另外我们有一个 Request 请求代表要处理的请求,内部包含一个难度级别和要请求的内容,我们先来看下类图的设计:

首先我们先定义一个请求接口:

interface IRequest {
    // 获取请求级别
    int getRequestLevel();

    // 获取要请求的内容
    String getRequest();
}

该接口包括一个难度级别和要请求的内容,这就是我们需要链式处理的请求,链上的处理对象根据请求难度级别获取请求内容选择是否进行处理,接下来是 IRequest 的实现类:

public class Request implements IRequest {
    /**
     * 难度级别1--初级工程师解决
     * 难度级别2--中级工程师解决
     * 难度级别3--高级工程师解决
     */
    private int level;
    // 要请求的内容或要解决的问题
    private String request = "";

    Request(int _level, String _request) {
        this.level = _level;
        switch (this.level) {
            case 1:
                this.request = "难度级别为1的请求是:" + _request;
                break;
            case 2:
                this.request = "难度级别为2的请求是:" + _request;
                break;
            case 3:
                this.request = "难度级别为3的请求是:" + _request;
                break;
        }
    }

    @Override
    public int getRequestLevel() {
        return this.level;
    }

    @Override
    public String getRequest() {
        return this.request;
    }
}

实现类比较简单,类中的难度级别和请求内容从构造中传入,接下来是我们的核心类 Handler 抽象类:

public abstract class Handler {
    final static int Difficulty_LEVEL_1_REQUEST = 1; // 难度级别为1
    final static int Difficulty_LEVEL_2_REQUEST = 2; // 难度级别为2
    final static int Difficulty_LEVEL_3_REQUEST = 3; // 难度级别为3
    // 能处理的级别
    private int level = 0;
    // 责任传递,下一个责任人是谁
    private Handler nextHandler;

    // 每个类都要说明一下自己能处理哪些请求
    Handler(int level) {
        this.level = level;
    }

    // 负责Request的请求处理,final关键字声明不允许被子类覆盖
    final void HandleMessage(IRequest request) {
        // 如果请求级别小于可以处理的级别就直接处理,比如:高级工程师也可以处理难度级别为1的请求
        if (request.getRequestLevel() <= this.level) {
            this.response(request);
        } else {
            if (this.nextHandler != null) { // 有后续环节,请求传递
                this.nextHandler.HandleMessage(request);
            } else { // 无后续环节了,按照不同意处理
                System.out.println("--------难度级别为" + request.getRequestLevel() + "的请求-------");
                System.out.println("---抱歉,没有工程师可以处理---\n");
            }
        }
    }

    /*
     * 如果不属于你处理的请求,你应该让请求路由到下一个环节的责任人
     */
    void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    // 有请示那当然要回应
    protected abstract void response(IRequest request);
}

Handler 类是链中对象的抽象类,链上的所有的责任对象都需要继承该对象,我们定义 HandleMessage 方法来进行请求的链式处理,可以看到:如果请求的难度级别不高于链对象可处理的难度级别时,由链对象直接负责处理,也就实现了前面讲到的高级工程师也可以处理难度级别为1的初级问题;如果请求难度级别过高超出可处理级别则请求继续向下传递,直至没有责任人可以处理为止,这就是责任链模式的核心。最后是 Handler 类的三个具体实现类,分别代表三个责任人对象:初级工程师、中级工程师及高级工程师,来看下怎么写的:

// 初级难度的责任人
class Primary extends Handler {
    // 初级工程师可以处理难度等级为1的请求
    Primary() {
        super(Handler.Difficulty_LEVEL_1_REQUEST);
    }

    // 处理结果
    @Override
    protected void response(IRequest request) {
        System.out.println("--------难度级别为1的请求-------");
        System.out.println(request.getRequest());
        System.out.println("初级工程师处理结果: 已处理\n");
    }
}

class Middle extends Handler {
    // 中级工程师可以处理难度等级为2的请求
    Middle() {
        super(Handler.Difficulty_LEVEL_2_REQUEST);
    }

    // 处理结果
    @Override
    protected void response(IRequest request) {
        System.out.println("--------难度级别为2的请求-------");
        System.out.println(request.getRequest());
        System.out.println("中级工程师处理结果: 已处理\n");
    }
}

class Senior extends Handler {
    // 高级工程师可以处理难度级别为3的请求
    Senior() {
        super(Handler.Difficulty_LEVEL_3_REQUEST);
    }

    // 处理结果
    @Override
    protected void response(IRequest request) {
        System.out.println("--------难度级别为3的请求-------");
        System.out.println(request.getRequest());
        System.out.println("高级工程师处理结果: 已处理\n");
    }
}

这里,我们定义四个难度级别不同的请求,请求进入处理链后,各个责任对象就会根据难度级别选择处理,直至不能处理为止,测试结果输出如下:

--------难度级别为1的请求-------
难度级别为1的请求是:1+1=?
初级工程师处理结果: 已处理

--------难度级别为2的请求-------
难度级别为2的请求是:3*4=?
中级工程师处理结果: 已处理

--------难度级别为3的请求-------
难度级别为3的请求是:87834*765=?
高级工程师处理结果: 已处理

--------难度级别为4的请求-------
---抱歉,没有工程师可以处理---

可以看到,对于难度级别不同的请求,责任链上各个对象可以根据难度级别自行处理,对于不能处理的级别,也可以按照预期正常响应,责任链模式的魅力就在于此:_客户端不需要关心请求被谁处理,链上的各个责任人会根据预先设定的链的顺序依次处理,直至不能处理为止。_

组成角色

通过上面的实例,想必我们已经了解了什么是责任链模式,责任链模式的通用类图如下:

责任链模式的核心就是 Handler 链抽象对象,该对象包含一个指向下一个链对象的私有属性,“链”是责任链的核心,就是使用该属性进行链式调用实现的。责任链模式的包含的角色如下:

  • 请求者(Client):Client 角色就是向链发送请求的角色,在上面的例子中,Main 函数扮演这个角色;
  • 责任人的抽象类角色(Handler):Handler 角色是模式的核心,Handler 知道下一个责任人是谁,并根据责任人的处理能力选择是否将请求转发至下一个责任人。上面例子中,由 Handler 类扮演该角色;
  • 具体责任人对象(ConcreteHandler):该角色是具体处理请求的对象,上面例子中,由 Primary、Middle、Senior 类扮演。

总结

本节介绍了责任链模式的概念、示例,责任链模式很好的降低了请求者和处理者的耦合度,弱化了前后关系,使得请求者不必关心请求真正是被哪个环节的哪个责任人处理,另外责任链模式下,链的调用顺序也是可控的,这也很好的实现了有序性。

责任人链模式的链式调用,有个非常明显的缺点就是:每个请求可能都是从头到尾走一遍,特别是调用链比较长时,这就加剧了系统的响应时间及导致调试的复杂性。


Author: Re:0
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Re:0 !
 Previous
工厂模式 工厂模式
定义工厂模式,是设计模式中最为常见的模式之一。属于创建型模式,提供创建对象的最佳方式。 工厂模式,顾名思义,一个模型,用来大规模的生产同类产品。该模式将对象的具体实例过程抽象化,并不关心具体的创建过程。通常,工厂模式被用来定义一个对象模型,
2022-03-07
Next 
外观模式(门面模式) 外观模式(门面模式)
定义本小节我们要学习的设计模式叫做外观模式,也叫做门面模式 Facade。想象一下,我们系统随着时间的推移,系统复杂性、类之间的相互调用会变得越来越多,相比较客户角度而言,客户往往关注的是某个单一接口 API,而不会关心该 API 内部的复
2022-03-05
  TOC