策略
这在项目中多处使用。例如:后台活动商品冲突功能,小程序多支付渠道选择。
定义
顾名思义,策略模式(Strategy Pattern)定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。
什么时候使用它
一个模块有许多类,而区分它们的只是行为。
优缺点
优点:
- 算法可以自由切换。
- 避免使用多重条件判断。
- 扩展性良好。
缺点:
- 策略类会增多。
- 所有策略类都需要对外暴露。
核心实现
- 环境(Context)
维护一个对策略对象的引用,负责将客户端请求委派给具体的策略对象执行。环境类可以通过依赖注入、简单工厂等方式来获取具体策略对象。
- 抽象策略(Abstract Strategy)
定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法。
- 具体策略(Concrete Strategy)
实现了抽象策略定义的接口或抽象类,包含了具体的算法实现。
示例
需求是,小程序端支付将会提供多种支付渠道供选择。
先来定义一个环境(Context):
java
/**
* 抽象策略工厂
*
* @author mjyang
* @date 2023/5/23 17:03
*/
@Component
public class AbstractStrategyFactory implements CommandLineRunner {
/**
* 策略集合
*/
private final Map<String, AbstractStrategy> abstractStrategyHashMap = MapUtil.newHashMap();
/**
* 根据 mark 获取具体策略
*
* @param mark 策略标识
* @return 实际执行策略
*/
public AbstractStrategy get(String mark) {
return Optional.ofNullable(abstractStrategyHashMap.get(mark)).orElseThrow(() -> new RuntimeException(String.format("%s 策略未定义", mark)));
}
/**
* 根据 mark 查询具体策略并执行
*
* @param mark 策略标识
* @param t 策略入参
* @param <T> 策略入参范型
*/
public <T> void execute(String mark, T t) {
AbstractStrategy strategy = get(mark);
strategy.execute(t);
}
/**
* 根据 mark 查询具体策略并执行,带返回结果
*
* @param mark 策略标识
* @param t 策略入参
* @param <T> 策略入参范型
* @param <R> 策略出参范型
* @return <R>
*/
public <T, R> R executeResp(String mark, T t) {
AbstractStrategy strategy = get(mark);
return (R) strategy.executeResp(t);
}
@Override
public void run(String... args) {
Map<String, AbstractStrategy> strategyMap = SpringUtil.getBeansOfType(AbstractStrategy.class);
strategyMap.forEach((beanName, bean) -> {
if (abstractStrategyHashMap.containsKey(bean.mark())) {
throw new RuntimeException(String.format("%s duplicate execution policy", bean.mark()));
}
abstractStrategyHashMap.put(bean.mark(), bean);
});
}
}
再来定义抽象策略(Abstract Strategy):
java
/**
* 策略抽象接口
*
* @author mjyang
* @date 2023/5/23 17:03
*/
public interface AbstractStrategy<T, R> {
/**
* 策略标识
*
* @return 策略标识
*/
String mark();
/**
* 执行策略
*
* @param t 策略入参
*/
default void execute(T t) {
}
/**
* 执行策略,带返回值
*
* @param t 策略入参
* @return 策略后返回值
*/
default R executeResp(T t) {
return null;
}
}
再来定义具体策略(Concrete Strategy):
java
/**
* 微信支付类
*
*/
public class WxPayService implements AbstractStrategy<PayRequestDto, Void> {
@Override
public String mark() {
return "wx_pay";
}
@Override
public void execute(PayRequestDto dto) {
...
}
}
java
/**
* 支付宝支付类
*
*/
public class AlipayPayService implements AbstractStrategy<PayRequestDto, Void> {
@Override
public String mark() {
return "alipay_pay";
}
@Override
public void execute(PayRequestDto dto) {
...
}
}
接下来就是客户端调用了:
java
public static void main(String[] args) {
SpringUtil.getBean(AbstractStrategyFactory.class).get("wx_pay");
}
以上这个示例是一个通用策略,通过这个简单的示例,演示了如何来使用策略模式。