1、背景

  在你的项目中是否可以看到成堆if-else语句呢?我们来想象一下一个支付场景,用户下单时需要判断当前订单是否为优惠或团购或促销等,那你首先想到的是根据当前订单类型来匹配所有的订单类型,满足哪一种就走对应的处理是吗?就比如下面这样

如何干掉烦人的if-else

这样做是可以实现功能,但我上架了新的活动这时候有新类型订单又该怎么办呢?当然你可以再判断一次不就是嵌套一次if-else吗?在一个大型项目中这样做是致命的,不仅仅代码冗余,而且耦合极高,我这里还只是用伪代码示例,真实开发中可能有几十个甚至几百个if-else,可怕的是每个if-else中还包裹着复杂的业务逻辑代码。。。

2、策略模式

  什么是策略模式呢?使用策略模式解决了什么问题呢?还是用我们上面的例子来说明,如果使用了策略模式每种订单类型都会是一个单独的个体不会受到其他业务逻辑影响,这就解决了上面我们最头疼的如果有新的类型加入的话还需要嵌套的问题,其次你还可以玩一些有意思的比如使用AOP动态织入一些功能后面会介绍。

  先来张万年不变的UML,解释下Strategy为策略抽象类当然你也可以做成接口,它的目的就是抽取业务中公共资源为方法,本例中订单实体类即为业务资源因为所需要的订单类型以及订单其他信息都来源于此,而下面的具体策略A、B即为具体的实现,如团购类型的订单则执行团购策略普通类型订单则执行普通订单策略,因为都实现或继承了策略类因此两者完全解耦,相信大家最懵的就是环境类了,既然都解耦了为什么还需要环境类呢?想象一下现在业务时解除耦合了但是客户端(购买者)如何调用具体的策略呢?它怎么就知道该笔订单是什么类型呢?因此环境类必然会持有策略抽象类实例,有了环境就可以让客户端调用,整个流程就变成:客户端 —> 环境 —> 策略抽象类 —> 具体策略

如何干掉烦人的if-else

 

3、动手撸码

  考虑到该demo大家可以直接拿去使用,因此我们使用注解的方式进一步解耦,这样你可以通过数字类型直接匹配策略实现,如前端传1表示普通订单类型2表示团购订单,那么你只需要在你的团购订单策略实现类中加上注解就好。因此我们先来定义注解。

如何干掉烦人的if-else

先不着急解析注解,我们先把架子搞好,接下来我们将策略抽象类的接口定义出来

如何干掉烦人的if-else

进一步实现策略抽象类,这里以团购订单和普通订单为例,实际项目中可以自由扩展。

如何干掉烦人的if-else如何干掉烦人的if-else

接着是最为重要的环境类,重点为getInstance方法,如何自动选择对应的处理策略呢?其实很简单handlerMap中已经保存了所有标有注解的类已经注解中的值,有了这两个信息之后我们通过获取用户订单类型找到对应的策略类,当然实际上它是一个Bean,因此这里使用了BeanTool一个小工具类用于获取对应的策略Bean。

如何干掉烦人的if-else

如何干掉烦人的if-else

最后是最为重要的一步即:解析注解以及注解对应的类,将它们保存起来,然后提供给上面的HandlerContext调用

如何干掉烦人的if-else

实现了BeanFactoryPostProcessor接口之后我们就可以在Bean对象初始化前后进行拦截,那么要拦截什么呢?当然是我们的具体策略,每个用户的订单类型不同因此在真正进入到具体策略之前我们进行一次拦截,拦截的目的是我们先获取标有注解@OrderHandlerType的策略实现类,其次将用户的订单类型也进行解析,然后将其进行映射保存至Map中,最后将环境作为单例Bean注册到容器中,这样在HandlerContext中就可以使用这些信息,那么之前提到的自动选择呢?别急接着往下看

如何干掉烦人的if-else

现在我们的OrderService就成了这个样子,只需要将HandlerContext环境注入进来,然后调用获取实例的方法即可。我们来写一个测试Controller来演示下,我们以2个不同的端口启动来看效果

如何干掉烦人的if-else

如何干掉烦人的if-else 如何干掉烦人的if-else

项目已经发布至GitHub: https://github.com/wanghaord/noif-demo ,如果觉得有用请给个Star谢谢~

相关文章: