摘要:在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。至此,我们的责任链模式已经讲完了。总结本篇文章以实际项目中的场景为例,向你描述责任链模式的妙用。而是我写出了代码,才发现用到了责任链模式。
一说到「设计模式」,可能很多人都有听过。
但是如果真的要你说说应用场景,可能会有点「难以描述」。
除了应用场景比较多的单例模式你能够信手拈来,其他的可能会觉得有点难以掌握。也许压根都没用过。
今天,通过本篇文章,让你对责任链模式也能够信手拈来。
本篇文章通过实际项目中的例子来让你认识何为责任链模式。
定义百度百科的介绍:责任链模式是一种设计模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
维基百科的介绍:责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。该模式还描述了往该处理链的末尾添加新的处理对象的方法。
我的介绍:顾名思义,责任链模式是一条链,链上有多个节点,每个节点都有各自的责任。当有输入时,第一个责任节点看自己能否处理该输入,如果可以就处理。如果不能就交由下一个责任节点处理。依次类推,直到最后一个责任节点。
定义总是有点文绉绉,还是看下下面的例子加深下理解吧。
例子举几个例子:
1. 需求开发例子
假设现在有个需求来了,首先是实习生拿到这个需求。
如果实习生能够实现,直接实现。如果不行,他把这个需求交给初级工程师。
如果初级工程师能够实现,直接实现。如果不行,交给中级工程师。
如果中级工程师能够实现,直接实现。如果不行,交给高级工程师。
如果高级工程师能够实现,直接实现。如果不行,交给 CTO。
如果 CTO能够实现,直接实现。如果不行,直接跟产品说,需求不做。
对于程序员来说,没有实现不了的需求,只有不想做的需求
2. 买球篮例子
假设你现在有个篮球,然后想要买个球篮。
你肯定是到店里,让老板把所有尺寸的球篮拿出来。
然后你一个一个试。
第一个不行,就第二个。
第二个不行,就第三个。
...
直到找到合适的。
通过定义和列举的例子,大家对于责任链模式应该有点熟悉了。
是不是觉得自己平时写的代码中好像有用到的样子,有点熟悉?
不要急,接下来我们给大家看看一些熟悉的代码,这里以 Java 代码为例子,其他语言也是类似的。
场景给定一个输入值,根据输入值执行不同逻辑。
我们一看,分分钟写出如下代码:
String input = "1"; if ("1".equals(input)) { //TODO do something } else if ("2".equals(input)) { //TODO do something } else if ("3".equals(input)) { //TODO do something }
或者如下代码:
String input = "1"; switch (input) { case "1": //TODO do something break; case "2": //TODO do something break; case "3": //TODO do something break; default: //TODO do something break; }
如果每个分支里面的逻辑比较简单,那还好,如果逻辑复杂,假设每个 case 大概要 100 行代码处理,有 10 个 case,一下子就出来一个「千行代码」文件。而且还不利于维护、测试和扩展。
如果能够想办法把代码拆分成每个 case 一个文件,这样不仅代码逻辑清晰了很多,而且不管是后续维护、扩展还是进行测试,都方便很多。
因此,本篇文章核心,责任链模式的妙用——拆分代码就来了。
责任链模式拆分代码这里以上面场景为例子进行拆分代码说明,其他场景相信大家能够举一反三。
1. 定义一个抽象类。
public abstract class BaseCase { // 为 true 表明自己可以处理该 case private boolean isConsume; public BaseCase(boolean isConsume) { this.isConsume = isConsume; } // 下一个责任节点 private BaseCase nextCase; public void setNextCase(BaseCase nextCase) { this.nextCase = nextCase; } public void handleRequest() { if (isConsume) { // 如果当前节点可以处理,直接处理 doSomething(); } else { // 如果当前节点不能处理,并且有下个节点,交由下个节点处理 if (null != nextCase) { nextCase.handleRequest(); } } } abstract protected void doSomething(); }
注释已经写的很清楚了。这里就不再赘述。
2. 各个 case 来实现该抽象类。
这里列举一个 case,其他可以看代码。
public class OneCase extends BaseCase { public OneCase(boolean isConsume) { super(isConsume); } @Override protected void doSomething() { // TODO do something System.out.println(getClass().getName()); } }
3. 初始化各个 case,并指定每个 case 的下一个节点。
String input = "1"; OneCase oneCase = new OneCase("1".equals(input)); TwoCase twoCase = new TwoCase("2".equals(input)); DefaultCase defaultCase = new DefaultCase(true); oneCase.setNextCase(twoCase); twoCase.setNextCase(defaultCase); oneCase.handleRequest();
好了,到此我们责任链模式拆分代码就告一段落了。
一个优化上面是责任链模式拆分代码的一个基本实现。
后面有同事给了建议,说可以参考 OkHttp 里面的 Interceptor 实现。
所以这边看了一下,做了如下改进。
先说一下大概思想吧。
将所有的 case 集中起来,通过遍历确定能够处理的 case。
同样是以上面的场景为例进行说明。
1. 定义一个接口。
interface BaseCase { // 所有 case 处理逻辑的方法 void doSomething(String input, BaseCase baseCase); }
2. 建立一个责任链管理类,管理所有 case。
public class CaseChain implements BaseCase { // 所有 case 列表 private ListmCaseList = new ArrayList<>(); // 索引,用于遍历所有 case 列表 private int index = 0; // 添加 case public CaseChain addBaseCase(BaseCase baseCase) { mCaseList.add(baseCase); return this; } @Override public void doSomething(String input, BaseCase baseCase) { // 所有遍历完了,直接返回 if (index == mCaseList.size()) return; // 获取当前 case BaseCase currentCase = mCaseList.get(index); // 修改索引值,以便下次回调获取下个节点,达到遍历效果 index++; // 调用 当前 case 处理方法 currentCase.doSomething(input, this); } }
3. 各个 case 实现接口。这里以其中一个为例。
public class OneCase implements BaseCase { @Override public void doSomething(String input, BaseCase baseCase) { if ("1".equals(input)) { // TODO do something System.out.println(getClass().getName()); return; } //当前没法处理,回调回去,让下一个去处理 baseCase.doSomething(input, baseCase); } }
4. 初始化各个 case
String input = "1"; CaseChain caseChain = new CaseChain(); caseChain.addBaseCase(new OneCase()) .addBaseCase(new TwoCase()) .addBaseCase(new DefaultCase()); caseChain.doSomething(input, caseChain);
好了,注释写的很清楚,相信大家看懂是没问题的。
至此,我们的责任链模式已经讲完了。
相信你对于责任链模式已经熟记于心了。
如果你还有点疑问
可以留言,看下代码或者敲敲代码。
总结本篇文章以实际项目中的场景为例,向你描述责任链模式的妙用。
看完文章,可能你只学到其形,而没有学到其神。
通过不断的使用以及自己经验的不断积累,相信达到形神兼备也是时间问题而已。
等你完全掌握之后,不再是「我要用责任链模式,因此写出了代码」。
而是「我写出了代码,才发现用到了责任链模式」。
正如《倚天屠龙记》里面张三丰教张无忌太极剑时,最后张无忌全都忘了一样。
温馨提示:
学习了新设计模式,难免有点手痒。
但是切记不要滥用设计模式。
不要为了设计而设计。
比如你就几个 case,而且处理逻辑就是弹个框。
你说你要用上设计模式?这样成本会更高,其实没必要。
所以学会是一回事,什么时候用又是另一回事了。
觉得不错,欢迎转发分享。
文中所有代码
参考:
http://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html
https://github.com/simple-android-framework/android_design_patterns_analysis/tree/master/chain-of-responsibility/AigeStudio
https://www.jianshu.com/p/8a157cb73434
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/3027.html
摘要:前言近期在做的拦截器功能,正好用到了责任链模式。通过官方图就可以非常清楚的看出是一个责任链模式用责任链模式设计一个拦截器对于拦截器来说使用责任链模式再好不过了。设置拦截器到责任链中时通过反射将的值保存到各个拦截器中。 showImg(https://segmentfault.com/img/remote/1460000016756077?w=1733&h=1300); 前言 近期在做 ...
摘要:责任链模式涉及到的角色如下所示抽象处理者角色定义一个处理请求的抽象类。如果一个类承担了一部分责任,还将请求踢给下一个皮球,则被称为不纯的责任链模式。一般来说,日常开发中不纯的责任链模式用的比较多一点。参考责任链模式更多文章 在阎宏博士的《JAVA与模式》一书中开头是这样描述责任链(Chain of Responsibility)模式的: 责任链模式是一种对象的行为模式。在责任链模式里,...
摘要:咦这一层一层上报就涉及到这次的责任链模式。责任链模式和观察者模式存在一个共同点,就是传递责任链模式是一级一级的传递,形成一条链,链节点处理者之间是存在传递关系的。这是责任链模式和观察者模式的区别,也是责任链模式的核心。 今天来说说程序员小猿和产品就关于需求发生的故事。前不久,小猿收到了产品的需求。 产品经理:小猿,为了迎合大众屌丝用户的口味,我们要放一张图,要露点的。 小猿:........
摘要:咦这一层一层上报就涉及到这次的责任链模式。责任链模式和观察者模式存在一个共同点,就是传递责任链模式是一级一级的传递,形成一条链,链节点处理者之间是存在传递关系的。这是责任链模式和观察者模式的区别,也是责任链模式的核心。 今天来说说程序员小猿和产品就关于需求发生的故事。前不久,小猿收到了产品的需求。 产品经理:小猿,为了迎合大众屌丝用户的口味,我们要放一张图,要露点的。 小猿:........
时间:2017年08月30日星期三说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学源码:https://github.com/zccodere/s...学习源码:https://github.com/zccodere/s... 第一章:责任链模式简介 1-1 课程简介 课程大纲 什么是责任链模式 如何实现责任链模式 责任链模式如何解耦 责任链模式的应用 案例:...
阅读 2451·2021-10-22 09:55
阅读 1742·2021-09-27 13:35
阅读 1137·2021-08-24 10:02
阅读 1233·2019-08-30 15:55
阅读 1097·2019-08-30 14:13
阅读 3350·2019-08-30 13:57
阅读 1870·2019-08-30 11:07
阅读 2322·2019-08-29 17:12