天天看點

Observer(觀察者)模式

1.概述

一些面向對象的程式設計方式,提供了一種建構對象間複雜網絡互連的能力。當對象們連接配接在一起時,它們就可以互相提供服務和資訊。 通常來說,當某個對象的狀态發生改變時,你仍然需要對象之間能互相通信。但是出于各種原因,你也許并不願意因為代碼環境的改變而對代碼做大的修改。也許,你隻想根據你的具體應用環境而改進通信代碼。或者,你隻想簡單的重新構造通信代碼來避免類和類之間的互相依賴與互相從屬。

2.問題

當一個對象的狀态發生改變時,你如何通知其他對象?是否需要一個動态方案――一個就像允許腳本的執行一樣,允許自由連接配接的方案?

3.解決方案

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

觀測模式允許一個對象關注其他對象的狀态,并且,觀測模式還為被觀測者提供了一種觀測結構,或者說是一個主體和一個客體。主體,也就是被觀測者,可以用來聯系所有的觀測它的觀測者。客體,也就是觀測者,用來接受主體狀态的改變 觀測就是一個可被觀測的類(也就是主題)與一個或多個觀測它的類(也就是客體)的協作。不論什麼時候,當被觀測對象的狀态變化時,所有注冊過的觀測者都會得到通知。 觀測模式将被觀測者(主體)從觀測者(客體)種分離出來。這樣,每個觀測者都可以根據主體的變化分别采取各自的操作。(觀測模式和Publish/Subscribe模式一樣,也是一種有效描述對象間互相作用的模式。)觀測模式靈活而且功能強大。對于被觀測者來說,那些查詢哪些類需要自己的狀态資訊和每次使用那些狀态資訊的額外資源開銷已經不存在了。另外,一個觀測者可以在任何合适的時候進行注冊和取消注冊。你也可以定義多個具體的觀測類,以便在實際應用中執行不同的操作。 将一個系統分割成一系列互相協作的類有一個常見的副作用:需要維護相關對象間的一緻性。我們不希望為了維持一緻性而使各類緊密耦合,因為這樣降低了它們的可重用性。

4.适用性

在以下任一情況下可以使用觀察者模式: • 當一個抽象模型有兩個方面, 其中一個方面依賴于另一方面。将這二者封裝在獨立的對象中以使它們可以各自獨立地改變和複用。 • 當對一個對象的改變需要同時改變其它對象 , 而不知道具體有多少對象有待改變。 • 當一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之 , 你不希望這些對象是緊密耦合的。

5.結構

6.模式的組成

觀察者模式包含如下角色: 目标(Subject): 目标知道它的觀察者。可以有任意多個觀察者觀察同一個目标。 提供注冊和删除觀察者對象的接口。 具體目标(ConcreteSubject):  将有關狀态存入各ConcreteObserver對象。 觀察者(Observer):  為那些在目标發生改變時需獲得通知的對象定義一個更新接口。當它的狀态發生改變時, 向它的各個觀察者發出通知。 具體觀察者(ConcreteObserver):   維護一個指向ConcreteSubject對象的引用。存儲有關狀态,這些狀态應與目标的狀态保持一緻。實作O b s e r v e r的更新接口以使自身狀态與目标的狀态保持一緻。

7.效果

Observer模式允許你獨立的改變目标和觀察者。你可以單獨複用目标對象而無需同時複用其觀察者, 反之亦然。它也使你可以在不改動目标和其他的觀察者的前提下增加觀察者。 下面是觀察者模式其它一些優點: 1 )觀察者模式可以實作表示層和資料邏輯層的分離,并定義了穩定的消息更新傳遞機制,抽象了更新接口,使得可以有各種各樣不同的表示層作為具體觀察者角色。 2 )在觀察目标和觀察者之間建立一個抽象的耦合 :一個目标所知道的僅僅是它有一系列觀察者 , 每個都符合抽象的Observer類的簡單接口。目标不知道任何一個觀察者屬于哪一個具體的類。這樣目标和觀察者之間的耦合是抽象的和最小的。因為目标和觀察者不是緊密耦合的, 它們可以屬于一個系統中的不同抽象層次。一個處于較低層次的目标對象可與一個處于較高層次的觀察者通信并通知它 , 這樣就保持了系統層次的完整。如果目标和觀察者混在一塊 , 那麼得到的對象要麼橫貫兩個層次 (違反了層次性), 要麼必須放在這兩層的某一層中(這可能會損害層次抽象)。 3) 支援廣播通信 :不像通常的請求, 目标發送的通知不需指定它的接收者。通知被自動廣播給所有已向該目标對象登記的有關對象。目标對象并不關心到底有多少對象對自己感興趣 ;它唯一的責任就是通知它的各觀察者。這給了你在任何時刻增加和删除觀察者的自由。處理還是忽略一個通知取決于觀察者。 4) 觀察者模式符合“開閉原則”的要求。 觀察者模式的缺點 1) 如果一個觀察目标對象有很多直接和間接的觀察者的話,将所有的觀察者都通知到會花費很多時間。 2) 如果在觀察者和觀察目标之間有循環依賴的話,觀察目标會觸發它們之間進行循環調用,可能導緻系統崩潰。 3) 觀察者模式沒有相應的機制讓觀察者知道所觀察的目标對象是怎麼發生變化的,而僅僅隻是知道觀察目标發生了變化。 4)  意外的更新 因為一個觀察者并不知道其它觀察者的存在 , 它可能對改變目标的最終代價一無所知。在目标上一個看似無害的的操作可能會引起一系列對觀察者以及依賴于這些觀察者的那些對象的更新。此外 , 如果依賴準則的定義或維護不當,常常會引起錯誤的更新 , 這種錯誤通常很難捕捉。       簡單的更新協定不提供具體細節說明目标中什麼被改變了 , 這就使得上述問題更加嚴重。如果沒有其他協定幫助觀察者發現什麼發生了改變,它們可能會被迫盡力減少改變。

8.實作

9.與其他相關模式

1) 終結者模式Mediator: 通過封裝複雜的更新語義 , ChangeManager充當目标和觀察者之間的中介者。 2) 單間模式Singleton: ChangeManager可使用Singleton模式來保證它是唯一的并且是可全局通路 的。

10.總結與分析

通過Observer模式,把一對多對象之間的通知依賴關系的變得更為松散,大大地提高了程式的可維護性和可擴充性,也很好的符合了開放-封閉原則。