管道的归管道,策略的归策略(IF-ELSE清除计划)

1,928 阅读6分钟

管道的归管道,策略的归策略(IF-ELSE 清除计划)

0202年,代码帝国IF-ELSE模块越加庞大,严重影响了帝国的运行,使得系统不堪重负,于是帝国推出了IF-ELSE清除计划,顿时,一场腥风血雨席卷了整个帝国,无数势力你方唱吧我登场,阴谋阳谋你来我去精彩纷呈,此时,一个叫做魔法海螺的组织提出了自己的见解,随着这个组织的出现,历史的车轮开始滚动了起来,岁月翻开了新的篇章

真序

咳咳,不扯了,不知道大家最近有没有在掘金刷到干掉IF-ELSE的文章,各位大佬都针对各个场景提出了很好的方法,但是,作为一个CRUD-BOY,我觉得策略模式其实适应场景是有限的,主要的原因有以下几点

  1. 策略模式重,重在以下几点
  • 每个IF-ELSE都需要独立的处理策略,即单独实现类(就算是内部类开销也很大)

  • 方法簇(所有的策略方法)需要钩子方法钩中自己处理的逻辑,主要有这些方式

    • Map<String,Handler>显性暴露钩子
    • 注解便携式暴露钩子
    • 基于SpringBeanName侵入式暴露钩子
    • ... 其他
  • 涉及到策略分层时,策略方法之间的相互嵌套回调是灾难性的

  1. 策略模式在业务摇摆严重的场景下维护成本巨大
  • 策略方法输入输出固定,增加一个参数都需要修改所有的方法簇
  • 废弃的策略以及新增的策略混杂一起,不敢随便修改和删除
  • 大量重复代码,虽然策略分层,但是实际业务会有大量重复的代码,抽了不够内聚,不抽IDEA一片冒黄
  1. 作为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格式,哦???然后当你打开Java8function包下面的**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的计划,欢迎下次光临,谢谢惠顾,祝端午安康,阖家幸福!