天天看點

設計模式之觀察者模式

OBSERVER(觀察者)—對象行為型模式

1. 意圖

    定義對象間的一種一對多的依賴關系 ,當一個對象的狀态發生改變時 , 所有依賴于它的對象都得到通知并被自動更新。

2. 别名

    依賴(Dependents), 釋出-訂閱( P u b l i s h - S u b s c r i b e )

3. 動機

    将一個系統分割成一系列互相協作的類有一個常見的副作用:需要維護相關對象間的一緻性。我們不希望為了維持一緻性而使各類緊密耦合,因為這樣降低了它們的可重用性。

    例如, 許多圖形使用者界面工具箱将使用者應用的界面表示與底下的應用資料分離。定義應用資料的類和負責界面表示的類可以各自獨立地複用。 當然它們也可一起工作。一個表格對象和一個柱狀圖對象可使用不同的表示形式描述同一個應用資料對象的資訊。表格對象和柱狀圖對象互相并不知道對方的存在,這樣使你可以根據需要單獨複用表格或柱狀圖。但在這裡是它們表現的似乎互相知道。當使用者改變表格中的資訊時 ,柱狀圖能立即反映這一變化 , 反過來也是如此。

<a href="https://s2.51cto.com/wyfs02/M02/A6/6A/wKioL1nOJCWCQB7GAADnPIbSGx0819.png" target="_blank"></a>

    這種互動也稱為釋出-訂閱(p u b l i s h - s u b s c r i b e)。目标是通知的釋出者。它發出通知時并不需知道誰是它的觀察者。可以有任意數目的觀察者訂閱并接收通知。

4. 适用性

在以下任一情況下可以使用觀察者模式 :

     當一個抽象模型有兩個方面 , 其中一個方面依賴于另一方面。将這二者封裝在獨立的對象中以使它們可以各自獨立地改變和複用。

     當對一個對象的改變需要同時改變其它對象 , 而不知道具體有多少對象有待改變。

     當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之 , 你不希望這些對象是緊密耦合的。

适用場景

    1.swing元件

    2.HTML控件事件:比如onblur,onclick

    3.JavaEE中各種監聽器:ServletContextListener、HttpSessionListener、ServletRequestListener

例如:建立兩個HttpSessionListener對象

public class OnlineUserListener implements HttpSessionListener {}

public class LoginUserListener implements HttpSessionListener{}

注:其實是在web.xml中建立對象

然後就會注冊:類似xmlhttp.onreadystatechange=state_Change這樣注冊對象(這裡不是調用是注冊,是一個函數頭指針),注冊給要發事件的對象(具體的當時沒寫);然後事件觸發之後就會回調這個函數。

    4.XMLHttpRequest

XMLHttpRequest 對象

   提供了浏覽器多線程互動模式 (浏覽器使用多線程和伺服器互動)

    同步阻塞模式  ---  浏覽器首頁面使用

    異步、局部重新整理模式  ---- ajax 

    回調機制 (callback,所有事件響應都是回調機制)---------- 1. 要注冊   2. 等待事件觸發  3. 事件發生後,通知監聽者(通過回調)

<a href="https://s4.51cto.com/oss/201710/29/a0e087f73d4ba474cd81e8a494c1894e.png" target="_blank"></a>

回調機制:先注冊,将函數頭指針傳給被被注冊的對象,也就是要發消息的對象。

5. 結構

<a href="https://s5.51cto.com/wyfs02/M02/A6/6A/wKioL1nOJVaBzvcEAAEFVg69b00535.png" target="_blank"></a>

6. 參與者

S u b j e c t(目标)

— 目标知道它的觀察者。可以有任意多個觀察者觀察同一個目标。

— 提供注冊和删除觀察者對象的接口。

O b s e r v e r(觀察者)

— 為那些在目标發生改變時需獲得通知的對象定義一個更新接口。

C o n c r e t e S u b j e c t(具體目标)

— 将有關狀态存入各C o n c r e t e O b s e r v e r對象。

— 當它的狀态發生改變時, 向它的各個觀察者發出通知。

C o n c r e t e O b s e r v e r(具體觀察者)

— 維護一個指向C o n c r e t e S u b j e c t對象的引用。

— 存儲有關狀态,這些狀态應與目标的狀态保持一緻。

— 實作O b s e r v e r的更新接口以使自身狀态與目标的狀态保持一緻。

7.代碼示範

01.目标

