業務事件模型的實現

来源:http://www.cnblogs.com/jietang/archive/2016/03/20/5298985.html
-Advertisement-
Play Games

在實際業務開發過程中,很經常應用到觀察者模式。大致的處理流程是說在模塊初始化的時候,註冊若幹觀察者,然後它們處理自己感興趣的內容。當某一個具體的事件發生的時候,遍歷觀察者隊列,然後”觀察者“們就根據之前約定的具體情況,處理自己關註的事件。其實觀察者模式本人認為更確切的說法應該是:事件通知模型。那麼現


  在實際業務開發過程中,很經常應用到觀察者模式。大致的處理流程是說在模塊初始化的時候,註冊若幹觀察者,然後它們處理自己感興趣的內容。當某一個具體的事件發生的時候,遍歷觀察者隊列,然後”觀察者“們就根據之前約定的具體情況,處理自己關註的事件。其實觀察者模式本人認為更確切的說法應該是:事件通知模型。那麼現在,我們就用傳統的Java語言來實現一下(具體可以查看代碼的註釋,寫的挺詳細了)。

  業務事件定義如下:

/**
 * @filename:BusinessEvent.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:業務事件定義
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.businessevent;

public class BusinessEvent {

    // 某種具體的業務事件的數據內容
    private Object businessData;

    // 某種具體的業務事件的事件類型
    private String businessEventType;

    public BusinessEvent(String businessEventType, Object businessData) {
        this.businessEventType = businessEventType;
        this.businessData = businessData;
    }

    public Object getBusinessData() {
        return this.businessData;
    }

    public String getBusinessEventType() {
        return this.businessEventType;
    }

}

  接著就是業務事件監聽器的定義了

/**
 * @filename:BusinessEventListener.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:業務事件監聽器定義
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.businessevent;

public interface BusinessEventListener {
    
    //事件介面定義
    public void execute(BusinessEvent event);

}

  業務事件,總要有個管理者吧,那現在就實現一個

/**
 * @filename:BusinessEventManagement.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:業務事件管理器定義
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.businessevent;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//業務事件管理器
public class BusinessEventManagement {

    private Map<String, List<BusinessEventListener>> map = new HashMap<String, List<BusinessEventListener>>();

    public BusinessEventManagement() {

    }

    // 註冊業務事件監聽器
    public boolean addBusinessEventListener(String BusinessEventType,BusinessEventListener listener) {
        List<BusinessEventListener> listeners = map.get(BusinessEventType);
        
        if (null == listeners) {
            listeners = new ArrayList<BusinessEventListener>();
        }
        
        boolean result = listeners.add(listener);
        
        map.put(BusinessEventType, listeners);
        
        return result;
    }

    // 移除業務事件監聽器
    public boolean removeBusinessEventListener(String BusinessEventType,BusinessEventListener listener) {
        List<BusinessEventListener> listeners = map.get(BusinessEventType);
if (null != listeners) { return listeners.remove(listener); } return false; } // 獲取業務事件監聽器隊列 public List<BusinessEventListener> getBusinessEventListeners(String BusinessEventType) { return map.get(BusinessEventType); } }

  再來一個事件的發送者,來負責事件的派發

/**
 * @filename:BusinessEventNotify.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:業務事件發送者
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.businessevent;

import java.util.List;

public class BusinessEventNotify {

    private BusinessEventManagement businessEventManagement;;

    public BusinessEventNotify(BusinessEventManagement businessEventManagement) {
        this.businessEventManagement = businessEventManagement;
    }

    // 事件派發
    public void notify(BusinessEvent BusinessEvent) {
        if (null == BusinessEvent) {
            return;
        }

        List<BusinessEventListener> listeners = businessEventManagement.getBusinessEventListeners(BusinessEvent.getBusinessEventType());

        if (null == listeners) {
            return;
        }

        for (BusinessEventListener listener : listeners) {
            listener.execute(BusinessEvent);
        }
    }
}

  關鍵的來了,下麵可以根據自己的業務規定,註冊若幹個事件的監聽器。下麵我們就先註冊兩個監聽器,分別是簡訊監聽器、彩鈴監聽器,然後執行自己對“感興趣”事件進行的操作。

/**
 * @filename:SendSmsListener.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:簡訊消息監聽器
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.businessevent;

public class SendSmsListener implements BusinessEventListener {

    @Override
    public void execute(BusinessEvent event) {
        System.out.println("監聽器:" + this + "接收到業務事件,業務事件類型是["
                + event.getBusinessEventType() + "] ## 業務事件附帶的數據["
                + event.getBusinessData() + "]");
    }

}
/**
 * @filename:ColorRingListener.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:彩鈴消息監聽器
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.businessevent;

public class ColorRingListener implements BusinessEventListener {

    @Override
    public void execute(BusinessEvent event) {
        System.out.println("監聽器:" + this + "接收到業務事件,業務事件類型是["
                + event.getBusinessEventType() + "] ## 業務事件附帶的數據["
                + event.getBusinessData() + "]");
    }

}

  好了,全部的框架都完成了,那現在我們把上述模塊完整的調用起來。

/**
 * @filename:Main.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:主函數
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.businessevent;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        // 註冊監聽器
        BusinessEventManagement businessEventManagement = new BusinessEventManagement();
        
        businessEventManagement.addBusinessEventListener("彩鈴監聽器",new ColorRingListener());
        businessEventManagement.addBusinessEventListener("簡訊監聽器",new SendSmsListener());

        // 業務事件觸發
        BusinessEventNotify sender = new BusinessEventNotify(businessEventManagement);
        
        sender.notify(new BusinessEvent("彩鈴監聽器", "ReadBusinessEvent"));
        sender.notify(new BusinessEvent("簡訊監聽器", "WriteBusinessEvent"));
    }

}

  彩鈴監聽器感興趣的事件是讀事件(ReadBusinessEvent),簡訊監聽器感興趣的事件是寫事件(WriteBusinessEvent)。運行起來之後,發現果然組織的很好。當然有人會說,上面的情況JDK裡面已經有現成的類(java.util.EventObject、java.util.EventListener)支持了。那下麵我們就根據上面的例子,利用Spring框架來模擬一下事件模型是如何更優雅的應用的。

  在Spring裡面,所有事件的基類是ApplicationEvent,那我們從這個類派生一下,重新定義一下我們的業務事件。代碼如下

/**
 * @filename:BusinessEvent.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:業務事件定義
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.spring;

import org.springframework.context.ApplicationEvent;

public class BusinessEvent extends ApplicationEvent {
    
    // 某種具體的業務事件的數據內容
    private Object businessData;

    // 某種具體的業務事件的事件類型
    private String businessEventType;

    public BusinessEvent(String businessEventType, Object businessData) {
        super(businessEventType);

        this.businessEventType = businessEventType;
        this.businessData = businessData;
    }

    public Object getBusinessData() {
        return this.businessData;
    }

    public String getBusinessEventType() {
        return this.businessEventType;
    }
}

  同樣的,事件的發送者也要進行一下調整,代碼如下

/**
 * @filename:BusinessEventNotify.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:業務事件發送者
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.spring;

import java.util.List;

import newlandframework.spring.BusinessEvent;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class BusinessEventNotify implements ApplicationContextAware {

    private List<String> businessListenerList;
    
    private ApplicationContext ctx;

    public void setBusinessListenerList(List<String> businessListenerList) {
this.businessListenerList = businessListenerList; } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ctx = applicationContext; } public void notify(BusinessEvent businessEvent) { if (businessListenerList.contains(businessEvent.getBusinessEventType())) { BusinessEvent event = new BusinessEvent( businessEvent.getBusinessEventType(), businessEvent.getBusinessData()); ctx.publishEvent(event); return; } } }

  下麵我們就來註冊一下Spring方式的簡訊、彩鈴監聽器:

/**
 * @filename:SendSmsListener.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:簡訊消息監聽器
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.spring;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class SendSmsListener implements ApplicationListener {
    
    final String strKey = "SMS";

    public void onApplicationEvent(ApplicationEvent event) {
        // 這裡你可以截取感興趣的實際類型
        if (event instanceof BusinessEvent) {
            BusinessEvent businessEvent = (BusinessEvent) event;

            if (businessEvent.getBusinessEventType().toUpperCase().contains(strKey)) {
                System.out.println("監聽器:" + this + "接收到業務事件,業務事件類型是["
                        + businessEvent.getBusinessEventType()
                        + "] ## 業務事件附帶的數據[" + businessEvent.getBusinessData()
                        + "]");
            }
        }
    }
}
/**
 * @filename:ColorRingListener.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:彩鈴消息監聽器
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.spring;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class ColorRingListener implements ApplicationListener {

    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof BusinessEvent) {
            BusinessEvent businessEvent = (BusinessEvent) event;
            System.out.println("監聽器:" + this + "接收到業務事件,業務事件類型是["
                    + businessEvent.getBusinessEventType() + "] ## 業務事件附帶的數據["
                    + businessEvent.getBusinessData() + "]");
        }
    }
}

  最後我們編寫一下Spring的依賴註入的配置文件spring-event.xml,當然事件的監聽器也是在這裡面依賴註入實現自動裝配的。

<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
             http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
    default-autowire="byName">
    <bean id="smsListener" class="newlandframework.spring.SendSmsListener" />
    <bean id="ringListener" class="newlandframework.spring.ColorRingListener" />
    <bean id="event" class="newlandframework.spring.BusinessEventNotify">
        <property name="businessListenerList">
            <list>
                <value>DealColorRing</value>
                <value>DealSms</value>
            </list>
        </property>
    </bean>
</beans>

  一切準備就緒,現在我們把上面Spring方式實現的事件模型,完整的串起來,代碼如下:

/**
 * @filename:Main.java
 *
 * Newland Co. Ltd. All rights reserved.
 * 
 * @Description:主函數
 * @author tangjie
 * @version 1.0
 * 
 */

