Spring使用设计模式优化你的代码-策略设计模式

1 业务场景

假设有这样的业务场景,MQ把消息推送过来,根据不同类型采取不同的解析 方式。多数的小伙伴就会写出以下的代码:

f(type=="A"){
   //按照A格式解析
 
}else if(type=="B"){
    //按B格式解析
}else{
    //按照默认格式解析
}

这个代码可能会存在哪些问题呢

  • 如果分支变多,这里的代码就会变得臃肿,难以维护,可读性低
  • 如果你需要接入一种新的解析类型,那只能在原有代码上修改

说得专业一点的话,就是以上代码,违背了面向对象编程的开闭原则 以及单一原则

  • 开闭原则 (对于扩展是开放的,但是对于修改是封闭的):增加或者删除某个逻辑,都需要修改到原来代码
  • 单一原则 (规定一个类应该只有一个发生变化的原因):修改任何类型的分支逻辑代码,都需要改动当前类的代码。

如果你的代码就是酱紫:有多个if...else等条件分支,并且每个条件分支,可以封装起来替换的,我们就可以使用策略模式 来优化。

2 策略模式定义

策略模式 定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的的客户。这个策略模式的定义是不是有点抽象呢?那我们来看点通俗易懂的比喻:

假设你跟不同性格类型的小姐姐约会,要用不同的策略,有的请电影比较好,有的则去吃小吃效果不错,有的去逛街买买买最合适。当然,目的都是为了得到小姐姐的芳心,请看电影、吃小吃、逛街就是不同的策略。

策略模式针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。

3 策略模式的使用

策略模式怎么使用呢?酱紫实现的:

  • 一个接口或者抽象类,里面两个方法(一个方法匹配类型,一个可替换的逻辑实现方法)
  • 不同策略的差异化实现(就是说,不同策略的实现类)
  • 使用策略模式

3.1 一个接口,两个方法

/**
 * 消息上报接口
 *
 * @author lyl
 * @version 2021/11/18 09:15:45
 */
public interface IMessageStrategy {

    /**
     * 属于哪种消息解析类型
     *
     * @return .
     */
    MessageTypeOperationEnum gainMessageType();

    /**
     * 业务参数方法
     *
     * @param response 消息参数
     */
    void operation(Object objectParam);
}

3.2 定义消息类型

/**
 * 消息通知类型
 *
 * @author lyl
 * @version 2021/11/18 09:21:57
 */
@Getter
@AllArgsConstructor
public enum MessageTypeOperationEnum {

    //消息通知类型

    ALARM("1", "告警上报"),
    FAULT("2", "故障修复上报"),
    HEART_BEAT("3", "心跳上报");

    private String code;

    private String message;

    public static MessageTypeOperationEnum match(String key) {
        MessageTypeOperationEnum result = null;
        for (MessageTypeOperationEnum s : values()) {
            if (key.equals(s.getCode())) {
                result = s;
                break;
            }
        }
        return result;
    }

    public static MessageTypeOperationEnum catchMessage(String msg) {
        MessageTypeOperationEnum result = null;
        for (MessageTypeOperationEnum s : values()) {
            if (s.getMessage().equals(msg)) {
                result = s;
                break;
            }
        }
        return result;
    }
}

3.3 策略的差异化实现

A 类型消息策略具体实现

@Slf4j
@Component
@AllArgsConstructor
public class HeartBeatOperation implements IMessageStrategy {
    @Override
    public MessageTypeOperationEnum gainMessageType() {
        return MessageTypeOperationEnum.HEART_BEAT;
    }

    @Override
    public void operation(Object objectParam) {
        logger.info("A 类型消息解析,参数:{}",objectParam);
		//心跳消息的具体处理业务
    }
}

B 类型消息策略具体实现

@Slf4j
@Component
@AllArgsConstructor
public class AlarmOperation implements IMessageStrategy {
    @Override
    public MessageTypeOperationEnum gainMessageType() {
        return MessageTypeOperationEnum.HEART_BEAT;
    }

    @Override
    public void operation(Object objectParam) {
        logger.info("B 类型消息解析,参数:{}",objectParam);
		//告警消息的具体处理业务
    }
}

C 类型消息策略具体实现

@Slf4j
@Component
@AllArgsConstructor
public class FaultOperation implements IMessageStrategy {
    @Override
    public MessageTypeOperationEnum gainMessageType() {
        return MessageTypeOperationEnum.HEART_BEAT;
    }

    @Override
    public void operation(Object objectParam) {
        logger.info("C 类型消息解析,参数:{}",objectParam);
		//故障上报消息的具体处理业务
    }
}

3.4 使用策略模式

/**
 * 消息策略封装
 *
 * @author lyl
 * @version 2021/11/18 10:42:54
 */
@Component
public class StrategyMessageService implements ApplicationContextAware {

    private Map<MessageTypeOperationEnum, IMessageStrategy> iMessageStrategyMap = new ConcurrentHashMap<>();

    /**
     * 使用消息策略,改方提供给需要使用测试的业务调用,然后会改方法会根据具体的消息类型,调用具体策略实现
     *
     * @param messageTypeOperationEnum 消息类型
     * @param queueResponse            消息参数
     */
    public void operation(MessageTypeOperationEnum messageTypeOperationEnum, OuterSouthRestResponse<OuterResponseSouthData> queueResponse) {
        IMessageStrategy iMessageStrategy = iMessageStrategyMap.get(messageTypeOperationEnum);
        if (iMessageStrategy != null) {
            //使用策略模式调用,这样就走具体策略方法
            iMessageStrategy.operation(queueResponse);
        }
    }

    /**
     * 策略封装
     *
     * @param applicationContext .
     * @throws BeansException .
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, IMessageStrategy> tempMap = applicationContext.getBeansOfType(IMessageStrategy.class);
        tempMap.values().forEach(strategyService -> iMessageStrategyMap.put(strategyService.gainMessageType(), strategyService));
    }
}

3.5 具体的业务调用


/**
 * 消息监听业务
 *
 * @author lyl
 * @version 2021/4/5 0005 11:45:10
 */
@Slf4j
@Component
public class MessageListener {

    @Autowired
    private StrategyMessageService strategyMessageService;

    /**
     * 告警上报
     *
     * @param message 。
     * @param channel 。
     * @throws IOException 。
     */
    @RabbitListener(queues = MqConstant.REPORT)
    public void alarmQueues(Message message, Channel channel) throws IOException {
   		strategyMessageService.operation(MessageTypeOperationEnum.ALARM,message)
    }

    /**
     * 故障修复
     *
     * @param message 。
     * @param channel 。
     * @throws IOException 。
     */
    @RabbitListener(queues = MqConstant.OPEN)
    public void faultQueues(Message message, Channel channel) throws IOException {
        strategyMessageService.operation(MessageTypeOperationEnum.FAULT,message)
    }


    /**
     * 心跳上报
     *
     * @param message 。
     * @param channel 。
     * @throws IOException 。
     */
    @RabbitListener(queues = MqConstant.HEARTBEAT)
    public void heartBeatQueues(Message message, Channel channel) throws IOException {
         strategyMessageService.operation(MessageTypeOperationEnum.HEART_BEAT,message)
    }
}

如果在操作中遇到问题可以通过公众号留言,希望能能够帮住你解决。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值