<code>public</code> <code>abstract</code> <code>class</code> <code>Subject {</code>

<code>    </code> 

<code>    </code><code>//一個目标有多個觀察者</code>

<code>    </code><code>private</code> <code>List&lt;Observer&gt; observers;</code>

<code>    </code><code>//建立目标的時候再執行個體化對象</code>

<code>    </code><code>public</code> <code>Subject(){</code>

<code>        </code><code>observers = </code><code>new</code> <code>ArrayList&lt;Observer&gt;();</code>

<code>    </code><code>}</code>

<code>    </code><code>//添加觀察者</code>

<code>    </code><code>public</code> <code>void</code> <code>attach(Observer observer){</code>

<code>        </code><code>observers.add(observer);</code>

<code>    </code><code>//移除觀察者</code>

<code>    </code><code>public</code>  <code>void</code> <code>detach(Observer observer){</code>

<code>        </code><code>observers.remove(observer);</code>

<code>    </code><code>//通知消息</code>

<code>    </code><code>public</code> <code>void</code> <code>notifyMsg(String msg){</code>

<code>        </code><code>if</code><code>(observers != </code><code>null</code><code>){</code>

<code>            </code><code>for</code><code>(Observer observer : observers ){</code>

<code>                </code><code>observer.receiveMsg(msg);</code>

<code>            </code><code>}</code>

<code>        </code><code>}</code>

<code>}</code>

實作接口,定義定時提醒功能

<code>public</code> <code>class</code> <code>TimerService </code><code>extends</code> <code>Subject{</code>

02.觀察者

<code>public</code> <code>abstract</code> <code>class</code> <code>Observer {</code>

<code>    </code><code>protected</code> <code>String name;</code>

<code>    </code><code>//觀察者名字</code>

<code>    </code><code>public</code> <code>Observer(String name){</code>

<code>        </code><code>this</code><code>.name = name;</code>

<code>    </code><code>//接受目标釋出的消息</code>

<code>    </code><code>public</code> <code>abstract</code> <code>void</code> <code>receiveMsg(String msg);</code>

03.寫具體對象實作觀察者接口

<code>public</code> <code>class</code> <code>Teacher </code><code>extends</code> <code>Observer{</code>

<code>    </code><code>public</code> <code>Teacher(String name) {</code>

<code>        </code><code>super</code><code>(name);</code>

<code>        </code><code>// TODO Auto-generated constructor stub</code>

<code>    </code><code>@Override</code>

<code>    </code><code>public</code> <code>void</code> <code>receiveMsg(String msg) {</code>

<code>        </code><code>System.out.println( msg + </code><code>"--"</code> <code>+ </code><code>this</code><code>.name + </code><code>"該講課了"</code><code>);       </code>

<code>public</code> <code>class</code> <code>Student </code><code>extends</code> <code>Observer{</code>

<code>    </code><code>public</code> <code>Student(String name) {</code>

<code>        </code><code>System.out.println( msg + </code><code>"--"</code> <code>+ </code><code>this</code><code>.name + </code><code>"該學習了"</code><code>);</code>

04.實作釋出與訂閱功能

<code>public</code> <code>class</code> <code>Test {</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>

<code>        </code><code>TimerService service = </code><code>new</code> <code>TimerService();</code>

<code>        </code><code>Teacher t1 = </code><code>new</code> <code>Teacher(</code><code>"t1"</code><code>);</code>

<code>        </code><code>Teacher t2 = </code><code>new</code> <code>Teacher(</code><code>"t2"</code><code>);</code>

<code>        </code><code>Teacher t3 = </code><code>new</code> <code>Teacher(</code><code>"t3"</code><code>);</code>

<code>        </code><code>Student s1 = </code><code>new</code> <code>Student(</code><code>"s1"</code><code>);</code>

<code>        </code><code>Student s2 = </code><code>new</code> <code>Student(</code><code>"s2"</code><code>);</code>

<code>        </code><code>service.attach(t1);</code>

<code>        </code><code>service.attach(t2);</code>

<code>        </code><code>service.attach(s1);</code>

<code>        </code><code>service.attach(t3);</code>

<code>        </code><code>service.notifyMsg(</code><code>"現在8點了"</code><code>);</code>

05.結果

<code>現在</code><code>8</code><code>點了--t1該講課了</code>

<code>現在</code><code>8</code><code>點了--t2該講課了</code>

<code>現在</code><code>8</code><code>點了--s1該學習了</code>

<code>現在</code><code>8</code><code>點了--t3該講課了</code>

版權聲明:原創作品,如需轉載,請注明出處。否則将追究法律責任

本文轉自 叫我北北 51CTO部落格,原文連結:http://blog.51cto.com/qinbin/1969818

繼續閱讀