本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
什么是策略模式?
定义一系列算法,将每一个算法装起来,并让它们可以相互替换。策略模式让算法可以独立于使用它的客户变化。 又称为改策( Policy)模式。
实际业务场景
同一个消费组同一个topic下不同的tag原有代码业务,代码按照if else的方式实现,新增一个tag的时候需要修改if条件,对原有业务影响较大,违反【开闭原则】。
/**
* 消息监听
*
*/
@Slf4j
@Service
public class MQMessageListener implements MessageListener {
@Override
public Action consume(Message message, ConsumeContext context) {
String body = new String(message.getBody(), Charsets.UTF_8);
log.info("消息监听-start;消息体:{}", body);
// mq消息的tag
String tag = message.getTag();
// 原有代码逻辑
if ("tag1".equalsIgnoreCase(tag)) {
// tag1 的代码处理逻辑
handleMessage(businessType, saleFinishMessage);
}
// 原有代码逻辑
if ("tag2".equalsIgnoreCase(tag)) {
// tag2 的代码处理逻辑
handleMessage(businessType, saleFinishMessage);
}
// 原有代码逻辑
if ("tag3".equalsIgnoreCase(tag)) {
// tag3 的代码处理逻辑
handleMessage(businessType, saleFinishMessage);
}
// mq消息反馈
return Action.CommitMessage;
}
}
使用策略模式重构代码
设计类图
定义公共策略处理
/**
* @author MengyuWu
* @version 1.0.0
* @ClassName AbstractHandleStrategy.java
* @Description 抽象消息的策略
* @createTime 2022年07月19日 10:18:00
*/
@Slf4j
@Component
public abstract class AbstractHandleStrategy {
public abstract void execute(String body);
}
定义策略选择器
/**
* @author MengyuWu
* @version 1.0.0
* @ClassName StrategySelector.java
* @Description 销转采履约新系统 选择器
* @createTime 2022年07月19日 10:15:00
*/
@Slf4j
@Component
public class StrategySelector {
@Resource
private Map<String, AbstractHandleStrategy> strategyMap;
@Transactional(rollbackFor = Exception.class)
public void execute(String messageBody, String tag){
// 根据类型获取对应的策略类进行
AbstractSales2Strategy strategy = strategyMap.get(HandleStrategyEnum.getStrategyByTag(tag));
// 执行策略
strategy.execute(messageBody,bizId);
}
}
定义tag1、tag2、tag3的策略处理业务逻辑
/**
* @author MengyuWu
* @version 1.0.0
* @ClassName XXX1HandleStrategy.java
* @Description 策略1
* @createTime 2022年07月19日 10:53:00
*/
@Component("XXX1HandleStrategy")
@Slf4j
public class XXX1HandleStrategy extends AbstractHandleStrategy {
@Override
public void execute(String body,String bizId) {
// TODO tag1业务逻辑
}
}
/**
* @author MengyuWu
* @version 1.0.0
* @ClassName XXX2HandleStrategy.java
* @Description 策略2
* @createTime 2022年07月19日 10:53:00
*/
@Component("XXX2HandleStrategy")
@Slf4j
public class XXX2HandleStrategy extends AbstractHandleStrategy {
@Override
public void execute(String body,String bizId) {
// TODO tag2业务逻辑
}
}
/**
* @author MengyuWu
* @version 1.0.0
* @ClassName XXX3HandleStrategy.java
* @Description 策略3
* @createTime 2022年07月19日 10:53:00
*/
@Component("XXX3HandleStrategy")
@Slf4j
public class XXX3HandleStrategy extends AbstractHandleStrategy {
@Override
public void execute(String body,String bizId) {
// TODO tag3业务逻辑
}
}
message监听逻辑
/**
* @author MengyuWu
* @version 1.0.0
* @ClassName MQMessageListener.java
* @Description 消息监听
* @createTime 2022年07月19日 10:07:00
*/
@Slf4j
@Service
public class MQMessageListener implements MessageListener {
/**
* 新履约消息策略选择器
*/
@Autowired
private StrategySelector strategySelector;
@Override
public Action consume(Message message, ConsumeContext consumeContext) {
try {
String body = new String(message.getBody(), Charsets.UTF_8);
// mq消息的tag 用于区分正向和逆向消息
String tag = message.getTag();
// 执行策略选择器
StrategySelector.execute(body, sales2BizIdentity);
// mq消息反馈
return Action.CommitMessage;
} catch (Exception e) {
// 返回失败,自动重试
return Action.ReconsumeLater;
}
}
}
策略模式优缺点
优点
策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
策略模式提供了管理相关的算法族的办法。
策略模式提供了可以替换继承关系的办法。
使用策略模式可以避免使用多重条件转移语句。
缺点
客户端必须知道所有的策略类,并自行决定使用哪一个策略类。 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。