设计模式之美
王争
前Google工程师,《数据结构与算法之美》专栏作者
立即订阅
21545 人已学习
课程目录
已更新 70 讲 / 共 102 讲
0/6登录后,你可以任选6讲全文学习。
开篇词 (1讲)
开篇词 | 一对一的设计与编码集训,让你告别没有成长的烂代码!
免费
设计模式学习导读 (3讲)
01 | 为什么说每个程序员都要尽早地学习并掌握设计模式相关知识?
02 | 从哪些维度评判代码质量的好坏?如何具备写出高质量代码的能力?
03 | 面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?
设计原则与思想:面向对象 (11讲)
04 | 理论一:当谈论面向对象的时候,我们到底在谈论什么?
05 | 理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?
06 | 理论三:面向对象相比面向过程有哪些优势?面向过程真的过时了吗?
07 | 理论四:哪些代码设计看似是面向对象,实际是面向过程的?
08 | 理论五:接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?
09 | 理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?
10 | 理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?
11 | 实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?
12 | 实战一(下):如何利用基于充血模型的DDD开发一个虚拟钱包系统?
13 | 实战二(上):如何对接口鉴权这样一个功能开发做面向对象分析?
14 | 实战二(下):如何利用面向对象设计和编程开发接口鉴权功能?
设计原则与思想:设计原则 (12讲)
15 | 理论一:对于单一职责原则,如何判定某个类的职责是否够“单一”?
16 | 理论二:如何做到“对扩展开放、修改关闭”?扩展和修改各指什么?
17 | 理论三:里式替换(LSP)跟多态有何区别?哪些代码违背了LSP?
18 | 理论四:接口隔离原则有哪三种应用?原则中的“接口”该如何理解?
19 | 理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?
20 | 理论六:我为何说KISS、YAGNI原则看似简单,却经常被用错?
21 | 理论七:重复的代码就一定违背DRY吗?如何提高代码的复用性?
22 | 理论八:如何用迪米特法则(LOD)实现“高内聚、松耦合”?
23 | 实战一(上):针对业务系统的开发,如何做需求分析和设计?
24 | 实战一(下):如何实现一个遵从设计原则的积分兑换系统?
25 | 实战二(上):针对非业务的通用框架开发,如何做需求分析和设计?
26 | 实战二(下):如何实现一个支持各种统计规则的性能计数器?
设计原则与思想:规范与重构 (11讲)
27 | 理论一:什么情况下要重构?到底重构什么?又该如何重构?
28 | 理论二:为了保证重构不出错,有哪些非常能落地的技术手段?
29 | 理论三:什么是代码的可测试性?如何写出可测试性好的代码?
30 | 理论四:如何通过封装、抽象、模块化、中间层等解耦代码?
31 | 理论五:让你最快速地改善代码质量的20条编程规范(上)
32 | 理论五:让你最快速地改善代码质量的20条编程规范(中)
33 | 理论五:让你最快速地改善代码质量的20条编程规范(下)
34 | 实战一(上):通过一段ID生成器代码,学习如何发现代码质量问题
35 | 实战一(下):手把手带你将ID生成器代码从“能用”重构为“好用”
36 | 实战二(上):程序出错该返回啥?NULL、异常、错误码、空对象?
37 | 实战二(下):重构ID生成器项目中各函数的异常处理代码
设计原则与思想:总结课 (3讲)
38 | 总结回顾面向对象、设计原则、编程规范、重构技巧等知识点
39 | 运用学过的设计原则和思想完善之前讲的性能计数器项目(上)
40 | 运用学过的设计原则和思想完善之前讲的性能计数器项目(下)
设计模式与范式:创建型 (7讲)
41 | 单例模式(上):为什么说支持懒加载的双重检测不比饿汉式更优?
42 | 单例模式(中):我为什么不推荐使用单例模式?又有何替代方案?
43 | 单例模式(下):如何设计实现一个集群环境下的分布式单例模式?
44 | 工厂模式(上):我为什么说没事不要随便用工厂模式创建对象?
45 | 工厂模式(下):如何设计实现一个Dependency Injection框架?
46 | 建造者模式:详解构造函数、set方法、建造者模式三种对象创建方式
47 | 原型模式:如何最快速地clone一个HashMap散列表?
设计模式与范式:结构型 (8讲)
48 | 代理模式:代理在RPC、缓存、监控等场景中的应用
49 | 桥接模式:如何实现支持不同类型和渠道的消息推送系统?
50 | 装饰器模式:通过剖析Java IO类库源码学习装饰器模式
51 | 适配器模式:代理、适配器、桥接、装饰,这四个模式有何区别?
52 | 门面模式:如何设计合理的接口粒度以兼顾接口的易用性和通用性?
53 | 组合模式:如何设计实现支持递归遍历的文件系统目录树结构?
54 | 享元模式(上):如何利用享元模式优化文本编辑器的内存占用?
55 | 享元模式(下):剖析享元模式在Java Integer、String中的应用
设计模式与范式:行为型 (11讲)
56 | 观察者模式(上):详解各种应用场景下观察者模式的不同实现方式
57 | 观察者模式(下):如何实现一个异步非阻塞的EventBus框架?
58 | 模板模式(上):剖析模板模式在JDK、Servlet、JUnit等中的应用
59 | 模板模式(下):模板模式与Callback回调函数有何区别和联系?
60 | 策略模式(上):如何避免冗长的if-else/switch分支判断代码?
61 | 策略模式(下):如何实现一个支持给不同大小文件排序的小程序?
62 | 职责链模式(上):如何实现可灵活扩展算法的敏感信息过滤框架?
63 | 职责链模式(下):框架中常用的过滤器、拦截器是如何实现的?
64 | 状态模式:游戏、工作流引擎中常用的状态机是如何实现的?
65 | 迭代器模式(上):相比直接遍历集合数据,使用迭代器有哪些优势?
66 | 迭代器模式(中):遍历集合的同时,为什么不能增删集合元素?
不定期加餐 (3讲)
加餐一 | 用一篇文章带你了解专栏中用到的所有Java语法
加餐二 | 设计模式、重构、编程规范等相关书籍推荐
春节特别加餐 | 王争:如何学习《设计模式之美》专栏?
免费
设计模式之美
登录|注册

