|
一、觀察者模式的本來面目
工作時間長了,會發(fā)現(xiàn)代碼中的很多東西都是相通相似的,就說JAVA的事件機制其實就是觀察者模式的實現(xiàn),學(xué)會了觀察者模式,事件機制自己無師自通,先以我的角度看看什么是觀察者模式。
觀察者模式,顧名思義,應(yīng)該有觀察者(抽象觀察者“Observer”角色)和被觀察者(抽象主題“Subject”角色),被觀察者一旦有變化就通知觀察者更新自己。
形象圖:

下面是觀察者模式的類圖:

從我的角度簡單點理解,我們知道面向?qū)ο缶幊滩贿^是對象之間的相互調(diào)用,那么被觀察者應(yīng)該有個列表(List)來把所有觀察者引用起來,當有事件要通知觀察者時,我們從List中把所有觀察者類取出來挨個調(diào)用觀察者的方法(如update())。這個過程中只有充分利用了面向?qū)ο缶幊痰亩鄳B(tài),繼承等特性才能實現(xiàn)。
下面是代碼實現(xiàn):
被觀察者(抽象主題類):
Java代碼 
- package com.lifanghu.observer;
-
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-14 下午06:18:26
- * @name com.lifanghu.observer.Subject.java
- * @version 1.0
- */
- public abstract class Subject {
-
- private List observers = new ArrayList();
-
- /**
- * 增加一個觀察者
- * @param observer
- * @author lifh
- */
- public void addObserver(Observer observer) {
- observers.add(observer);
- }
- /**
- * 刪除一個觀察者
- * @param observer
- * @author lifh
- */
- public void removeObserver(Observer observer) {
- observers.remove(observer);
- }
- /**
- * 通知所有觀察者
- * @author lifh
- */
- public void notifyObservers() {
- for (Observer observer : observers) {
- observer.update(this);
- }
- }
- }
實際被觀察者(真實主題角色):
Java代碼 
- package com.lifanghu.observer;
-
- /**
- * 實際被觀察者
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-14 下午10:48:02
- * @name com.lifanghu.observer.XiaoMing.java
- * @version 1.0
- */
- public class XiaoMing extends Subject {
-
- private String state;
-
- //實際要通進行通知的方法
- public void change() {
- this.notifyObservers();
- }
- public String getState() {
- return state;
- }
- public void setState(String state) {
- this.state = state;
- }
- }
抽象觀察者:
Java代碼 
- package com.lifanghu.observer;
-
- /**
- * 實際觀察者
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-14 下午10:54:07
- * @name com.lifanghu.observer.XiaoWang.java
- * @version 1.0
- */
- public class XiaoWang implements Observer {
-
- public void update(Subject subject) {
- XiaoMing xm = (XiaoMing) subject;
- System.out.println("小王得到通知:" + xm.getState() + ";小王說:活該!");
- }
- }
具體觀察者1:
Java代碼 
- package com.lifanghu.observer;
-
- /**
- * 實際觀察者
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-14 下午10:54:07
- * @name com.lifanghu.observer.XiaoWang.java
- * @version 1.0
- */
- public class XiaoWang implements Observer {
-
- public void update(Subject subject) {
- XiaoMing xm = (XiaoMing) subject;
- System.out.println("小王得到通知:" + xm.getState() + ";小王說:活該!");
- }
- }
具體觀察者2:
Java代碼 
- package com.lifanghu.observer;
-
- /**
- * 實際觀察者
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-14 下午10:56:17
- * @name com.lifanghu.observer.ZhangShan.java
- * @version 1.0
- */
- public class ZhangShan implements Observer {
-
- public void update(Subject subject) {
- XiaoMing xm = (XiaoMing) subject;
- System.out.println("張三得到通知:" + xm.getState() + ";張三說:快吃藥吧!");
- }
- }
客戶端調(diào)用邏輯:
Java代碼 
- package com.lifanghu.observer;
-
- /**
- * 實際觀察者
- * @author lifh
- * @mail wslfh2005@163.com
- * @since 2012-6-14 下午10:56:17
- * @name com.lifanghu.observer.ZhangShan.java
- * @version 1.0
- */
- public class ZhangShan implements Observer {
-
- public void update(Subject subject) {
- XiaoMing xm = (XiaoMing) subject;
- System.out.println("張三得到通知:" + xm.getState() + ";張三說:快吃藥吧!");
- }
- }
輸出結(jié)果:
寫道
張三得到通知:小明病了;張三說:快吃藥吧! 小王得到通知:小明病了;小王說:活該!
說明:對于觀察者模式JDK是有相應(yīng)的實現(xiàn)支持的,內(nèi)置觀察者模式主要有2個類,一個是類Observable,一個是接口類Observer ,大家可以上網(wǎng)去查,或者直接看它的源碼,這里就不多說了。
二、從觀察者模式到事件機制
關(guān)于事件機制上面也談了,它其實就是觀察者模式的實現(xiàn),關(guān)于兩者的聯(lián)系也可以看iteye上的另一討論http://www./topic/182643,里面說的已經(jīng)很清楚了。
關(guān)于事件模型我想說的是里面的三個元素:事件源,事件本身,監(jiān)聽者,對應(yīng)觀察者模式的三個元素分別是:被觀察者,觀察者方法要傳入的參數(shù),觀察者。
關(guān)于事件機制JDK也有相應(yīng)的實現(xiàn)java.util.EventListener和java.util.EventObject 。
三、Mina中的事件以及監(jiān)聽器的實現(xiàn)
Mina 中有主要有三種事件:
1、org.apache.mina.core.service包下面對IoService接口實現(xiàn)和IoSession接口實現(xiàn)的監(jiān)聽,它不是一個純的事件模型,沒有事件本身(EventObject)的存在。
2、org.apache.mina.core.session包下在線程池環(huán)境下對于事件的觸發(fā)從而進入過濾器鏈進行的處理,它不是一個純事件的模型,少了監(jiān)聽器(EventListener)的實現(xiàn)。
3、org.apache.mina.core.future包下對于異步IO操作(IoFuture)進行監(jiān)聽。它也不是一個純的事件模型,也是少了事件本身(EventObject)的存在。
下面分別介紹下這三種事件細節(jié)。
1、service包下面主要有兩個類是用于監(jiān)聽模式的,監(jiān)聽者IoServiceListener和它的幫助類IoServiceListenerSupport,IoServiceListener接口繼承了EventListener,標明自己是個監(jiān)聽者接口,主要監(jiān)聽service和session的創(chuàng)建,空閑,銷毀事件的。IoServiceListenerSupport作為它的幫助類,實際上充當了事件源的角色,它存儲了IoServiceListener的成員列表。
Java代碼 
- /** A list of {@link IoServiceListener}s. */
- private final List listeners = new CopyOnWriteArrayList();
里面有增加和刪除監(jiān)聽者的方法:
Java代碼 
- /**
- * Adds a new listener.
- *
- * @param listener The added listener
- */
- public void add(IoServiceListener listener) {
- if (listener != null) {
- listeners.add(listener);
- }
- }
-
- /**
- * Removes an existing listener.
- *
- * @param listener The listener to remove
- */
- public void remove(IoServiceListener listener) {
- if (listener != null) {
- listeners.remove(listener);
- }
- }
通知監(jiān)聽者的方法:
Java代碼 
- /**
- * Calls {@link IoServiceListener#serviceActivated(IoService)}
- * for all registered listeners.
- * 通知方法
- */
- public void fireServiceActivated() {
- if (!activated.compareAndSet(false, true)) {
- // The instance is already active
- return;
- }
-
- activationTime = System.currentTimeMillis();
-
- // Activate all the listeners now
- for (IoServiceListener listener : listeners) {//循環(huán)提取出listeners執(zhí)行本身的方法
- try {
- listener.serviceActivated(service);
- } catch (Throwable e) {
- ExceptionMonitor.getInstance().exceptionCaught(e);
- }
- }
- }
再來看接口IoService,有對監(jiān)聽器的操作:
Java代碼 
- /**
- * Adds an {@link IoServiceListener} that listens any events related with
- * this service.
- */
- void addListener(IoServiceListener listener);
-
- /**
- * Removed an existing {@link IoServiceListener} that listens any events
- * related with this service.
- */
- void removeListener(IoServiceListener listener);
它的實現(xiàn)AbstractIoService里面可以看到,實際是調(diào)用的IoServiceListenerSupport的方法執(zhí)行的有關(guān)操作:
Java代碼 
- /**
- * {@inheritDoc}
- */
- public final void addListener(IoServiceListener listener) {
- listeners.add(listener);
- }
-
- /**
- * {@inheritDoc}
- */
- public final void removeListener(IoServiceListener listener) {
- listeners.remove(listener);
- }
看下AbstractIoAcceptor類的調(diào)用方法:
Java代碼 
- if (activate) {
- //觸發(fā)監(jiān)聽器的服務(wù)創(chuàng)建事件
- getListeners().fireServiceActivated();
- }
2、session包下的事件模型主要還是基于多線程模型來實現(xiàn)的,可以看到IoEvent實現(xiàn)了Runnable接口,它作為任務(wù)放入到線程池中去執(zhí)行,看它的run方法:
Java代碼 
- // 此類實現(xiàn)了 Runnable 它的存在主要為了線程池過濾器ExecutorFilter來使用的。
- // 這樣如果加入了ExecutorFilter后,后面所有的數(shù)據(jù)處理都是多線程方式進行的。
- // 一般放在handler前面,也就是所有過濾器的后面,因為handler主要做業(yè)務(wù)處理,可能會有數(shù)據(jù)庫的操作,比較耗時,適合多線程。
- public void run() {
- //激活各種事件
- fire();
- }
IO事件類型:
Java代碼 
- package org.apache.mina.core.session;
-
- /**
- * An {@link Enum} that represents the type of I/O events and requests.
- * Most users won't need to use this class. It is usually used by internal
- * components to store I/O events.
- *
- * @author Apache MINA Project
- */
- public enum IoEventType {
- SESSION_CREATED,//session創(chuàng)建
- SESSION_OPENED,//session打開
- SESSION_CLOSED,//session關(guān)閉
- MESSAGE_RECEIVED,//消息接收
- MESSAGE_SENT,//消息發(fā)送
- SESSION_IDLE,//session空閑
- EXCEPTION_CAUGHT,//發(fā)生異常
- WRITE,//寫事件
- CLOSE,//關(guān)閉session事件
- }
它有一個實現(xiàn)類IoFilterEvent,我們知道如果我們想要利用mina的多線程處理,需要如下加一個過濾器:
Java代碼 
- connector.getFilterChain().addLast("executor", new ExecutorFilter());
在這個時候我們的IoEvent就派上了用場,ExecutorFilter是一個實現(xiàn)了線程池(線程池在后面的文章中會介紹)的過濾器,看下ExecutorFilter的調(diào)用:
Java代碼 
- @Override
- public final void sessionOpened(NextFilter nextFilter, IoSession session) {
- if (eventTypes.contains(IoEventType.SESSION_OPENED)) {
- IoFilterEvent event = new IoFilterEvent(nextFilter, IoEventType.SESSION_OPENED,
- session, null);
- //觸發(fā)事件
- fireEvent(event);
- } else {
- nextFilter.sessionOpened(session);
- }
- }
- /**
- * Fires the specified event through the underlying executor.
- *
- * @param event The filtered event
- */
- protected void fireEvent(IoFilterEvent event) {
- //將事件提交給線程池執(zhí)行
- executor.execute(event);
- }
可以看到這個session下的事件模型沒有監(jiān)聽器,所以基本就沒有事件模式的概念了,但是還是有一些事件模型的一些影子,所以可以認為它是一個偽事件模型。
3、future包下面的事件模型,是比較常規(guī)的事件模型,這是一個異步調(diào)用后的事件模型,當設(shè)定的異步操作完成后會調(diào)用監(jiān)聽器的operationComplete方法,事件源為IoFuture等,監(jiān)聽器是IoFutureListener,它只有一個方法:
Java代碼 
- /**
- * Invoked when the operation associated with the {@link IoFuture}
- * has been completed even if you add the listener after the completion.
- * 只有一個處理完成的回調(diào)方法,當線程池將我們的任務(wù)處理完成后會調(diào)用此方法。
- * @param future The source {@link IoFuture} which called this
- * callback.
- */
- void operationComplete(F future);
看下事件源的代碼:
Java代碼 
- package org.apache.mina.core.future;
-
- import java.util.concurrent.TimeUnit;
-
- import org.apache.mina.core.session.IoSession;
-
- /**
- * Represents the completion of an asynchronous I/O operation on an
- * {@link IoSession}.
- * Can be listened for completion using a {@link IoFutureListener}.
- * 因為有了線程池模型才會有異步的概念。
- * 我們將各種IO操作(連接,關(guān)閉,讀,寫)以任務(wù)的方式放入隊列中并返回IoFuture供線程池去處理。
- * 處理過程和處理完成的操作會改變IoFuture的狀態(tài)。
- * @author Apache MINA Project
- */
- public interface IoFuture {
- /**
- * Returns the {@link IoSession} which is associated with this future.
- */
- IoSession getSession();
-
- /**
- * Wait for the asynchronous operation to complete.
- * The attached listeners will be notified when the operation is
- * completed.
- */
- IoFuture await() throws InterruptedException;
-
- /**
- * Wait for the asynchronous operation to complete with the specified timeout.
- * 等待操作在指定時間內(nèi)完成
- * @return true if the operation is completed.
- */
- boolean await(long timeout, TimeUnit unit) throws InterruptedException;
-
- /**
- * Wait for the asynchronous operation to complete with the specified timeout.
- *
- * @return true if the operation is completed.
- */
- boolean await(long timeoutMillis) throws InterruptedException;
-
- /**
- * Wait for the asynchronous operation to complete uninterruptibly.
- * The attached listeners will be notified when the operation is
- * completed.
- * 等待異步操作完成,完成后會觸發(fā)注冊的監(jiān)聽器。
- * @return the current IoFuture
- */
- IoFuture awaitUninterruptibly();
-
- /**
- * Wait for the asynchronous operation to complete with the specified timeout
- * uninterruptibly.
- *
- * @return true if the operation is completed.
- */
- boolean awaitUninterruptibly(long timeout, TimeUnit unit);
-
- /**
- * Wait for the asynchronous operation to complete with the specified timeout
- * uninterruptibly.
- *
- * @return true if the operation is finished.
- */
- boolean awaitUninterruptibly(long timeoutMillis);
-
- /**
- * @deprecated Replaced with {@link #awaitUninterruptibly()}.
- */
- @Deprecated
- void join();
-
- /**
- * @deprecated Replaced with {@link #awaitUninterruptibly(long)}.
- */
- @Deprecated
- boolean join(long timeoutMillis);
-
- /**
- * Returns if the asynchronous operation is completed.
- */
- boolean isDone();
-
- /**
- * Adds an event listener which is notified when
- * this future is completed. If the listener is added
- * after the completion, the listener is directly notified.
- * 增加異步完成后的監(jiān)聽者
- */
- IoFuture addListener(IoFutureListener?> listener);
-
- /**
- * Removes an existing event listener so it won't be notified when
- * the future is completed.
- * 刪除異步完成后的監(jiān)聽者
- */
- IoFuture removeListener(IoFutureListener?> listener);
- }
看下調(diào)用監(jiān)聽者的方法類DefaultIoFuture的代碼:
Java代碼 
- /**
- * Sets the result of the asynchronous operation, and mark it as finished.
- */
- public void setValue(Object newValue) {
- synchronized (lock) {
- // Allow only once.
- if (ready) {
- return;
- }
-
- result = newValue;
- ready = true;
- if (waiters > 0) {
- lock.notifyAll();
- }
- }
-
- //調(diào)用監(jiān)聽者的方法
- notifyListeners();
- }
在此我們可以學(xué)到JAVA的異步只有在多線程操作下才有可能實現(xiàn)。
四、推薦文章
參考文章:
1. 觀察者模式
http://ttitfly./blog/152512
2. 《JAVA與模式》之觀察者模式
http://www.cnblogs.com/java-my-life/archive/2012/05/16/2502279.html
3. Java事件機制理解及應(yīng)用
http://blog.csdn.net/JianZhiZG/article/details/1427073
4. java 事件機制
http://www./chenweicai/archive/2007/04/13/110350.html
五、總結(jié)
事件模型作為mina中一個重要的設(shè)計模式很好的體現(xiàn)了JAVA高內(nèi)聚,低耦合的設(shè)計思想,也讓用戶的調(diào)用代碼簡潔易用,本文章本著拋磚引玉的態(tài)度希望大家能指出缺點,共同討論。
|