【设计模式】Chain of Responsibility 责任链式模式

2023-11-12

一, 前言

责任链行为模式是行为模式的一种。

行为模式涉及到算法和对象间职责的分配,行为模式不仅描述对象或类的模式,还描述它们之间的通信模式。

行为模式分为 :Template Method 模板方法 和 Interpreter 解析器行为模式。

模板方法:
是一个算法的抽象定义,它逐步地定义该算法,每一步调用抽象操作或一个原语操作,子类定义抽象操作以具体实现该算法。

解析器模式:
将一个文法表示为一个类层次,并实现一个解析器作为这些类的实例上的一个操作。

行为对象模式使用对象复合,而不是继承。

二、责任链—对象行为模式

1. 意图

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

2. 动机

. 根据普遍性(generality)即从最特殊到最普遍的顺序组织信息。
. 该模式的思想是,给多个对象处理一个请求的机会,从而解耦发送者和接收者。
. 要沿链转发请求,并保证接收者为隐式的 (implicit),每个在链上的对象都有一致的处理请求和访问链上后继者的接口。

3. 适用性

. 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定;
. 想在不明确指定接收者的情况下, 向多个对象中的一个提交了一个请求;
. 可处理一个请求的对象集合应被动态指定。

4. 结构

这里写图片描述

Handler
. 定义一个处理请求的接口;
. (可选) 实现后继链;

ConcreteHandler 继承 Handler
. 处理它所负责的请求;
. 可访问它的后继者;
. 如果可处理该请求,就处理之;否则将该请求转发给它的后继者。

Client
. 向链上的具体处理者 (ConcreteHandler)对象提交请求。

5. 效果
优点

(1). 降低耦合度
该模式使得一个对象无需知道是其他哪一个对象一个指向其后继者的引用,而不需保持它所有的后选者的引用;
责任链可简化对象的相互连接。它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。

(2). 增强了给对象指派职责(Responsibility)的灵活性
可以通过在运行时刻对该链进行动态的增加或修改来增加改变处理一个请求的那些职责。

缺点

不能保证被接受
请求没有明确的接收者,该请求可能一直到链的末端都得不到处理;也可能因该链没有被正确配置而得不到处理。

6. 实现需要考虑的问题
(1). 抽象处理者 Handler

. 定义一个请求的处理方法, HandleMessage, 对外开放的方法;
. 定义链的编排方法 setNext, 设置下一个处理者;
. 定义具体的请求者必须实现的两个方法:自己能够处理的级别 getHandleLevel 和具体的处理任务 echo;

(2). 具体处理者 ConcreteHandler

. 定义自己的处理逻辑;
. 设置自己的处理级别;

(3). 在场景类或高层模块中对链进行组装,并传递请求,并返回结果

三. 实例代码

抽象处理者

/**
 *  抽象处理者
 * @author Administrator
 *
 */
public abstract class Handler {

    private Handler nextHandler;

    // 每个处理者都必须对请求做出处理
    public final Response handMessage(Request request){
        Response response = null;
        // 判断是否是自己的处理级别
        if (this.getHandlerLevel().equals(request.getRequestLevel())) {
            response = this.echo(request);
        } else {    // 不属于自己的处理级别
            if (nextHandler != null) {
                response = nextHandler.handMessage(request);
            } else {
                // 没有适当的处理者,业务自行处理
            }
        }

        return response;
    }

    /**
     *  设置下一个处理者是谁
     * @param handler
     */
    public void setNext(Handler handler){
        this.nextHandler = handler;
    }

    // 每个处理者都有一个处理级别
    protected abstract Level getHandlerLevel();
    // 每个处理者都必须实现处理任务
    protected abstract Response echo(Request request);
}

具体处理者

// 具体处理者
public class ConcreteHandler1 extends Handler{

    // 定义自己的处理逻辑
    @Override
    protected Level getHandlerLevel() {
        // 完成处理逻辑
        return null;
    }

    // 设置自己的处理级别
    @Override
    protected Response echo(Request request) {
        // 设置自己的处理级别
        return null;
    }

}

封装请求等信息

public class Request {
    // 请求等级
    public Level getRequestLevel(){
        return null;
    }
}
public class Level {
    // 定义一个请求和处理等级
}
public class Response {
    // 处理者返回的数据
}

场景类

