在實際業務開發過程中,很經常應用到觀察者模式。大致的處理流程是說在模塊初始化的時候,註冊若幹觀察者,然後它們處理自己感興趣的內容。當某一個具體的事件發生的時候,遍歷觀察者隊列,然後”觀察者“們就根據之前約定的具體情況,處理自己關註的事件。其實觀察者模式本人認為更確切的說法應該是:事件通知模型。那麼現
在實際業務開發過程中,很經常應用到觀察者模式。大致的處理流程是說在模塊初始化的時候,註冊若幹觀察者,然後它們處理自己感興趣的內容。當某一個具體的事件發生的時候,遍歷觀察者隊列,然後”觀察者“們就根據之前約定的具體情況,處理自己關註的事件。其實觀察者模式本人認為更確切的說法應該是:事件通知模型。那麼現在,我們就用傳統的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")); } }
運行的結果如下,非常完美,不是麽?