一说到「设计模式」,可能不少人都有听过。html
可是若是真的要你说说应用场景,可能会有点「难以描述」。android
除了应用场景比较多的单例模式你可以信手拈来,其余的可能会以为有点难以掌握。也许压根都没用过。git
今天,经过本篇文章,让你对责任链模式也可以信手拈来。程序员
本篇文章经过实际项目中的例子来让你认识何为责任链模式。github
百度百科的介绍:责任链模式是一种设计模式。在责任链模式里,不少对象由每个对象对其下家的引用而链接起来造成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪个对象最终处理这个请求,这使得系统能够在不影响客户端的状况下动态地从新组织和分配责任。设计模式
维基百科的介绍:责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。该模式还描述了往该处理链的末尾添加新的处理对象的方法。bash
个人介绍:顾名思义,责任链模式是一条链,链上有多个节点,每一个节点都有各自的责任。当有输入时,第一个责任节点看本身可否处理该输入,若是能够就处理。若是不能就交由下一个责任节点处理。依次类推,直到最后一个责任节点。ide
定义老是有点文绉绉,仍是看下下面的例子加深下理解吧。学习
举几个例子:测试
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 List<BaseCase> mCaseList = 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,并且处理逻辑就是弹个框。
你说你要用上设计模式?这样成本会更高,其实不必。
因此学会是一回事,何时用又是另外一回事了。
以为不错,欢迎转发分享。
参考: