管道的归管道,策略的归策略(IF-ELSE
清除计划)
序
0202年,代码帝国IF-ELSE
模块越加庞大,严重影响了帝国的运行,使得系统不堪重负,于是帝国推出了IF-ELSE
清除计划,顿时,一场腥风血雨席卷了整个帝国,无数势力你方唱吧我登场,阴谋阳谋你来我去精彩纷呈,此时,一个叫做魔法海螺的组织提出了自己的见解,随着这个组织的出现,历史的车轮开始滚动了起来,岁月翻开了新的篇章
真序
咳咳,不扯了,不知道大家最近有没有在掘金刷到干掉IF-ELSE
的文章,各位大佬都针对各个场景提出了很好的方法,但是,作为一个CRUD-BOY
,我觉得策略模式其实适应场景是有限的,主要的原因有以下几点
- 策略模式重,重在以下几点
-
每个
IF-ELSE
都需要独立的处理策略,即单独实现类(就算是内部类开销也很大) -
方法簇
(所有的策略方法)需要钩子方法钩中自己处理的逻辑,主要有这些方式Map<String,Handler>
显性暴露钩子注解
便携式暴露钩子- 基于
SpringBeanName
侵入式暴露钩子 - ... 其他
-
涉及到策略分层时,策略方法之间的
相互嵌套回调
是灾难性的
- 策略模式在业务摇摆严重的场景下维护成本巨大
- 策略方法
输入输出固定
,增加一个参数都需要修改所有的方法簇 废弃的策略以及新增的策略
混杂一起,不敢随便修改和删除- 大量
重复代码
,虽然策略分层,但是实际业务会有大量重复的代码,抽了不够内聚
,不抽IDEA一片冒黄
- 作为
CRUD-BOY
我就是Diss策略模式(好的,这就是私货手动滑稽)
CRUD
场景策略模式写不动,也觉得没必要- 如果我接了策略模式的代码,在搞懂钩子,方法簇分布之前
我是不敢动的
,虽然后面改起来很爽 - 被需求,BUG追着跑的人不配写策略,对不起,我不配5555
真容
管道模式
,是在简单场景清理IF-ELSE的绝佳手段,大家在学习管道时,会不会感觉跟责任链
很像,但是我觉得是有区别的,为了方便大家区分,梳理一下
- 管道模式的每个管节有输入和输出,而Filter这种经典责任链主要还是上下文处理数据流转
- 管道的顺序是在各个管节拼接后体现的,拼接完管道后不可修改
- 复杂的管道模式是有Valve的,即阀门,可以控制不再往下流转
初探--极简管道
管道模式由来已久,但是管道模式其实也很复杂,会有Pipeline管道
、Context上下文
、Status状态
、Valve阀门
等,("▔□▔)那我为啥要选管道模式,掀桌了,这跟策略模式比较来根本毫无优点,还是一样一大团东西,混在一起,作为CRUD-BOY
我根本用不着,稍安勿躁,我们先搞搞简单的管道,让我们更简单易用
管节逻辑
public interface Step<IN, OUT> {
/**
* 管节处理逻辑
*
* @param input 管节输入
* @return OUT 管节输出
*/
OUT process(IN input);
}
管道逻辑
public class Pipeline<IN, OUT> {
/**
* 当前管节
*/
private Step<IN, OUT> current;
/**
* 此构造方法只用于初始化
* 头部管节 即第一个管节
*
* @param current 当前管节
*/
public Pipeline(Step<IN, OUT> current) {
this.current = current;
}
/**
* 拼接管节并返回新的管道
* 这里注意一下,返回的是完整的管道
* 即最顶部管节的输入,最底部管节的输出
* @param next 下一个管节
* @param <NEXT> 下一个管节的输出
* @return 拼接了下一个管节的管道
*/
public <NEXT> Pipeline<IN, NEXT> pipe(Step<OUT, NEXT> next) {
return new Pipeline<>(input -> next.process(current.process(input)));
}
/**
* 真实执行
* @param input 输入
* @return 输出
*/
public OUT execute(IN input) {
return this.current.process(input);
}
}
举个栗子
//头部管节
Pipeline<Integer, String> start = new Pipeline<>(input -> String.valueOf(input));
//继续增加管节
Pipeline<Integer, String> pipeline = start
.pipe(input -> Integer.parseInt(input) + 1)
.pipe(input -> Collections.singletonList(String.valueOf(input + 1)))
.pipe(input -> input.get(0));
//真实执行
String execute = pipeline.execute(1);
优点
这样的管道实现有没有让大家眼前一亮呢?没错,这就是非常简单的管道实现,没有实现类,没有上下文,没有开关,没有状态,只有简单的处理逻辑,所有的一切都是如此的简单,对我而言,就是我再写CRUD
时,IF-ELSE
少了,然后没有复杂的策略类需要管理,平常写写CRUD就很开心,不用再搞很多复杂的代码了
再探--函数式编程
如果以上代码在IDEA中打开,你会发现提示你改成Lambda格式,哦???然后当你打开Java8
的function包下面的**Function<T, R>**接口时,这就是见证奇迹的时刻,bing~~~~
R apply(T t);
花擦,这个好像一个管节,然后你会发现以下代码
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
("▔□▔),这不就是接管节的方法么,我果然是个CRUD-BOY
,人家早就实现了,你还在造轮子,关键造出来还没有别人秀,真的是没来由的一股忧伤,然后,让我们试试咋用呗
举一颗悲伤的栗子
//头部管节
Function<Integer, String> start = input -> String.valueOf(input);
//继续增加管节
Function<Integer, String> pipeline = start
.andThen(input -> Integer.parseInt(input) + 1)
.andThen(input -> Collections.singletonList(String.valueOf(input + 1)))
.andThen(input -> input.get(0));
//真实执行
String execute = pipeline.apply(1);
PPT式总结
咋样,看到这个代码是不是心怦怦跳,恨不得马上打开IDEA撸一波代码,感受酣畅淋漓的管道模式,也就是撸---管道模式,兄弟,不能污,要纯洁,纯洁的程序员才能写出碰触心灵的代码。。。不说了,请开心的写起来吧
程序员式总结
如果,你没有被我带歪的话,其实我们说的是IF-ELSE
清除计划,但是直到现在都没有说怎么清理IF-ELSE
,所以其实这篇文章相当于清理计划的前传,我会在下一篇文章里面,讲述怎么通过Java8
新特性Optional结合Function实现清理IF-ELSE
的计划,欢迎下次光临,谢谢惠顾,祝端午安康,阖家幸福!