62丨职责链模式上如何实现可灵活扩展算法的敏感信息过滤框架_W_第1页
62丨职责链模式上如何实现可灵活扩展算法的敏感信息过滤框架_W_第2页
62丨职责链模式上如何实现可灵活扩展算法的敏感信息过滤框架_W_第3页
62丨职责链模式上如何实现可灵活扩展算法的敏感信息过滤框架_W_第4页
62丨职责链模式上如何实现可灵活扩展算法的敏感信息过滤框架_W_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、下载APP62 | 职责链模式(上):如何实现可灵活扩展算法的敏感信息过滤框架?2020-03-25 王争设计模式之美进入课程讲述:冯永吉时长 09:23 大小 6.46M前几节课中,我们学习了模板模式、策略模式,今天,我们来学习职责链模式。这三种模式具有相同的作用:复用和扩展,在实际的项目开发中比较常用,特别是框架开发中,我们可以利用它们来提供框架的扩展点,能够让框架的使用者在不修改框架源码的情况下,基于扩展点定制化框架的功能。今天,我们主要讲解职责链模式的原理和实现。除此之外,我还会利用职责链模式,带你实现一个可以灵活扩展算法的敏感词过滤框架。下一节课,我们会更加贴近实战,通过剖析Serv

2、let 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 obje

3、cts and pass the request along the chain until an object handles it.翻译成中文就是:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。这么说比较抽象,我用更加容易理解的话来进一步解读一下。在职责链模式中,多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请 求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的

4、处理职责,所以叫作职责链模式。关于职责链模式,我们先来看看它的代码实现。结合代码实现,你会更容易理解它的定义。职责链模式有多种实现方式,我们这里介绍两种比较常用的。第一种实现方式如下所示。其中,Handler 是所有处理器类的抽象父类,handle() 是抽象方法。每个具体的处理器类(HandlerA、HandlerB)的 handle() 函数的代码结构类似, 如果它能处理该请求,就不继续往下传递;如果不能处理,则交由后面的处理器来处理(也就是调用 successor.handle())。HandlerChain 是处理器链,从数据结构的角度来看,它就是一个记录了链头、链尾的链表。其中,记录

5、链尾是为了方便添加处理器。复制代码1234public abstract class Handler protected Handler successor = null;public void setSuccessor(Handler successor) 5this.successor = successor;678public abstract void handle();91011public class HandlerA extends Handler 12Override13public boolean handle() 14boolean handled = false;15/.

6、16if (!handled & successor != null) 17successor.handle();1819202122public class HandlerB extends Handler 23Override24public void handle() 25boolean handled = false;26/.27if (!handled & successor != null) 28successor.handle();2930313233public class HandlerChain 34private Handler head = null;35private

7、 Handler tail = null;3637public void addHandler(Handler handler)38handler.setSuccessor(null);3940if (head= null) 41head =handler;42tail =handler;43return;444546tail.setSuccessor(handler);47tail = handler;484950public void handle() 51if (head != null) 52head.handle();5354555657 / 使用举例58 public class

