来看看如何使用策略模式干掉讨厌的 if else
干掉if else常用策略模式!其实就是抽取一个抽象类,然后根据类型指定不同的实现类执行方法。你学废了吗?
需求
这里虚拟一个业务需求,让大家容易理解。假设有一个订单系统,里面的一个功能是根据订单的不同类型作出不同的处理。
订单实体:
service接口:
传统实现
根据订单类型写一堆的if else:
策略模式实现
利用策略模式,只需要两行即可实现业务逻辑:
可以看到上面的方法中注入了HandlerContext,这是一个处理器上下文,用来保存不同的业务处理器,具体在下文会讲解。我们从中获取一个抽象的处理器AbstractHandler,调用其方法实现业务逻辑。
现在可以了解到,我们主要的业务逻辑是在处理器中实现的,因此有多少个订单类型,就对应有多少个处理器。以后需求变化,增加了订单类型,只需要添加相应的处理器就可以,上述OrderServiceV2Impl完全不需改动。
我们先看看业务处理器的写法:
首先每个处理器都必须添加到spring容器中,因此需要加上@Component注解,其次需要加上一个自定义注解@HandlerType,用于标识该处理器对应哪个订单类型,最后就是继承AbstractHandler,实现自己的业务逻辑。
自定义注解 @HandlerType:
抽象处理器 AbstractHandler:
自定义注解和抽象处理器都很简单,那么如何将处理器注册到spring容器中呢?
具体思路是:
1、扫描指定包中标有@HandlerType的类;
2、将注解中的类型值作为key,对应的类作为value,保存在Map中;
3、以上面的map作为构造函数参数,初始化HandlerContext,将其注册到spring容器中;
我们将核心的功能封装在HandlerProcessor类中,完成上面的功能。
HandlerProcessor:
ClassScanner:扫描工具类源码
HandlerProcessor需要实现BeanFactoryPostProcessor,在spring处理bean前,将自定义的bean注册到容器中。
核心工作已经完成,现在看看HandlerContext如何获取对应的处理器:
HandlerContext:
BeanTool:获取bean工具类
#getInstance
方法根据类型获取对应的class,然后根据class类型获取注册到spring中的bean。
最后请注意一点,HandlerProcessor和BeanTool必须能被扫描到,或者通过@Bean的方式显式的注册,才能在项目启动时发挥作用。
总结
利用策略模式可以简化繁杂的if else代码,方便维护,而利用自定义注解和自注册的方式,可以方便应对需求的变更。本文只是提供一个大致的思路,还有很多细节可以灵活变化,例如使用枚举类型、或者静态常量,作为订单的类型,相信你能想到更多更好的方法。
策略模式介绍
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
介绍
**意图:**定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
**主要解决:**在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
**何时使用:**一个系统有许多许多类,而区分它们的只是他们直接的行为。
**如何解决:**将这些算法封装成一个一个的类,任意地替换。
**关键代码:**实现同一个接口。
应用实例:
-
1、诸葛亮的锦囊妙计,每一个锦囊就是一个策略。
-
2、旅行的出游方式,选择骑自行车、坐汽车,每一种旅行方式都是一个策略。
-
3、JAVA AWT 中的 LayoutManager。
优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。
使用场景:
- 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 2、一个系统需要动态地在几种算法中选择一种。
- 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
**注意事项:**如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。