策略模式实现监听同一个消费组同一个topic下不同的tag区分业务处理代码改造

121 阅读3分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

什么是策略模式?

定义一系列算法,将每一个算法装起来,并让它们可以相互替换。策略模式让算法可以独立于使用它的客户变化。 又称为改策( 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;
    }
}
​

使用策略模式重构代码

设计类图

image-20221130104351494

定义公共策略处理

/**
 * @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;
        }
    }
}
​

策略模式优缺点

优点

策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。

策略模式提供了管理相关的算法族的办法。

策略模式提供了可以替换继承关系的办法。

使用策略模式可以避免使用多重条件转移语句。

缺点

客户端必须知道所有的策略类,并自行决定使用哪一个策略类。 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。