文章目录
1. 策略模式介绍
策略模式是一种行为模式,也是替代大量if else
的利器(在项目设计中用的最多的)
一句总结就是: 定义一组算法类,将每个算法分别封装起来,让它们可以互相替换
举个例子🌰:
- 出行旅游: 乘坐飞机、乘坐火车、骑自行车、自己开私家车
- 交易方式: 信用卡、支付宝、微信
- 生成唯一ID策略: UUID、DB自增、DB+Redis、雪花算法、Leaf算法
上述场景都可以使用策略模式进行行为包装,供给外部使用
2. 策略模式的经典结构
- 上下文 (Context) 维护指向具体策略的引用, 且仅通过策略接口与该对象进行交流。
- 策略 (Strategy) 接口是所有具体策略的通用接口, 它声明了一个上下文用于执行策略的方法。
- 具体策略 (Concrete Strategies) 实现了上下文所用算法的各种不同变体。
- 客户端 (Client) 会创建一个特定策略对象并将其传递给上下文。 上下文则会提供一个设置器以便客户端在运行时替换相关联的策略。当上下文需要运行算法时, 它会在其已连接的策略对象上调用执行方法。 上下文不清楚其所涉及的策略类型与算法的执行方式。
图片来源:https://refactoringguru.cn/design-patterns/strategy
3. 优惠场景实战
3.1 面向过程开发
从头写到尾, 后续有新的优惠活动则继续添加新的if分支, 这种做法随着功能的不断累积, 往往会导致代码结构的复杂化, 进而使得整个系统变得难以维护和扩展。
3.2 使用策略模式改造代码
-
定义抽象策略接口
-
定义具体策略类
-
定义策略工厂
-
Service层调用获取折扣后的价格
3.3 上述实现的优点
- 将原本方法中的
if
语句优化掉 - 定义策略工厂,封装创建策略实现(算法),对客户端屏蔽具体的创建细节
- 有更好的隔离性与和扩展性
3.4 上述实现的缺点
- 添加一个策略算法实现,需要改动策略工厂中的代码,不符合开闭原则。
4. 使用 Spring 改造代码
要解决 3.4 中的缺点, 仅需将 static 代码块中消除即可。
可以使用 Spring 的特性实现, 使用ApplicationContext.getBeansOfType(Class<T> type)
来获取容器中所有指定类型的Bean, 这样 map 中的值就有了, 而键则需要具体策略类来指定。
1. 改造抽象接口
- 抽象策略接口中,新定义了
key()
接口,此接口用来标示算法的唯一性
2.改造实现类
- 具体策略实现类,使用
@Component
修饰,将对象本身交由 Spring 进行管理
3. 改造策略工厂
通过 InitializingBean
接口实现中调用 IOC 容器查找对应策略实现,随后将策略实现 key()
方法返回值作为 key, 策略实现本身作为 value 添加到 Map 容器中等待客户端的调用。
其中 DiscountStrategy
中所有具体策略实现类如下, 分别是95折策略和99折策略。
这样就通过 Spring 的一些特性同时满足了开闭原则
后续添加具体策略类, 仅需实现DiscountStrategy
接口即可, 不需要有额外的操作
这样就通过 Spring 的一些特性同时满足了开闭原则
若想要进一步优化代码, 可以使用枚举类作为 key()
中的返回值, 作为 map 中的 key 能更方便阅读更优雅