/**
 *  场景类
 * @author Administrator
 *
 */
public class Client {
    public static void main(String[] args) {
        // 声明所有的处理节点
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        Handler handler3 = new ConcreteHandler3();

        // 设置链中的阶段顺序1-->> 2-->> 3
        handler1.setNext(handler2);
        handler2.setNext(handler3);
        // 提交请求,返回结果
        Response response = handler1.handMessage(new Request());
    }
}

上面这个例子是正规的责任链模式,在 Android 的源码中也有责任链式模式,在输入系统中,将输入事件传递到 ViewRootImpl 时,就用到了。

 // Set up the input pipeline.
                CharSequence counterSuffix = attrs.getTitle();
                mSyntheticInputStage = new SyntheticInputStage();
                InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
                InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
                        "aq:native-post-ime:" + counterSuffix);
                InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
                InputStage imeStage = new ImeInputStage(earlyPostImeStage,
                        "aq:ime:" + counterSuffix);
                InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
                InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
                        "aq:native-pre-ime:" + counterSuffix);

详情参考 【读书笔记】Android 输入系统 一文。

其实还有一种变异类型,在 OkHttp 源码中
抽象类

public interface  Interceptor {

    Response intercept(Chain chain) throws IOException;


    interface Chain{
        Request request();

        Response proceed(Request request) throws IOException;

    }
}

具体实现类

public class BridgeInterceptor implements Interceptor{

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request userRequest = chain.request();

        Response networkResponse = chain.proceed(userRequest);

        System.out.println("BridgeInterceptor intercept");

        return networkResponse;
    }

}
public class CacheInterceptor implements Interceptor{

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        Response response = chain.proceed(request);

        System.out.println("CacheInterceptor intercept");
        return response;
    }

}
public class ConnectInterceptor implements Interceptor{

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();

        Response response = new Response();

        System.out.println("ConnectInterceptor intercept");
        return response;
    }

}
public class RealInterceptorChain implements Interceptor.Chain{

    private final List<Interceptor> interceptors;
    private final int index;
    private final Request request;
    private int calls;

    public RealInterceptorChain(List<Interceptor> interceptors, int index, Request request) {
        this.interceptors = interceptors;
        this.index = index;
        this.request = request;
    }

    @Override
    public Request request() {
        return request;
    }

    @Override
    public Response proceed(Request request) throws IOException {
        if (index >= interceptors.size()) {
            throw new AssertionError();
        }

        calls++;

        // Call the next interceptor in the chain.
        RealInterceptorChain next = new RealInterceptorChain(interceptors, index + 1, request);
        Interceptor interceptor = interceptors.get(index);
        Response response = interceptor.intercept(next);

        // Confirm that the next interceptor made its required call to  chain.proceed().
        if (index + 1 < interceptors.size() && next.calls != 1) {
            throw new IllegalStateException("network interceptor " + interceptor
                    + " must call proceed() exactly once");
        }

        // Confirm that the intercepted response isn't null.
        if (response == null) {
            throw new NullPointerException("interceptor " + interceptor  + " returned null");
        }
        return response;
    }

}

场景类

public class TempClient {

    public static void main(String[] args) throws IOException {

        List<Interceptor> interceptors = new ArrayList<Interceptor>();
        interceptors.add(new BridgeInterceptor());
        interceptors.add(new CacheInterceptor());
        interceptors.add(new ConnectInterceptor());

        Request request = new Request();
        Interceptor.Chain chain = new RealInterceptorChain(interceptors, 0, request);
        chain.proceed(request);

        /**
         *  执行结果, 倒序
         *   ConnectInterceptor intercept
         *   CacheInterceptor intercept
         *   BridgeInterceptor intercept
         */
    }

}

