设计模式之策略模式
一、策略模式是什么?
策略模式主要是用来解决代码里面的多重if判断问题的。我们知道设计模式需要对扩展开放,对修改关闭。而我们在写代码的时候进行了多重if判断不仅使代码的可读性非常差,而且在每次新增加一个内容就需要修改一次if判断对代码本身修改,违反了对修改关闭的原则。我们这个时候就需要使用策略模式
二、策略模式详解
1.策略模式组成
策略模式的主要角色:
- 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
- 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
- 环境(Context)类:持有一个策略类的引用,最终给客户端调用。
2.示例demo
首先简单举个例子:
例如我们在项目中需要用到聚合支付平台:阿里支付、微信支付等。目前的系统暂时只支持阿里支付和微信支付。
按照我们以前写代码的方式可能是这样的:
public Object pay(String payCode){
Object result = null;
if("aLi_pay".equals(payCode)){
result = toAliPay();
}else if("weChat_pay".equals(payCode)){
result = toWeChatPay();
}else if ("xiaoMi_pay".equals(payCode)){
result = toXiaoMiPay();
}
}
如果我们再增加一个银联支付的话需要再增加一个if判断。虽然看起来这种写法很简单而且容易理解没有什么问题,如果我们封装框架呢?使用者要扩展我们的支付渠道,我们不可能让使用者去修改我们的源代码增加一个if判断。所以这个时候我们就需要使用策略模式来实现。
这是使用策略模式的实现思路。定义父类支付策略接口,然后分别写阿里、微信、小米实现(都有一个Pay方法)。传入PayCode后,我们在方法中调用的是父类接口去执行Pay方法,而我们的父类对象的获取是在Context中根据Code去数据库(也可以使用枚举等方式)获取Bean的ID,然后在Spring容器中获取具体的实现类(使用了多态机制)。这种实现方式如果我们需要扩展银联支付的话需要写一个银联支付去实现支付接口,并且在数据库中增加银联支付的BeanId就可以了。用策略模式实现具有很好的扩展性,而且不用修改其他代码我们的支付策略代码也可以封装成一个jar包。
下面是伪代码实现:
数据库对象
@Data
public class PayChannel {
private String id;
/*传入标识代码*/
private Stirng payCode;
/*Spring容器的beanID*/
private String beanId;
/*是否开启使用*/
private String useFlag;
...
}
支付类
public interface PayStrategy {
/*支付方法*/
Object pay();
}
public class ALiPayStrategy implements PayStrategy {
@Override
public Object pay() {
/*调用阿里支付的操作*/
...
return null;
}
}
...微信支付、小米支付
下面是核心调用类
public class PayContextStrategy {
@Autowired
private PayChannelMapper payChannelMapper; /*数据库*/
@Autowired
private SpringcContextUtils springcContextUtils; /*Spring上下文加载类工具类,百度上有*/
public Object toPay(String payCode){
***代码中相关的空判断已省略
/*数据库查询对应的BeanID*/
String beanId = payChannelMapper.getBeanIdByPayCode(payCode);
/*通过容器获取对应的支付类*/
PayStrategy payStrategy = springcContextUtils.getBean(beanId,PayStrategy.class);
/*执行支付方法*/
return payStrategy.pay();
}
}
使用
public class PayController {
@Autowired
private PayContextStrategy payContextStrategy;
public Object toPay(String payCode){
/*相关空判断*/
...
return payContextStrategy.toPay(payCode);
}
}
总结
优点
- 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if…else 语句、switch…case 语句。
- 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
- 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
- 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
- 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
缺点
- 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
- 策略模式造成很多的策略类,增加维护难度。
画图工具使用的迅捷流程图,挺好用的终生会员价才38,大家可以看看。
https://www.liuchengtu.com/process