案例思考-Switch 语句实现职责链模式
案例介绍
撇去之前 Stream 深入分析到 Lambada 扩展使用 介绍的 switch 语句是 Java 的语法糖,底层编译是通过 hashcode、equal 实现多类型遍历 case。
我们来看下近期编程时在代码中看到 Switch 被误用的情况:
- Part Code Ⅰ
public Result run(RunTypeEnum runType) switch(runType) { case A: return runA(); case B: if (configService.isCanRunB()) { return runB(); } startDoNotB(); case C: if (configService.isCanRunC()) { return runC(); } startDoNotC(); default: startDoDefault(runType); return runDefault(); } }
- Part Code Ⅱ
public Result run(RunTypeEnum runType) switch(runType) { case A: return runA(); case B: if (configService.isCanRunB()) { return runB(); } startDoNotB(); break; case C: if (configService.isCanRunC()) { return runC(C); } startDoNotC(); break; default: startDoDefault(runType); break; } return runDefault(); }
以上两段代码翻译成 if else 如下:
- Part Code Ⅰ Result
public Result run(RunTypeEnum runType) if (runType == A) { return runA(); } if (runType == B) { if (configService.isCanRunB()) { return runB(); } startDoNotB(); // 虽然不等于 C,但是还是会跑 C 块的代码 if (configService.isCanRunC()) { return runC(); } startDoNotC(); } if (runType == C) { if (configService.isCanRunC()) { return runC(); } startDoNotC(); } startDoDefault(runType); return runDefault(); }
- Part Code Ⅱ Result
public Result run(RunTypeEnum runType) if (runType == A) { return runA(); } else if (runType == B) { if (configService.isCanRunB()) { return runB(); } startDoNotB(); } else if (runType == C) { if (configService.isCanRunC()) { return runC(); } startDoNotC(); } startDoDefault(runType); return runDefault(); }
总结分析
- 使用 switch 的时候一定要注意使用 return 或 break 中断,否则一旦匹配上,会顺延执行每个 case 块里面的代码
- 正常情况下我们需要使用多 case 匹配一个代码块,则需要用到这个顺延执行的特效,而不是使用 if (exp1 || exp2 || exp3 …) {do…}。
switch (type) { case A: return doA(); case B1: case B2: case B3: return doB(); case C: case D: return doNotAB(); default: return doNothiong(); }
- 深入思考:是否可以更加深入使用这个顺延模式
面向函数编程 of 职责链模式
我们先来看看面向对象的职责链模式(伪代码):
某个审批流程 A,当申请员工等级为 Lvx 时候,需要 Lvx-1 的所有人审批,最后由系统自动审批。
已知共有 5 个级别,每个级别审批需要做不同的事。
class SpSystemOfA {
public void doSp() {
sout("system auto done :{}!", sys?.do());
}
}
class SpLv1OfA extends SpSystemOfA {
public void doSp() {
sout("lv1 done :{}!", lv1?.do());
super.doSp();
}
}
class SpLv2OfA extends SpLv1OfA {
public void doSp() {
sout("lv2 done :{}!", lv2?.do());
super.doSp();
}
}
class SpLv3OfA extends SpLv2OfA {
public void doSp() {
sout("lv3 done :{}!", lv3?.do());
super.doSp();
}
}
class SpLv4OfA extends SpLv3OfA {
public void doSp() {
sout("lv4 done :{}!", lv4?.do());
super.doSp();
}
}
psvm(args[]) {
SpSystemOfA spLvxOfA = getSpOfAByLv(staff.Lv);
spLvxOfA.doSp();
}
- 职责链模式会顺延执行父类的代码块,通常用于流程类业务,只要定义好流,就能形成很多复杂的审批模板或执行流模板。 PS:比如 工单审批/CI/DevOps
- 再通过 List、Map 集合去一对多封装,发散匹配形成更复杂的并行流、树形流、图形流等等。 PS:比如 脑图/路径分析/预测模拟
下面我们使用 switch 来模拟上面的设计模式(伪代码):
public static void doSp(lvx) {
case(lvx - 1) {
case Lv4:
sout("lv4 done :{}!", lv4?.do());
case Lv3:
sout("lv3 done :{}!", lv3?.do());
case Lv2:
sout("lv2 done :{}!", lv2?.do());
case Lv1:
sout("lv1 done :{}!", lv1?.do());
default:
sout("system auto done :{}!", sys?.do());
}
}
psvm(args[]) {
doSp(staff.Lv);
}
- 线性流 = switch 顺延 + 单线程
- 并行流/图形流 = switch 顺延 + 多线程控制 + 函数式接口传参
邀请标记你的阅读体验😉 | →