8、Application 59 public static void main(String args) 60 HandlerChain chain = new HandlerChain();61 chain.addHandler(newHandlerA();62 chain.addHandler(newHandlerB();63 chain.handle();6465 实际上,上面的代码实现不够优雅。处理器类的 handle() 函数,不仅包含自己的业务逻辑, 还包含对下一个处理器的调用,也就是代码中的 successor.handle()。一个不熟悉这种代码结构的程序员,在添加新的处理器类的

9、时候,很有可能忘记在 handle() 函数中调用successor.handle(),这就会导致代码出现 bug。针对这个问题,我们对代码进行重构,利用模板模式,将调用 successor.handle() 的逻辑从具体的处理器类中剥离出来,放到抽象父类中。这样具体的处理器类只需要实现自己的业务逻辑就可以了。重构之后的代码如下所示:1public abstract class Handler 复制代码23protected Handler successor = null;4public void setSuccessor(Handler successor)5 this.successor

10、 = successor;678public final void handle()9 boolean handled =10doHandle();11if (successor != null & !handled)12 successor.handle();131415161718public class HandlerA extends Handler19 Override20protected boolean doHandle()21 boolean handled = false;22/.23return handled;24252627282930313233343536publi

11、c class HandlerB extends Handler Overrideprotected boolean doHandle() boolean handled = false;/.return handled;/ HandlerChain和Application代码不变我们再来看第二种实现方式,代码如下所示。这种实现方式更加简单。HandlerChain 类用数组而非链表来保存所有的处理器,并且需要在 HandlerChain 的 handle() 函数中,依次调用每个处理器的 handle() 函数。复制代码1 public interface IHandler 2 boolea

12、n handle();3 45 public class HandlerA implements IHandler 6 Override7 public boolean handle() 8 boolean handled = false;9/.10return handled;1112 1314 public class HandlerB implements IHandler 15 Override16 public boolean handle() 17 boolean handled = false;18/.19return handled;2021 2223 public class

13、 HandlerChain 24 private List handlers = new ArrayList();2526 public void addHandler(IHandler handler) 27 this.handlers.add(handler);282930 public void handle() 31 for (IHandler handler : handlers) 32boolean handled = handler.handle();33if (handled) 34break;353637383940/ 使用举例41public class Applicati

14、on 42public static void main(String args)43 HandlerChain chain = new44HandlerChain(); chain.addHandler(new45HandlerA(); chain.addHandler(new46HandlerB(); chain.handle();4748 在 GoF 给出的定义中,如果处理器链上的某个处理器能够处理这个请求,那就不会继续往下传递请求。实际上,职责链模式还有一种变体,那就是请求会被所有的处理器都处理一遍, 不存在中途终止的情况。这种变体也有两种实现方式:用链表存储处理器和用数组存储处理器,

15、跟上面的两种实现方式类似,只需要稍微修改即可。我这里只给出其中一种实现方式,如下所示。另外一种实现方式你对照着上面的实现自行修改。复制代码1 public abstract class Handler 2 protected Handler successor = null;345678910111213141516public void setSuccessor(Handler successor) this.successor = successor;public final void handle() doHandle();if (successor != null) successor

16、.handle();protected abstract void doHandle();1718 public class HandlerA extends Handler 19Override20protected void doHandle() 21/.22232425public class HandlerB extends Handler 26Override27protected void doHandle() 28/.29303132public class HandlerChain 33private Handler head = null;34private Handler

17、tail = null;36public void addHandler(Handler handler)37handler.setSuccessor(null);3839if (head = null) 40head = handler;41tail = handler;42return;434445tail.setSuccessor(handler);46tail = handler;474849public void handle() 50if (head != null) 51head.handle();525354553556 / 使用举例57 public class Applic

18、ation 58 public static void main(String args) 59HandlerChain chain = new HandlerChain();60chain.addHandler(new HandlerA();61chain.addHandler(new HandlerB();62chain.handle();6364 职责链模式的应用场景举例职责链模式的原理和实现讲完了,我们再通过一个实际的例子,来学习一下职责链模式的应用场景。对于支持 UGC(User Generated Content,用户生成内容)的应用(比如论坛)来说, 用户生成的内容(比如,在论坛

19、中发表的帖子)可能会包含一些敏感词(比如涉黄、广告、 等词汇)。针对这个应用场景,我们就可以利用职责链模式来过滤这些敏感词。对于包含敏感词的内容,我们有两种处理方式,一种是直接禁止发布,另一种是给敏感词打马赛克(比如,用 * 替换敏感词)之后再发布。第一种处理方式符合 GoF 给出的职责链模式的定义,第二种处理方式是职责链模式的变体。我们这里只给出第一种实现方式的代码示例,如下所示,并且,我们只给出了代码实现的骨架,具体的敏感词过滤算法并没有给出,你可以参看我的另一个专栏数据结构与算法之美中多模式字符串匹配的相关章节自行实现。复制代码123456789101112131415161718192

20、02122232425262728public interface SensitiveWordFilter boolean doFilter(Content content);public class SexyWordFilter implements SensitiveWordFilter Overridepublic boolean doFilter(Content content) boolean legal = true;/.return legal;/ PoliticalWordFilter、AdsWordFilter类代码结构与SexyWordFilter类似public clas

21、s SensitiveWordFilterChain private List filters = new ArrayList();public void addFilter(SensitiveWordFilter filter) this.filters.add(filter);/ return true if content doesnt contain sensitive words. public boolean filter(Content content) for (SensitiveWordFilter filter : filters) if (!filter.doFilter

22、(content) return false;29303132 33return true;34 public class ApplicationDemo 35 public static void main(String args) 36 SensitiveWordFilterChain filterChain = new SensitiveWordFilterChain();37 filterChain.addFilter(new AdsWordFilter();38 filterChain.addFilter(new SexyWordFilter();39 filterChain.add

23、Filter(newPoliticalWordFilter();4041boolean legal = filterChain.filter(new Content();42if (!legal) 43/ 不发表44 else 45/ 发 表464748 看了上面的实现,你可能会说,我像下面这样也可以实现敏感词过滤功能,而且代码更加简单,为什么非要使用职责链模式呢?这是不是过度设计呢?复制代码1234567891011121314151617181920212223public class SensitiveWordFilter / return true if content doesnt

24、contain sensitive words. public boolean filter(Content content) if (!filterSexyWord(content) return false;if (!filterAdsWord(content) return false;if (!filterPoliticalWord(content) return false;return true;private boolean filterSexyWord(Content content) /.private boolean filterAdsWord(Content conten

25、t) 24252627282930/.private boolean filterPoliticalWord(Content content) /.我们前面多次讲过,应用设计模式主要是为了应对代码的复杂性,让其满足开闭原则,提高 代码的扩展性。这里应用职责链模式也不例外。实际上,我们在讲解 策略模式的时候, 也讲过类似的问题,比如,为什么要用策略模式?当时的给出的理由,与现在应用职责链模 式的理由,几乎是一样的,你可以结合着当时的讲解一块来看下。首先,我们来看,职责链模式如何应对代码的复杂性。将大块代码逻辑拆分成函数,将大类拆分成小类,是应对代码复杂性的常用方法。应用职责链模式,我们把各个敏感

26、词过滤函数继续拆分出来,设计成独立的类,进一步简化了SensitiveWordFilter 类,让 SensitiveWordFilter 类的代码不会过多,过复杂。其次,我们再来看,职责链模式如何让代码满足开闭原则,提高代码的扩展性。当我们要扩展新的过滤算法的时候,比如,我们还需要过滤特殊符号,按照非职责链模式的代码实现方式,我们需要修改 SensitiveWordFilter 的代码,违反开闭原则。不过,这样的修改还算比较集中,也是可以接受的。而职责链模式的实现方式更加优雅,只需要新添加一个 Filter 类,并且通过 addFilter() 函数将它添加到 FilterChain 中即可

27、,其他代码完全不需要修改。不过,你可能会说,即便使用职责链模式来实现,当添加新的过滤算法的时候,还是要修改客户端代码(ApplicationDemo),这样做也没有完全符合开闭原则。实际上,细化一下的话,我们可以把上面的代码分成两类:框架代码和客户端代码。其中, ApplicationDemo 属于客户端代码,也就是使用框架的代码。除 ApplicationDemo 之外的代码属于敏感词过滤框架代码。假设敏感词过滤框架并不是我们开发维护的,而是我们引入的一个第三方框架,我们要扩展一个新的过滤算法,不可能直接去修改框架的源码。这个时候,利用职责链模式就能达到开篇所说的,在不修改框架源码的情况下,

28、基于职责链模式提供的扩展点,来扩展新的功能。换句话说,我们在框架这个代码范围内实现了开闭原则。除此之外,利用职责链模式相对于不用职责链的实现方式,还有一个好处,那就是配置过滤算法更加灵活,可以只选择使用某几个过滤算法。重点回顾好了,今天的内容到此就讲完了。我们一块儿总结回顾一下,你需要重点掌握的内容。在职责链模式中,多个处理器依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。在 GoF 的定义中,一旦某个处理器能处理这个请求,就不会继续

29、将请求传递给后续的处理器了。当然,在实际的开发中,也存在对这个模式的变体,那就是请求不会中途终止传递, 而是会被所有的处理器都处理一遍。职责链模式有两种常用的实现。一种是使用链表来存储处理器,另一种是使用数组来存储处 理器,后面一种实现方式更加简单。课堂讨论今天讲到利用职责链模式,我们可以让框架代码满足开闭原则。添加一个新的处理器,只需要修改客户端代码。如果我们希望客户端代码也满足开闭原则,不修改任何代码,你有什么办法可以做到呢?欢迎留言和我分享你的想法。如果有收获,也欢迎你把这篇文章分享给你的朋友。 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其

30、法律责任。上一篇61 | 策略模式(下):如何实现一个支持给不同大小文件排序的小程序?下一篇63 | 职责链模式(下):框架中常用的过滤器、是如何实现的?写留言精选留言 (32)小晏子2020-03-25如果希望客户端代码也满足开闭原则,不修改任何代码,那么有个办法是不需要用户手动添加处理器,让框架代码能自动发现处理器,然后自动调用,要实现这个,就需要框架代码中自动发现接口实现类,可以通过注解和反射实现,然后将所有实现类都放到调用链中。这有个问题就是不够灵活,所有调用链可能都被执行,用户不能自由选择和组合处理器。展开 1 14Michael2020-03-25之前在公司做的一个关于金融日历的需

31、求,就用到了老师说的指责链模式,一个用户有各种金融日历提醒,每个提醒逻辑不一样,通过给各个提醒服务打上注解标记,通过spring i oc容器中动态获取提醒服务对象,再利用Java中的future,并行调用,最终得到的提醒汇聚成了一个提醒列表,再通过排序规则返给前端,之前这么做了,代码复合开闭原则了, 但不知道是责任链模式,老师讲了,才恍然大悟,是责任链的变体,所有链条都执行一展开 11葫芦娃2020-03-25通过配置文件配置需要的处理器,客户端代码也可以不改,通过反射动态加载9唔多志2020-03-25职责链模式和装饰器模式太像了.展开75韵呀2020-03-25在项目开发中,无意用到过滤链思维,也就是老师说的职责链模式的变体。理解更深刻了。收获总结:标准的职责链模式,链上的处理器顺序执行,有一个处理器可以处理,就终止传递执行变体的职责链模式,链上的处理器会顺序执行,不会终止。展开3Geek_54edc12020-03-25通过配置文件,配置需要的过滤处理器,利用java的反射机制,动态的加载处理器类,创建处理器对象。2攻城拔寨2020-03-25如果客户端

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论