62 | 职责链模式(上):如何实现可灵活扩展算法的敏感信息过滤框架?

王争 2020-03-25
前几节课中,我们学习了模板模式、策略模式,今天,我们来学习职责链模式。这三种模式具有相同的作用:复用和扩展,在实际的项目开发中比较常用,特别是框架开发中,我们可以利用它们来提供框架的扩展点,能够让框架的使用者在不修改框架源码的情况下,基于扩展点定制化框架的功能。
今天,我们主要讲解职责链模式的原理和实现。除此之外,我还会利用职责链模式,带你实现一个可以灵活扩展算法的敏感词过滤框架。下一节课,我们会更加贴近实战,通过剖析 Servlet Filter、Spring Interceptor 来看,如何利用职责链模式实现框架中常用的过滤器、拦截器。
话不多说,让我们正式开始今天的学习吧!

职责链模式的原理和实现

职责链模式的英文翻译是 Chain Of Responsibility Design Pattern。在 GoF 的《设计模式》中,它是这么定义的:
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《设计模式之美》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(40)

  • 小晏子
    如果希望客户端代码也满足开闭原则,不修改任何代码,那么有个办法是不需要用户手动添加处理器,让框架代码能自动发现处理器,然后自动调用,要实现这个,就需要框架代码中自动发现接口实现类,可以通过注解和反射实现,然后将所有实现类都放到调用链中。这有个问题就是不够灵活,所有调用链可能都被执行,用户不能自由选择和组合处理器。
    2020-03-25
    1
    16
  • Michael
    之前在公司做的一个关于金融日历的需求,就用到了老师说的指责链模式,一个用户有各种金融日历提醒,每个提醒逻辑不一样,通过给各个提醒服务打上注解标记,通过spring ioc容器中动态获取提醒服务对象,再利用Java中的future,并行调用,最终得到的提醒汇聚成了一个提醒列表,再通过排序规则返给前端,之前这么做了,代码复合开闭原则了,但不知道是责任链模式,老师讲了,才恍然大悟,是责任链的变体,所有链条都执行一遍。
    2020-03-25
    11
  • 葫芦娃
    通过配置文件配置需要的处理器,客户端代码也可以不改,通过反射动态加载
    2020-03-25
    10
  • 唔多志
    职责链模式和装饰器模式太像了...
    2020-03-25
    7
    5
  • Geek_54edc1
    通过配置文件,配置需要的过滤处理器,利用java的反射机制,动态的加载处理器类,创建处理器对象。
    2020-03-25
    3
  • 韵呀
    在项目开发中,无意用到过滤链思维,也就是老师说的职责链模式的变体。理解更深刻了。
    收获总结:
    标准的职责链模式,链上的处理器顺序执行,有一个处理器可以处理,就终止传递执行
    变体的职责链模式,链上的处理器会顺序执行,不会终止。

    职责链模式的两种实现方式:
    1.链表,只记录head和tail,结合模板方法模式,显式调用下一个处理器,具体处理器只要实现自己的处理逻辑即可。
    2.数组列表,将处理器放进一个list里,Java的arraylist底层就是一个数组,for循环调用所有的处理器
    2020-03-25
    3
  • 守拙
    总结:

    * Chain Of Responsibility Pattern通常应用在框架设计中, 为框架提供扩展点.
    * COF Pattern 在我们日常使用的框架中经常见到: Okhttp的HttpRequestInterceptor, Rxjava的ObservableFilter等等.
    * COF的底层实现方式通常分为两种: 数组实现和链表实现. 无论哪种实现, 都可以使用Iterator来遍历职责链.



    课堂讨论:

    ​ 今天讲到利用职责链模式,我们可以让框架代码满足开闭原则。添加一个新的处理器,只需要修改客户端代码。如果我们希望客户端代码也满足开闭原则,不修改任何代码,你有什么办法可以做到呢?



    ​ 如果客户端代码满足开闭原则, 则需要从Chain的构造器着手, Chain构造完成后直接调用执行即可.

    ​ 可以采用依赖注入的方式为Chain注入对象, 其底层原理通常是注解+反射.
    2020-03-25
    2
  • 攻城拔寨
    如果客户端全盘接受所有处理器,可以通过自动扫描注册的方式添加处理器。这样比较不灵活,客户端没法选处理器。
    还有个方法就是用配置中心/文件去做,客户端通过配置添加处理器。如果存在多个客户端代码需要添加不同处理器,可以用不同配置项去加载添加责任链。
    2020-03-25
    2
  • 课后题:在项目中遇到跟责任链模式很相像的内容,业务是将天线扫描到的电子标签分发到不同的类中,这些类都实现了一个接口,有同样的方法,项目中的做法是在对象中维护一个ArrayList容器,在对象与天线建立连接后开始回调,将数据发送给各个实现类
    我们需要做的就是给某个接口添加一个实现类,然后将它存入对象的容器中,通过利用框架的依赖注入的方式,在类这个粒度上可以满足开闭原则
    2020-03-25
    2
  • test
    在静态初始化块里面定义好字符串常量与处理类的对应关系,用户使用的时候在配置文件里面配置好
    2020-03-25
    2
  • Liam
    1 工厂模式创建chain
    2 使用配置文件或注解添加节点
    3 反射自动装配chain
    2020-03-25
    2
  • Monday
    思考题,客户端组装过滤器时,从配置文件获取
    2020-03-25
    2
  • iamjohnnyzhuang
    课后问题:
    方法比较多,可以通过解析配置文件生成对应的链,那就不用改代码了。或者可以使用注解,框架通过注解识别到对应的处理器并且将其生成链。
    ---
    责任链这个设计模式感觉是算比较实用的一个了,在工作时有几种场景用到:
    1)过滤链的设计,一条数据要不要过滤,通过扩展不同的过滤器来决定和小争哥文章说的类似。由于我们的每个过滤器代码都比较复杂,而且优先级也不一样,所以通过这种设计模式很好的降低了复杂度、解耦。
    2)数据加工处理,一条数据过来了,只有最基础的IP信息,我们需要对它做不同的加工处理,例如扩展出省份运营商(调用接口1)、扩充出其对应的服务器厂商(调用接口2)等等。而针对不同的业务可能不需要全部字段,例如假如这条数据如果是从公司自己的接口上报的要所有字段,如果是从友商接口上报的只要个别几个字段。通过责任链非常灵活的实现了扩展、定制化配置


    2020-03-30
    1
  • 平凡世界
    请求中间件,也算职责链的一种变体吧
    2020-03-27
    1
  • 小刀
    配置文件+反射
    2020-03-25
    1
  • 墨雨
    可以使用自定义注解来添加责任链
    2020-03-25
    1
  • lcf枫
    Dj 的middleware gorm的注册函数都是这种模式
    2020-04-05
  • 弹簧人
    添加一个新的处理器,只需要修改客户端代码。
    ------------------------------------------------------
    将责任链的调用接口存入数据库中,客户端代码负责读取数据库,看看都有哪些操作。数据库动态配置
    2020-04-04
  • 用HandlerChain类处理职责链的组装,也是职责分离;很多教程里都是addHandler方法返回当前参数hanlder,使用时类似builder的使用方式。
    2020-04-04
  • 云峰
    如果使用spring的话,可以根据接口类型获取所有的bean的集合,然后遍历add到数组/链表中
    2020-04-03
收起评论
40
返回
顶部