策略模式+Spring配置類優化多if..else思路

来源:https://www.cnblogs.com/charlton/archive/2023/07/28/17586887.html
-Advertisement-
Play Games

## 圖示 ![image](https://img2023.cnblogs.com/blog/1866596/202307/1866596-20230728101801138-171904977.png) ## 1. 現狀 > 場景: 假設設備上報不同類型的消息,我們要對不同類型的消息做不同的處理 ...


圖示

image

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;
    }
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • [TOC] # 前言 做嵌入式的上位機開發需要要用到Qt的,Qt是一個開源、跨平臺的程式和UI開發框架。我們使用Qt可以用Python或者C++進行開發,這裡我使用的全部都是C++,不涉及到Python。 # 一、Qt安裝 要學習Qt前先得學習一下如何安裝Qt,這裡安裝的是QtIDE,是Qt的集成開 ...
  • `json.load()`和`json.loads()`都是Python標準庫`json`模塊中用於處理JSON數據的方法,二者的作用都是將JSON數據轉換為Python數據類型,它們之間的區別如下: ### 1. `json.load()`是從文件中讀取JSON數據 `json.load()`用於 ...
  • # 批處理 - **基本介紹:** 1. 當需要成批插入或者更新記錄時。可以採用Java的批量更新機制,這一機制允許多條語句一次性提交給資料庫批量處理。通常情況下比單獨提交處理更有效率。 2. JDBC的批量處理語句包括下麵方法: - addBatch():添加需要批量處理的SQL語句或參數; - ...
  • 公眾號服務號每個月只能群發推送四次文章,我們可以使用模板消息為公眾號粉絲推送信息 下麵是使用golang實現的模板消息發送類庫封裝,輕鬆實現模板消息發送 wechat.go package lib import ( "github.com/silenceper/wechat/v2" "github. ...
  • ## 教程簡介 Drupal是使用PHP語言編寫的開源內容管理框架(CMF),它由內容管理系統(CMS)和PHP開發框架(Framework)共同構成,在GPL2.0及更新協議下發佈。連續多年榮獲全球最佳CMS大獎,是基於PHP語言最著名的WEB應用程式。截止2011年底,共有13,802位WEB專 ...
  • CompletableFuture對象是JDK1.8版本新引入的類,這個類實現了兩個介面,一個是Future介面,一個是CompletionStage介面。 ...
  • 前言 需求背景: 業務系統需要做EXCEL的導入和導出功能,某些欄位是系統字典值,改造之前只能應用@Excel註解的combo屬性來做下拉限制,用readConverterExp屬性來做表達式實際值和顯示值的轉換。 每當運維人員在系統增加一個字典值的時候,都要來修改代碼,太麻煩了。 期望效果: 能夠 ...
  • var Edit: TComponent;begin Edit := FindComponent("Edit1"); If Edit is TEdit then TEdit(Edit).Text := '你好 Delphi7';end; RTTI(RunTime Type Information): ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...