觀察者模式
觀察者模式定義了對象之間的一對多依賴,這樣以來,當一個對象改變狀态時候,它的所有依賴者都會接收到通知并且自動更新。
通常觀察者模式,分為主題(Subject),觀察者(Observer)。一般主要用在當一個對象發生變化的時候,需要通知許多對象的時候,發生變化的對象稱為主題,而接受對象變化資訊的對象則是觀察者。一旦主題對象的資料庫發生了變化,那麼就會自動以某種方式送到觀察者,觀察者可以拒絕接受消息或者注冊稱為主題對象的一個接受消息的對象。
主題和觀察者定義了一對多的關系,觀察者依賴于此主題,隻要主題一旦發生變化的時候,觀察者就會接收到通知。
一般應用情況,許多的對象需要共同接受某一個對象變化的消息,譬如廣播訂閱者,譬如在java swing元件中許多元件可能會有許多個監聽事件等,均用的這種思想。
1 使用者自定義觀察者模式:
首先要明确,兩個最主要的接口,Subject,Observer
Subject主要是發送資料變化的接口,而Observer則是接受Subject對象變化的資訊。
常見Subject接口:
1
2
3
4
5
6
7
8
<code>public</code> <code>interface</code> <code>Subject {</code>
<code> </code><code>//向該主題中注冊或添加新的觀察者</code>
<code> </code><code>void</code> <code>registerObserver(Observer obs);</code>
<code> </code><code>//從該主題中删除移調某一個觀察者</code>
<code> </code><code>void</code> <code>removeeObserver(Observer obs);</code>
<code> </code><code>//通知該主題下面注冊的觀察者</code>
<code> </code><code>void</code> <code>notifyObservers();</code>
<code>}</code>
Observer接口
<code>public</code> <code>interface</code> <code>Observer {</code>
<code> </code><code>//接受主題變化傳遞的消息</code>
<code> </code><code>void</code> <code>update(Object obj);</code>
當然這隻是初步的最基本的自定義模型,具體的添加觀察者需要再實作了Subject後,利用集合對象來實作添加或删除觀察者。
一般類圖如下:
<a href="http://blog.51cto.com/attachment/201301/190100962.jpg"></a>
舉例說明:
一個資訊站,不停的接受資訊,而又有許多使用者需要當該資訊站一旦有最新資料,則能讓該資訊站能主動推送資料過來,此時,就構成了一對多的對象關系,資訊站變化,而使用者能自動的讓資訊站給它們發送資料。
Subject接口和Observer接口如上定義的,
定義一個資訊站類InformationStation實作了Subject接口:
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<code>import</code> <code>java.util.ArrayList;</code>
<code>public</code> <code>class</code> <code>InformationStation </code><code>implements</code> <code>Subject {</code>
<code> </code><code>// 利用ArrayList來動态的增加和移除觀察者</code>
<code> </code><code>private</code> <code>ArrayList<Observer> observers;</code>
<code> </code><code>// 實時資料</code>
<code> </code><code>private</code> <code>int</code> <code>data;</code>
<code> </code><code>// 表示資訊是否變化</code>
<code> </code><code>private</code> <code>boolean</code> <code>changed = </code><code>false</code><code>;</code>
<code> </code><code>// 用于注冊觀察者</code>
<code> </code><code>@Override</code>
<code> </code><code>public</code> <code>void</code> <code>registerObserver(Observer obs) {</code>
<code> </code><code>// TODO Auto-generated method stub</code>
<code> </code><code>observers.add(obs);</code>
<code> </code><code>}</code>
<code> </code><code>// 用于觀察者移除</code>
<code> </code><code>public</code> <code>void</code> <code>removeObserver(Observer obs) {</code>
<code> </code><code>int</code> <code>i = observers.indexOf(obs);</code>
<code> </code><code>if</code> <code>(i >= </code><code>0</code><code>)</code>
<code> </code><code>observers.remove(i);</code>
<code> </code><code>// 通知觀察者</code>
<code> </code><code>public</code> <code>void</code> <code>notifyObservers() {</code>
<code> </code><code>// 當資訊發生變化的時候,發送給所有觀察者</code>
<code> </code><code>if</code> <code>(changed) {</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i < observers.size(); i++)</code>
<code> </code><code>observers.get(i).update(data);</code>
<code> </code><code>}</code>
<code> </code><code>// 發送完畢後,再次設狀态</code>
<code> </code><code>changed = </code><code>false</code><code>;</code>
<code> </code><code>public</code> <code>void</code> <code>setData(</code><code>int</code> <code>newdata) {</code>
<code> </code><code>this</code><code>.data = newdata;</code>
<code> </code><code>changed = </code><code>true</code><code>;</code>
<code> </code><code>notifyObservers();</code>
<code> </code><code>// 可以供觀察者來拉資料</code>
<code> </code><code>public</code> <code>int</code> <code>getData() {</code>
<code> </code><code>return</code> <code>data;</code>
再定義一個觀察者,當然觀察者可以定義許多個,隻要實作了Observer接口即可,為了讓觀察者訂閱該主題,接受主題變化時候發送的資料,可以在構造器中傳遞一個要注冊的主題對象,也可以設定一個方法來提供觀察者來設定主題:ManagerObserver類
<code>public</code> <code>class</code> <code>ManagerObserver </code><code>implements</code> <code>Observer {</code>
<code> </code><code>// 之是以有個Subject屬性是為了便于該觀察者移除該主題</code>
<code> </code><code>private</code> <code>Subject station;</code>
<code> </code><code>// 擷取資料</code>
<code> </code><code>// 初始化的不做注冊</code>
<code> </code><code>public</code> <code>ManagerObserver() {</code>
<code> </code><code>// 初始化的時候注冊該觀察者的主題對象</code>
<code> </code><code>public</code> <code>ManagerObserver(Subject station) {</code>
<code> </code><code>this</code><code>.station = station;</code>
<code> </code><code>// 将該觀察者加入該主題對象中</code>
<code> </code><code>station.registerObserver(</code><code>this</code><code>);</code>
<code> </code><code>// 供觀察者添加修改主題對象</code>
<code> </code><code>public</code> <code>void</code> <code>setSubject(Subject station) {</code>
<code> </code><code>// 實作該方法,當主題發生變化的時候,主題就會通過該方法發送資料</code>
<code> </code><code>// 該update在實際的情況下,最好加上一個發送主題的對象,接口中加上即可,</code>
<code> </code><code>// 這樣可以判斷當一個觀察者注冊多個主題的時候,哪些資料屬于哪個主題發送的</code>
<code> </code><code>public</code> <code>void</code> <code>update(Object obj) {</code>
<code> </code><code>System.out.println(obj.toString());</code>
基本的模型ok了,可以做個測試類進行實作了
2 Java内置的觀察者模式:
Java内置有觀察者模式所需要的類,
Observer接口:如同上面的一樣,主要方法為
update(Observable o,Object arg);//第一個參數為主題對象,第二個為資料
Observable類:如同上面的Subject接口,隻不過這裡是變成類了,裡面有觀察者注冊,移除,通知等方法,并且有預設的Vetor集合作為屬性。
在實際開發的過程中,可以直接将你的主題直接實作該Observable類,其中有兩個非常重要的方法,notifyObservers();這個方法可以說主要來用于讓觀察者來拉資料,根據需要來接受資料,而notifyObservers(Object obj);這個方法主要是主題來主動推送資料給觀察者。
Java内置的觀察者模式的缺點,由于Observable是一個類,那麼你在實際運用的時候,則限制一定的靈活性,因為不能同時繼承多個類,你也無法建立自己的實作,除非你全部重寫Observable類,由于Observable在每次發送資料的時候都會堅持changed對象的狀态,但是該對象是protected,意味着你隻能繼承它來使用,不能new一個Observable對象,進而用組合的方式來實作。
觀察者模式的優點:
支援松耦合和減少依賴性。用戶端不再依賴于觀察器,因為通過使用主體和 Observer 接口對用戶端進行了隔離。許多架構具有此優點,在這些架構中的應用程式元件可以注冊為當(低級)架構事件發生時得到通知。結果,架構将調用應用程式元件,但不會依賴于它。
觀察器數目可變。觀察器可以在運作時注冊和移除,因為主體對于觀察器數目沒有任何假定。
本文轉自 zhao_xiao_long 51CTO部落格,原文連結:http://blog.51cto.com/computerdragon/1122895