注:1.本文综合《设计模式 可复用面向对象软件的基础》一书;
2. 《设计模式之禅》一书;
3. 上文中的的两个例子代码已放到 GitHub 上

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【设计模式】Chain of Responsibility 责任链式模式 的相关文章

  • JavaScript的设计模式解析——工厂模式

    这几天一直在看 JavaScript高级程序设计 在第六章面向对象的程序设计中 自我感觉对于小白而而言 会一定程度的难以理解 什么意思啊 根本不明白哇等等 注意 大神请略过 小小码农 不敢妄言 首先 我们开门见山 什么是工厂模式 工厂模式能
  • Java复习-25-单例设计模式

    单例设计模式 目的 使用场景 在实际开发下 会存在一种情况 某一种类在程序的整个生命周期中 只需要实例化一次就足够了 例如 系统数据类 由于操作系统只有一个 因此在程序初始化时该类只需要实例化一次 之后的系统数据更改都是在这一个实例化对象中
  • c++享元模式

    享元模式 1 享元模式简介 享元模式在 设计模式 可复用面向对象软件的基础 一书中是这样说的 运用共享技术有效地支持大量细粒度的对象 本质就是对大量细粒度的对象进行共享 不是每个对象都要通过new的方式去创建 而是通过区分对象的内部状态和外
  • 设计模式-单一职责原则介绍与理解

    描述 一个类应该专注于实现一个功能 好处 便于代码复用 举例 俄罗斯方块游戏 首先可以想到的是游戏逻辑与界面的分离 也就是说逻辑一个类 界面部分一个类 这样做的好处就是我们可以复用游戏逻辑的代码 例如我们用java写了一个基于PC端的俄罗斯
  • python语法(高阶)-设计模式(单例模式)

    参考内容 黑马程序员
  • Java设计模式:装饰者模式(Decorator Pattern)

    装饰者模式 涉及的重要设计原则 类应该对扩展开放 对修改关闭 装饰者模式定义 装饰者模式动态地将责任附加到对象上 若要扩展功能 装饰者提供了比继承更有弹性的替代方案 UML类图 装饰者模式事例 咖啡店 咖啡种类 1 深焙咖啡 DarkRoa
  • 计算资源合并模式——云计算架构常用设计模式

    背景 云计算的解决方案中 最初设计可能有意遵循关注点分离的设计原则 把操作分解为独立的计算单元以便可以单独托管和部署 然而 虽然这种策略可以帮助简化解决方案的逻辑实现 但是在同一个应用程序中要部署大量的计算单元 这会增加运行时的托管成本 并
  • 设计模式——导论

    作为软件开发人员 我们在平时工作的过程中 往往需要编写很多的代码来实现我们的需求 很多的时候会造成代码臃肿和代码冗余的情况 这个时候我们需要引入一个理念 设计模式 设计模式存在的意义在于 1 使得我们的代码更加精炼 2 使我们代码的可读性更
  • 设计模式--提供者模式provider

    设计模式 C 提供者模式 Provider Pattern 介绍 为一个API进行定义和实现的分离 示例 有一个Message实体类 对它的操作有Insert 和Get 方法 持久化数据在SqlServer数据库中或Xml文件里 根据配置文
  • linux内核中的设计模式

    创建型 Object Pool Object Pool模式可以提升性能 尤其是在对象的分配 初始化成本高 使用频率高 但使用时间短的情况下 对象池可以设置对象池的大小和回收时间缓存预分配的对象 NT和Linux都有简单的预分配缓存对象的机制
  • Java设计模式之装饰者设计模式Decorator Pattern

    目录 一 基本概念 二 结构 1 图示 三 案例演示 被装饰对象的基类 一个接口 有cost 和description 两个抽象方法 具体被装饰的对象 实现上面这个接口 装饰者抽象类 基类 实现drink接口 具体的装饰者类 糖 具体装饰者
  • 程序员必知的23种设计模式之组合模式

    文章目录 1 模式引出 学校院系展示需求 1 1 传统方案 1 2 传统方案问题分析 2 组合模式基本介绍 2 1 方案修改 3 组合模式解决的问题 4 组合模式的注意事项和细节 1 模式引出 学校院系展示需求 编写程序展示一个学校院系结构
  • 设计模式——State(状态)模式

    目录 前言 1 定义 2 适用性 3 结构 3 1 结构图 3 2 参与者 4 应用举例 4 1 State TcpState 4 2 Context TcpConnection 4 3 ConcreteState ListeningTcp
  • 【设计模式】工厂模式(Factory Pattern)

    1 概述 工厂模式 Factory Pattern 是最常用的设计模式之一 它属于创建类型的设计模式 它提供了一种创建对象的最佳方式 在工厂模式中 我们在创建对象时不会对客户端暴露创建逻辑 并且是通过一个共同的接口来指向新创建的对象 工厂模
  • JavaScript设计模式-02-单例模式

    Javascript 设计模式 02 单例模式 简介 单例就是保证一个类只有一个实例 实现的方法一般是先判断实例是否存在 如果存在直接返回 如果不存在就创建了再返回 确保了一个类只有一个实例对象 在JavaScript里 单例作为一个命名空
  • 泛型与反射机制在JDBC和Servlet编程中的实践

    写在前面 泛型与反射是java中的两种强大机制 可以很好的提高代码的灵活性和复用性 本篇文章向大家展现在JDBC和Servlet编程场景下反射和泛型技术的实践 通过灵活使用这两种机制打造 高度可复用的JDBC和Servlet代码 1 JDB
  • Java设计模式:模板方法模式

    作者主页 欢迎来到我的技术博客 个人介绍 大家好 本人热衷于 Java后端开发 欢迎来交流学习哦 如果文章对您有帮助 记得 关注 点赞 收藏 评论 您的支持将是我创作的动力 让我们一起加油进步吧 文章目录 一 模板方法模式的定义 二 模板方
  • 设计模式 原型模式 与 Spring 原型模式源码解析(包含Bean的创建过程)

    原创 疯狂的狮子Li 狮子领域 程序圈 2023 12 19 10 30 发表于辽宁 原型模式 原型模式 Prototype模式 是指 用原型实例指定创建对象的种类 并且通过拷贝这些原型 创建新的对象 原型模式是一种创建型设计模式 允许一个
  • 设计模式(3)--对象结构(5)--外观

    1 意图 为子系统中的一组接口提供一个一致的界面 Facade模式定义了一个高层接口 这个接口使得 这一子系统更加容易使用 2 两种角色 子系统 Subsystem 外观 Facade 3 优点 3 1 对客户屏蔽了子系统组件 减少了客户处
  • 自动化测试面试题(附答案)

    1 自动化代码中 用到了哪些设计模式 单例设计模式 工厂模式 PO设计模式 数据驱动模式 面向接口编程设计模式 2 什么是断言 Assert 断言Assert用于在代码中验证实际结果是不是符合预期结果 如果测试用例执行失败会抛出异常并提供断

