责任链模式:Chain of Responsibility

简介

职责链是一种行为设计模式,容许你将请求沿着处理者链进行发送。收到请求后,每一个处理者都可对请求进行处理,或将其传递给链上的下个处理者。 java

在这种模式中,一般每一个接收者都包含对另外一个接收者的引用。若是一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推,直到有对象处理它为止(也可能没有),如此使得每一个接收者都有机会接收和处理请求。设计模式

对于调用者来讲,调用者只须要将请求发送到职责链上便可,无须关心请求的处理细节和请求的传递,因此责任链也将请求的发送者和处理者进行了解耦。缓存

场景举例

一个事件须要通过多个对象处理是一个挺常见的场景,譬如客服咨询流程,采购审批流程,请假流程,软件开发中的异常处理流程,过滤系统等各类各样的流程,能够考虑使用责任链模式来实现。 cookie

如图,假如你刚购置了一个新的硬件设备,可是链接上电脑并不能正确执行,因而你决定拨打技术支持电话。网络

首先你会听到自动回复器的机器合成语音,它提供了针对各类问题的九个经常使用解决方案,你按照提示操做,机器人将你转接到一位人工客服人员。dom

客服发现问题的技术性比较强,没法提供任何具体的解决方案。因而他将你转接到一位技术工程师。ide

最后,工程师告诉了你新硬件设备驱动程序的下载网址,以及操做步骤,你按照说明解决了问题,几经周折,终于大功告成。 函数

概念

  1. 处理者 Handler:声明了全部具体处理者的通用接口。该接口一般包含用于请求处理的方法,以及设置下一个处理者的方法。
  2. 基础处理者(Base Handler):一般状况下,该类中定义了一个保存对于下个处理者引用的成员变量。客户端可经过将处理者传递给下个处理者的构造函数或设定方法来建立链。该类还能够实现默认的处理行为:肯定下个处理者存在后再将请求传递给它。
  3. 具体处理者(Concrete Handlers):包含处理请求的实际代码。每一个处理者接收到请求后,都必须决定是否进行处理,以及是否沿着链传递请求。处理者一般是独立且不可变的,须要经过构造函数一次性地得到全部必要地数据。
  4. 客户端(Client)可根据程序逻辑一次性或者动态地生成链。值得注意的是,请求可发送给链上的任意一个处理者,而非必须是第一个处理者。

活学活用

以请假流程为例,通常公司普通员工的请假流程简化以下 ui

普通员工发起一个请假申请,当请假天数小于3天时主管便可审批;当请假天数大于3天时,须要提交给项目经理审批,但若请假天数大于7天,就要提交给总经理审批。

public interface Handler {
    /** * 处理请假 * * @param days 请假天数 * @return 是否批准 */
    boolean handleHoliday(int days);

    /** * 设置责任链的下一个处理者 * * @param h 下一个处理者 */
    void setNext(Handler h);
}

public class BaseHandler implements Handler {
    private Handler next;

    @Override
    public boolean handleHoliday(int days) {
        if (next != null) {
            return next.handleHoliday(days);
        } else {
            System.out.println("未批准");
            return false;
        }
    }

    @Override
    public void setNext(Handler h) {
        next = h;
    }
}

public class LeaderManager extends BaseHandler {
    @Override
    public boolean handleHoliday(int days) {
        if (days <= 3) {
            System.out.println("LeaderManager 批准");
            return true;
        } else {
            return super.handleHoliday(days);
        }
    }
}

public class ProjectManager extends BaseHandler {
    @Override
    public boolean handleHoliday(int days) {
        if (days <= 7) {
            System.out.println("ProjectManager 批准");
            return true;
        } else {
            return super.handleHoliday(days);
        }
    }
}

public class DeptManager extends BaseHandler {
    @Override
    public boolean handleHoliday(int days) {
        System.out.println("DeptManager 批准");
        return true;
    }
}

public class Client {
    public static void main(String[] args) {
        Handler leaderManager = new LeaderManager();
        Handler projectManager = new ProjectManager();
        Handler deptManager = new DeptManager();
        leaderManager.setNext(projectManager);
        projectManager.setNext(deptManager);
        leaderManager.handleHoliday(5);
    }
}

// Logcat:
// ProjectManager 批准
复制代码

真实例子

Android 事件传递机制this

  • 伪代码
public boolean dispatchTouchEvent(MotionEvent event){
    boolean consume = false;
    if (onInterceptTouchEvent(event)) {
        consume = onTouchEvent(event);
    } else {
        consume = child.dispatchTouchEvent(event);
    }
    return consume;
}
复制代码

