图示

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. Spring Boot 整合邮件服务

    参考教程 首先参考了 Spring Boot整合邮件配置,这篇文章写的很好,按照上面的操作一步步走下去就行了. 遇到的问题 版本配置 然后因为反复配置版本很麻烦,所以参考了 如何统一引入 Spring ...

  2. 一文吃透Tomcat核心知识点

    架构 首先,看一下整个架构图.最全面的Java面试网站 接下来简单解释一下. Server:服务器.Tomcat 就是一个 Server 服务器. Service:在服务器中可以有多个 Service ...

  3. Maven工程开发

    Maven工程开发 编写pom.xml配置文件 <properties></properties>定义项目的基本信息 groupId 反向域名,定义项目组名 artifactI ...

  4. 【Python基础】数据类型与类型转换

    五种基本数据类型 在 Python 中,基本数据类型是指不可变对象的数据类型.以下是 Python 中的基本数据类型: 整数类型(int):表示整数,例如 1.2.3 等等. 浮点数类型(float) ...

  5. ASP.NET Response.Filter

    寫 ASP.NET 有時候會想要在畫面輸出前一刻進行攔截,並換掉 html 中的特定字元.例如網站中有許多頁面都有 www.google.com.tw 的超連結,我希望在測試機上可以把連結換成 www ...

  6. 2023-03-27:avio_list_dir.c 是 FFmpeg 库自带的一个示例程序,它提供了列出目录中所有文件和子目录的功能,请用go语言改写。

    2023-03-27:avio_list_dir.c 是 FFmpeg 库自带的一个示例程序,它提供了列出目录中所有文件和子目录的功能,请用go语言改写. 答案2023-03-27: 这段代码实现了通 ...

  7. vue全家桶进阶之路4:NPM包

    NPM(Node Package Manager)是 Node.js 的包管理工具,用来安装各种 Node.js 的扩展. NPM是 JavaScript 的包管理工具,也是世界上最大的软件注册表.有 ...

  8. yaml的读写

    yaml文件的读写是真的快,也很简单.代码如下:from ruamel.yaml import YAMLimport os # 读取yaml配置文件def read_yaml(yaml_path): ...

  9. Charles抓包补充解释

    配置 大佬的博客真的很详细很详细,我就不重复造轮子了,第一次直接看大佬的博客就好,这里Python爬取微信小程序(Charles) 补充解释 在这一步疑问很多,大佬说的不是很详细,就由我来补充下吧~ ...

  10. 【Java】Eclipse常用快捷键整理

    前言 还是最近在上Java课,由于疫情原因,看的网课,那里的老师比较实战派,很多时候不知道按了什么快捷键就立马出现了很骚的操作.网上查询后发现了一些快捷键对于我这个eclipse小白还是挺常用的,整理 ...