策略模式(Strategy Pattern)定义了一组同类型的算法,在不同的类中封装起来,每种算法可以根据当前场景相互替换,从而使算法的变化独立于使用它们的客户端(即算法的调用者)。
image.png
场景:
重构前代码:根据账单类型,调用不同的业务逻辑
BillInfo info = 账单信息
if(StringUtils.equals(info.getType(),"补账")){
}else if(StringUtils.equals(info.getType(),"挂账")){
}else if(StringUtils.equals(info.getType(),"赔付")){
}else if(...){
}
以上代码虽然书写简单,但违反了单一职责原则和开闭原则
单一职责原则:如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。
开闭原则:对扩展开放,对修改关闭
以后若要进行类型的扩展,需要修改这段主逻辑
策略模式是解决过多 if-else(或者 switch-case) 代码块的方法之一,提高代码的可维护性、可扩展性和可读性。
1.策略的定义
public interface BillStrategy {
/**
* 处理账单信息
*
* @param info 入参
*/
void handle(BillInfo info);
}
2.策略接口的实现,
每种账单类都实现了上述接口(基于接口而非实现编程),这样我们可以灵活的替换不同的业务逻辑。
/**
* 挂账策略类实现
*/
@Component
@RequiredArgsConstructor
public class BillOutstandingStrategyImpl implements BillStrategy {
private final BillBiz billBiz;
@Override
public void handle(BillInfo info) {
//校验入参
ValidationUtil.validate(info);
//业务逻辑
billBiz.handle(info)
}
}
3.策略的配置
/**
* 策略配置类
*/
@Component
@RequiredArgsConstructor
public class BillStrategyFactory implements InitializingBean {
private final List<BillStrategy> allHandler;
private final Map<BillEnum.BillRemedyType, BillStrategy> delegateMap;
public BillStrategy getStrategy(BillEnum.BillRemedyType type) {
if (Objects.isNull(type)) {
throw new BusinessException(ErrorCode.PCSC_0041);
}
if (!delegateMap.containsKey(type)) {
throw new BusinessException(ErrorCode.PCSC_0041);
}
return delegateMap.get(type);
}
@Override
public void afterPropertiesSet() {
configStrategy(BillEnum.BillRemedyType.挂账, BillOutstandingStrategyImpl.class);
configStrategy(BillEnum.BillRemedyType.补账, Bill...StrategyImpl.class);
configStrategy(BillEnum.BillRemedyType.赔付, Bill...StrategyImpl.class);
}
/**
* 配置挂补类型,策略的对应关系
*
* @param type 类型
* @param strategyClass 策略实现类
* @param <T> T
*/
private <T> void configStrategy(BillEnum.BillRemedyType type, Class<T> strategyClass) {
delegateMap.put(type, getStrategyByName(strategyClass.getSimpleName()));
}
/**
* 根据策略类名称,获取实现类
*
* @param simpleName 名称
* @return 实现类
*/
private BillStrategy getStrategyByName(String simpleName) {
return allHandler.stream()
.filter(item -> StringUtils.equals(simpleName, item.getClass().getSimpleName()))
.findFirst()
.orElse(null);
}
}
4.策略的使用
@Resource
private BillStrategyFactory billStrategyFactory;
billStrategyFactory
.getStrategy(billInfo.getType())
.handle(billInfo);
以上,接口类只负责业务策略的定义,每个策略的具体实现单独放在实现类中,工厂类 Factory 只负责获取具体实现类,而具体调用代码则负责业务逻辑的编排。这些实现用到了面向接口而非实现编程,满足了职责单一、开闭原则,从而达到了功能上的高内聚低耦合、提高了可维护性、扩展性以及代码的可读性。
后续类型扩展,只需要新增具体的业务实现类,在配置工厂进行配置即可,如果要进行灵活配置,可将配置工厂中的对应关系,放置到Apollo配置中心,即可完成灵活配置.