使用场景

  • 当必须按顺序执行多个处理者时,可使用该模式。
    • 不管你以何种顺序将处理者链接成一条链,全部请求都会严格按照顺序经过链上的处理者。
  • 若是所需处理者及其顺序须要在运行时进行改变,也可使用职责链模式。
    • 调用者能够根据运行时环境,动态地插入和移除处理者,或者改变其顺序。

纯的与不纯的责任链模式

“一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,而是把责任推给下家。不容许出现某一个具体处理者对象在承担了一部分责任后又把责任向下传的状况。

在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的责任链模式里面,一个请求能够最终不被任何接收端对象所接收。

纯的责任链模式的实际例子很难找到,通常看到的例子均是不纯的责任链模式的实现。有些人认为不纯的责任链根本不是责任链模式,这也许是有道理的。可是在实际的系统里,纯的责任链很难找到。若是坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大意义了。 ”

优缺点

  • 优势
    • 可控的请求处理的顺序。
    • 单一职责原则:每一个处理者职责单一,而且对发起操做和执行操做的类进行了解耦。
    • 开闭原则:你能够在不更改现有代码的状况下在程序中新增处理者。
  • 缺点
    • 有可能出现请求不被任何处理者处理的状况;
    • 责任链创建不当,有可能出现死循环;

和其余设计模式比较

  • 常见组合
    • 责任链一般和组合模式结合使用。在这种状况下,父组件接收到请求后,能够将请求沿包含子组件的链一直传递至对象树的叶结点。 Android 中 View 及其时间传递机制正是如此;
  • 容易混淆
    • 责任链模式与命令模式
      • 责任链按照顺序将请求动态传递给一系列的潜在接收者,直至其中一名接收者对请求进行处理。
      • 命令模式在发送者和请求者之间创建单向链接。
    • 责任链和装饰模式
      • 装饰模式主要目的是给原对象增长新行为,责任链的主要目的是让多个处理者都有机会处理某个请求;
      • 责任链的管理者能够相互独立地执行一切操做,还能够随时中止传递请求;
      • 能够在遵循基本接口的状况下扩展对象的行为;
      • 装饰没法中断请求的传递。

项目中例子

  • Router?

  • OkHttp Interceptor

    • 在OkHttp的内部实现中,interceptors并不只仅是拦截器这么简单。实际上,OkHttp发送网络请求的一切核心功能,包括创建链接、发送请求、读取缓存等,都是经过interceptors来实现的,这些interceptors在运行的时候彼此协做,构成了一个interceptor chain。
/** * 项目中自定义的 Interceptor */
object DomainSwitchInterceptor : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        val requestDomain = request.url().host()
        val domainManager = DomainManagerFactory.getInstance().getDomainManagerByDomain(requestDomain)
        val currentDomain = domainManager?.pickHostWithoutSchema()
        if (currentDomain != null && requestDomain != currentDomain) {
            request = request.newBuilder()
                .url(request.url().newBuilder().host(currentDomain).build())
                .build()
        }
        return chain.proceed(request)
    }
}


/** * 将自定义 Interceptor 添加到 OkHttp * 最终添加到 OkHttpClient 静态内部类 Builder 的 final List<Interceptor> interceptors 中 */
object RetrofitRestClient {

    val defaultOkHttpClient: OkHttpClient by lazy {
        VolleyManager.getOkHttpClient()
            .newBuilder()
            .addInterceptor(RequestCommonParamsInterceptor)
            .addInterceptor(DomainSwitchInterceptor)
            .addInterceptor(RequestMonitorInterceptor)
            .dns(HttpDns)
            .build()
    }
}

/** * 全部请求都是从 OkHttp 的 RealCall 的 getResponseWithInterceptorChain() 方法开始 */
Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors()); // client.interceptors()包含了自定义的拦截器
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    // 将全部 Interceptor 放入 RealInterceptorChain 构造责任链
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }
  
  /** * OkHttp Interceptor */
public interface Interceptor {
  Response intercept(Chain chain) throws IOException;

  /** * 构建责任链的接口 */
  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    @Nullable Connection connection();

    Call call();

    int connectTimeoutMillis();

    Chain withConnectTimeout(int timeout, TimeUnit unit);

    int readTimeoutMillis();

    Chain withReadTimeout(int timeout, TimeUnit unit);

    int writeTimeoutMillis();

    Chain withWriteTimeout(int timeout, TimeUnit unit);
  }
}

/** * Chain 的实现类 RealInterceptorChain 的 proceed 方法 */
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    return response;
  }
复制代码

Article by Panxc

相关文章
相关标签/搜索