package newlandframework.spring;

import newlandframework.spring.BusinessEvent;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("newlandframework/spring/spring-event.xml");

        BusinessEventNotify sender = (BusinessEventNotify) ctx.getBean("event");

        sender.notify(new BusinessEvent("DealColorRing", "ReadBusinessEvent"));
sender.notify(new BusinessEvent("DealSms", "ReadBusinessEvent")); } }

  運行的結果如下,非常完美,不是麽?

 


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

-Advertisement-
Play Games
更多相關文章
  • 這幾天呢,公司風波再起,去年一年公司CTO換啦4任,CEO換啦三個,這不剛來個新老大,感覺還不錯,卻沒乾過3個月又要走,索性趁老大們走來走去的時候,就給自己空出來,稍稍總結一下剛寫的一個日誌服務組件中用到的RabbitMQ,在.net中的實戰中應用。 首先不去討論我的日誌組件怎麼樣。因為有些日誌需要
  • 少爺菜鳥一枚,求輕噴。 今天在網上無意間看到一道面試題,感覺挺有意思的,題目是這樣:"請用任意一種面向對象語言實現一個電腦控制台程式,要求輸入兩個數和運算符號,輸出結果”。 第一遍的時候還在想,居然還有這麼簡單的面試題?花了幾分鐘敲了一下這個程式,代碼如下(為了方便,代碼本身不規範,很多情況並未考
  • oauth2.0 sso jackical
  • 在平時寫程式的時候往往會遇到這樣的需求,對於某些資源我們只想讓其只能由一個對象進行訪問,從而保證其完整性。比如,配置文件,工具類,線程池,緩存,日誌對象等。對這些資源進行訪問的對象我們只需要一個,當能對其進行讀寫的對象多了的時候就可能由於邏輯上的問題導致了很多意想不到的結果。在這個的背景下,結合了面...
  • 註冊組件以後,通過容器或 ILifetimeScope 的 Resolve 方法解析服務: 請註意,本例使用 ILifetimeScope 解析服務,而不是直接從容器解析。儘管可以從根容器直接解析組件,但是,某些情況下導致記憶體泄露。建議始終從 ILifetimeScope對象解析組件,以確保服務的實
  • 上一篇開源任務管理平臺TaskManager介紹發佈後,有網友聯繫我看看能不能做個後臺管理界面,方便管理系統中所有的任務。由於時間和技術問題1.0版本的時候,新增了一個3分鐘讀取配置文件動態修改任務的功能,不過總體來說還是不直觀,操作不便捷。剛好最近接觸到了Owin,可以實現自己的宿主程式運行Web
  • 常說的工廠模式一般認為有三種:簡單工廠、工廠方法模式、抽象工廠模式。其中簡單工廠嚴格上來說不是一種設計模式,而被認為是一種好的編碼習慣/風格。 簡單工廠 簡單工廠的本質就是封裝變化的代碼,使客戶代碼將要面臨的改變變少。而且被封裝的代碼也有了更好的復用性,比如服務多個客戶端或者被繼承/包裝等工具來擴展
  • 工廠模式分為三種模式,分別為: 下麵就分別介紹一下這三種設計模式: 簡單工廠模式就是由一個工廠類根據傳入的參數量,來決定創建哪一種產品類的實例。(仔細理解這句話,非常重要) 結構圖: 上圖涉及三個類: 源代碼實例: 抽象產品類(Product): Product.java: 具體產品類(Concre
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...