随机推荐

  • LeetCode 27.移除元素

    文章目录 题目分析 解题思路 思路1 暴力求解 遍历 接口源码 思路2 空间换时间 接口源码 思路3 双指针 快慢指针 接口源码 题目链接 LeetCode 27 移除元素 题目分析 给你一个数组 nums 和一个值 val 你需要 原地
  • 推荐算法实战项目:FNN 原理以及案例实战(附完整 Python 代码)

    本文要介绍的是FNN模型 出自于张伟楠老师于2016年发表的论文 Deep Learning over Multi field Categorical Data 论文提出了两种深度学习模型 分别叫做FNN Factorisation Mac
  • JMeter接口压测和性能监测

    引言 今天我来和大家分享一篇关于JMeter接口压测和性能监测的文章 在现代互联网时代 应用程序的性能已经成为了一个非常重要的问题 并且对于许多公司的生存和发展都起着至关重要的作用 而在这其中 JMeter是一个非常实用的工具 可以帮助我们
  • html5养树游戏源码,奥日小屋:寻找精灵之树

    大家好我是Receiver 又到了一年一度的夏促时间啦 不知道如何剁手的盒友可以考虑入坑 奥日与黑暗森林 哟 作为一款15年的游戏放在现在来看仍然有惊艳的画风 音乐与游戏性 夏促期间五折史低 今天给大家带来的是寻找银之树的流程攻略 另外奥日
  • 【JavaSE】jdk8新特性

    尚硅谷JavaSE笔记合集 文章名 链接 JavaSE 异常 文章地址 JavaSE 常用类 String LocalDateTime 文章地址 JavaSE 枚举 文章地址 JavaSE 注解 文章地址 JavaSE 集合框架 文章地址
  • 【设计相关】UML类图和时序图介绍

    文章目录 一 什么是UML UML的定义 UML的应用场景 类图 Class Diagrams 类关系 继承关系 记忆技巧 案例 汽车关系 购票机 类说明 方法说明 时序图 Sequence Diagrams 一 什么是UML UML的定义
  • CGAL的简介及安装设置

    一 CGAL库的介绍 CGAL Computational Geometry Algorithms Library 库 计算几何算法库 是一个大型的C 几何数据结构和算法库 包含Delaunay三角网 网格生成 布尔运算的多边形 各种几何处
  • [苹果开发者账号]05 换收款的银行账号

    问题场景 新公司申请的苹果开发者账号 收费APP有收入 苹果打款进入了公司银行账号 但银行反馈说 账号不能结算这笔钱 根因是 财务搞错账号业务了 解决方法 要换苹果的收款账号 提醒 涉及苹果这种境外业务 但又是可以人民币结算的 一定要和当地
  • IAR error: a declaration cannot have a label

    在使用switch时 在case 后面申请变量会出现 error a declaration cannot have a label错误 原因 Case statements are only labels This means the c
  • 【安全技术】Java 实现加密数据库连接

    一 前言 在很多项目中 数据库相关的配置文件内容都是以明文的形式展示的 这存在一定的安全隐患 在开发和维护项目时 不仅要关注项目的性能 同时也要注重其安全性 二 实现思路 我们都知道项目启动时 Spring 容器会加载配置文件并读取文件中的
  • FreeRTOS学习-软件定时器管理

    1 简介 软件定时器用于在未来的某个时间执行某个预先指定的函数 或者以一个固定的频率周期性调度该函数 这个预先指定的函数称为软件定时器回调函数 它是由软件定时器服务调用的 软件定时器由FreeRTOS的内核控制 不需要硬件的支持 不与硬件定
  • smart device industry

    公司培训 讲了一下smart device industry 不知讲得对不对 第一层 Ip Core 例如Intel MIPS ARM 第二层 芯片制造商Silicone 例如 broadcom Qualcomm BlueCore inte
  • Office2016软件安装教程

    关注公众号 免费获取资料 解压压缩文件 点击office 2013 专业增强版 64位文件夹 根据自身系统选择位数 右击setup gt 以管理员的身份运行 3 勾选接收 继续 4 选择自定义安装 5 点击浏览 选在office 安装位置
  • STM32实战项目系列教程 (一)—— 循迹小车

    前言 以往我们看到很多学习单片机知识的教程往往是从单片机内部资源出发 这样的教程原理往往晦涩难懂 初学者很难系统的学习开发单片机的项目 而本次教程是从项目出发教你学习循迹小车的制作 整个项目采用 STM32 单片机作为控制器来实现 所以在学
  • 【vue2】el-table 从接口获取数据改变了,但是页面却没有正常渲染

    方法一 在el table上面添加一个 key 属性 指定一个唯一的值 然后数据改变后 我们更新这个唯一值 这样 Vue 会自动重新渲染该组件 1 获取随机uuid 创建在uuid js文件当中 获取唯一id export function
  • 7月15日---7月21日(计划50小时,实际12小时,还有5258小时)

    本周单位事情应该不算多 没事就在家看看文挡 切忌浮躁 一颗平常心 就当学东西了 业余爱好 就按照DDRAW 软引擎 OSG引擎 自制3D引擎去走 上午PHYSX 中午DDRAW引擎 下午加入GAMEDEMO程序 晚上文挡 周六日文档 擦 最
  • 哪个进程在访问这个恶意域名???

    哪个进程在访问这个恶意域名 背景 信息安全工程师很多时候需要通过某个恶意域名来判断主机失陷情况 恶意域名特征比较明显的 比较容易通过威胁情报找到相关线索 例如fr minexmr com 通过威胁情查询 该恶意域名比较容易判断该主机感染Wa
  • 数据双向绑定

    一 什么是双向绑定 我们先从单向绑定切入单向绑定非常简单 就是把Model绑定到View 当我们用JavaScript代码更新Model时 View就会自动更新双向绑定就很容易联想到了 在单向绑定的基础上 用户更新了View Model的数
  • cocos cretor shader effect-the book of shader-4.二维矩阵

    2D Matrices 二维矩阵 前面章节 TheBookofShader开始 Shaping functions 造型函数 Color 颜色 Shapes 形状 平移 之前的章节我们学习了如何制作一些图形 而如何移动它们的技巧则是借助移动
  • 【设计模式】Chain of Responsibility 责任链式模式

    一 前言 责任链行为模式是行为模式的一种 行为模式涉及到算法和对象间职责的分配 行为模式不仅描述对象或类的模式 还描述它们之间的通信模式 行为模式分为 Template Method 模板方法 和 Interpreter 解析器行为模式 模