图示

1. 现状

场景: 假设设备上报不同类型的消息,我们要对不同类型的消息做不同的处理。如果我们通过if..else的方式处理的话会显得比较冗余。

例如:

if("alarmEvent".equals(msg)){
// 处理告警消息逻辑 ...
}else if("deviceBase".equals(msg)){
// 处理设备上报的基本信息 ...
}else if("heartBeat".equals(msg)){
// 处理设备心跳消息 ...
}else {
// ...
}

2. 消息处理Handler

那么对于不同消息的不同的处理逻辑我们可以单独放在一个实现类中,这些类有着相同的行为,所以我们可以定义一个接口:

public interface MessageHandler<T>{
T invoke(String bizUpMessage); // 处理接收到的消息
String getName();
String getIdentification(); // 获取消息标志
}

针对于不同的消息,我们可以有各自的实现

实现类1:

@Component
public class DeviceBaseInfoHandler implements MessageHandler<String> { @Override
public String invoke(String bizUpMessage) {
// 处理设备上报的基本信息 ...
return "";
} @Override
public String getName() {
return "";
} @Override
public String getIdentification() {
return "DeviceBaseInfoRequest";
}
}

实现类2:

@Component
public class AlarmEventHandler implements MessageHandler<String>{ @Override
public String invoke(String bizUpMessage) {
// 处理告警信息 ...
return null;
} @Override
public String getName() {
return "";
} @Override
public String getIdentification() {
return "AlarmEventRequest";
}
}

3. Handler注册处

我们可以将上一步的消息处理对象,根据消息的标志(Identification)不同,将消息放在一个Map中:

public class MessageHandlerRegisty {

    private Map<String, List<MessageHandler>> registerMap = new HashMap<>();

    // 注册各种 handler
public void regist(String identification, MessageHandler handler){
if(this.contains(identification)){
get(identification).add(handler);
} else {
List<MessageHandler> list = new ArrayList<>();
list.add(handler);
registerMap.put(identification, list);
}
} public boolean contains(String identification){
return registerMap.containsKey(identification);
} public List<MessageHandler> get(String identification){
return registerMap.get(identification);
}
}

4. 消息接收Service

消息接收接口

public interface IMessageService {
void messageReceived(String bizUpMessage); // 接收消息
}

5. 消息接收ServiceImpl

消息接收实现类

public class MessageServiceImpl implements IMessageService{

    public MessageHandlerRegisty registy;

    // 线程池
public ExecutorService executorService = new ThreadPoolExecutor(3, 10, 15, TimeUnit.MINUTES, new LinkedBlockingQueue(1000), new LogdDiscardPolicy()); public void messageReceived(String bizUpMessage){ // 获取消息的标志Identification
String identification = extractIdentification(bizUpMessage); if(StringUtils.isBlank(identification)){
return;
} if(!registy.contains(identification)){
return;
} for(MessageHandler handler : registy.get(identification)){
execute(handler, bizUpMessage); // 多线程处理消息
}
} public MessageHandlerRegisty getRegisty() {
return registy;
}
public void setRegisty(MessageHandlerRegisty registy) {
this.registy = registy;
} private void execute(MessageHandler handler, String bizUpMessage){
executorService.submit(new IotMessageTask(handler, bizUpMessage));
} public final class LogdDiscardPolicy extends ThreadPoolExecutor.DiscardPolicy {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
log.warn("MessageService pool is full !!!!!!!!");
}
} final class IotMessageTask implements Runnable { private MessageHandler handler;
private String bizUpMessage; public IotMessageTask(MessageHandler handler, String bizUpMessage){
this.handler = handler;
this.bizUpMessage = bizUpMessage;
} @Override
public void run() {
try {
Stopwatch stopwatch = Stopwatch.createStarted();
handler.invoke(bizUpMessage);
stopwatch = stopwatch.stop(); long cost = stopwatch.elapsed(TimeUnit.MICROSECONDS);
logTime(cost);
}catch (Exception e){
log.error("handler execute error - ", e);
}
} private void logTime(long cost){
if(cost > 50){
log.warn(" handler -> {}, cost too much -> {}", handler.getName(), cost);
} else {
log.info("handler -> {}, cost -> {}", handler.getName(), cost);
}
} } }

6. 将MessageServiceImpl对象配置到spring容器

@Configuration
public class ManagerConfig { @Bean
public IMessageService messageService(){
MessageServiceImpl messageService = new MessageServiceImpl();
messageService.setRegisty(buildRegisty());
return messageService;
} // 消息处理handler
@Autowired
private DeviceBaseInfoHandler deviceBaseInfoHandler;
@Autowired
private AlarmEventHandler alarmEventHandler; private MessageHandlerRegisty buildRegisty(){
MessageHandlerRegisty registy = new MessageHandlerRegisty();
registy.regist(deviceBaseInfoHandler.getIdentification(), deviceBaseInfoHandler);
registy.regist(alarmEventHandler.getIdentification(),alarmEventHandler); return registy;
}
}

策略模式+Spring配置类优化多if..else思路的更多相关文章

  1. Spring配置类理解(Lite模式和Full模式)

    Spring中的注解大家在开发中都常常用到,但是如果我说我们常常用的注解修饰了一个类,表示这个类就是一个配置类很多开发者都会有点迷糊了.具体配置类在开发中有什么样的用途我就不多说了,相信很多人都知道, ...

  2. Spring配置类为什么要分Full和Lite模式

    本文基于Spring 5.2.15-RELEASE 关于Spring配置类的Full模式和Lite模式,如果没有仔细阅读过源码或者官方文档的话,估计很多人都不知道这个概念.所以我们先来解释下这两个概念 ...

  3. Spring配置类深度剖析-总结篇(手绘流程图,可白嫖)

    生命太短暂,不要去做一些根本没有人想要的东西.本文已被 https://www.yourbatman.cn 收录,里面一并有Spring技术栈.MyBatis.JVM.中间件等小而美的专栏供以免费学习 ...

  4. 使用spring配置类代替xml配置文件注册bean类

    spring配置类,即在类上加@Configuration注解,使用这种配置类来注册bean,效果与xml文件是完全一样的,只是创建springIOC容器的方式不同: //通过xml文件创建sprin ...

  5. 521我发誓读完本文,再也不会担心Spring配置类问题了

    当大潮退去,才知道谁在裸泳.关注公众号[BAT的乌托邦]开启专栏式学习,拒绝浅尝辄止.本文 https://www.yourbatman.cn 已收录,里面一并有Spring技术栈.MyBatis.中 ...

  6. 简单工厂模式和策略模式结合使用php

    策略模式是有客户端自行实例化算法类的,而简单工厂模客户端只传参数,不关心对象的生成. 结合两种模式,可以在使用策略模式的时候客户端不再生成算法的对象.修改策略模式的配置类即可. 在之前策略模式基础上, ...

  7. 真懂Spring的@Configuration配置类?你可能自我感觉太良好

    当大潮退去,才知道谁在裸泳.关注公众号[BAT的乌托邦]开启专栏式学习,拒绝浅尝辄止.本文 https://www.yourbatman.cn 已收录,里面一并有Spring技术栈.MyBatis.中 ...

  8. 使用配置类而不使用XML文件(代替bean.xml)对spring进行配置

    以下类是一个配置类,它的作用和bean.xml是一样的注解: @Configuration 作用: 用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解. 获取容器时需要使用Anno ...

  9. 【Spring】简述@Configuration配置类注册BeanDefinition到Spring容器的过程

    概述 本文以SpringBoot应用为基础,尝试分析基于注解@Configuration的配置类是如何向Spring容器注册BeanDefinition的过程 其中主要分析了 Configuratio ...

  10. 【LabVIEW技巧】策略模式

    前言 在之前的文章提到了如何学习OOP以及对应的简单工厂模式,由于时间比较长,我们先回顾一下原有内容,然后继续了解新的模式. 为什么学习OOP 在测控系统的软件开发过程中,LabVIEW工程师一直认为 ...

随机推荐

  1. Java的初始化块

    三种初始化数据域的方法: 在构造器中设置值 在声明中赋值 初始化块(initialization block) 初始化块 在一个类的声明中,可以包含多个代码块.只要构造类的对象,这些块就会被执行. c ...

  2. IntelliJ IDEA一站式配置【全】(提高开发效率)

    IDEA常用设置(提高开发效率) 本人也是IDEA编译器的忠实用户了,但是有时出于各种原因,比如更换设备等等,IDEA总是需要重新安装配置.这就让我比较苦恼,因为总是记不全自己之前都修改了哪些地方(原 ...

  3. kafka生产者你不得不知的那些事儿

    前言 kafka生产者作为消息发送中很重要的一环,这里面可是大有文章,你知道生产者消息发送的流程吗?知道消息是如何发往哪个分区的吗?如何保证生产者消息的可靠性吗?如何保证消息发送的顺序吗?如果对于这些 ...

  4. 2023-05-24:为什么要使用Redis做缓存?

    2023-05-24:为什么要使用Redis做缓存? 答案2023-05-24: 缓存的好处 买啤酒和喝啤酒的例子可以帮助我们理解缓存的好处. 假设你在超市里买了一箱啤酒,如果你需要每次想喝啤酒就去超 ...

  5. 「高频面试题」Redis的持久化方式有哪些?

    RDB RDB(Redis DataBase)持久化是把当前Redis中全部数据生成快照保存在硬盘上.RDB持久化可以手动触发,也可以自动触发.save和bgsave命令都可以手动触发RDB持久化.除 ...

  6. ARC142

    ARC142 考试情况:一眼订正,鉴定为做出前三题. A - Reverse and Minimize 分析题目性质可得三种情况: \(K\) 末尾有 \(0\) 最多只有 \(K\) 本身一个答案. ...

  7. 【Python&RS】GDAL对栅格数据重采样/对齐栅格

            GDAL(Geospatial Data Abstraction Library)是一个在X/MIT许可协议下的开源栅格空间数据转换库.它利用抽象数据模型来表达所支持的各种文件格式.它 ...

  8. MAUI Blazor 项目实战 - 从0到1轻松构建多平台应用UI

    前言 最近在项目中尝鲜了MAUI,总体感受下来还是挺不错的,优缺点并存,但是瑕不掩瑜,目前随着.Net版本的迭代升级对它的支持也越来越友好,相信未来可期!感兴趣的朋友欢迎关注.文章中如有不妥的地方,也 ...

  9. 1.redis常见数据类型-字符串String、列表List、集合Set、Hash哈希、Zset有序集合

    背景: 这里说的数据类型是value的数据类型,key的类型都是字符串. 命令不区分大小写,而key的值是区分大小写的 help @+数据类型 会出现命令提示 比如 help@string,help@ ...

  10. 11. Mybatis的逆向工程

    正向工程:先创建 Java 实体类,由框架负责根据实体类生成数据库表. Hibernate 是支持正向工 程的. 逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源: Java 实体类 ...