《HeadFirst設計模式》讀書筆記二:觀察者模式

做者:摺紙
我的博客: https://www.zhezhi.press
記錄菜雞的成長之旅!

1. 模式定義和特色

image.png

觀察者(Observer)模式的定義:指多個對象間存在一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並被自動更新。這種模式有時又稱做發佈-訂閱模式、模型-視圖模式,它是對象行爲型模式。java

觀察者模式是一種對象行爲型模式,其主要優勢以下。編程

  • 下降了目標與觀察者之間的耦合關係,二者之間是抽象耦合關係。符合依賴倒置原則。
  • 目標與觀察者之間創建了一套觸發機制。

它的主要缺點以下。跨域

  • 目標與觀察者之間的依賴關係並無徹底解除,並且有可能出現循環引用。
  • 當觀察者對象不少時,通知的發佈會花費不少時間,影響程序的效率。

2. 模式的類圖結構

image.png

觀察者須要獲取到某些數據,但只有主題對象纔是真正管理這些數據的角色;這比起全部觀察者統一控制同一份數據具備更低的耦合性ui

咱們常說的 高內聚,低耦合是什麼意思?個人理解:該緊密聯繫的時候就緊密聯繫,不應緊密聯繫的時候就該拆分出來。(同一模塊內功能沒有必要拆分)

鬆耦合

當兩個對象鬆耦合時它們依然能夠交互,但不瞭解彼此的細節(對象之間的互相依賴降到了最低) --> 實現了有彈性的系統spa

關於觀察者的一切,主題只知道觀察者實現了某個接口(也就是Observer接口)。主題不須要知道觀察者的具體類是誰、作了些什麼或其餘任何細節。設計

任什麼時候候咱們均可以增長新的觀察者。由於主題惟一依賴的東西是一個實現Observer接口的對象列表,因此咱們能夠隨時增長觀察者。事實上,在運行時咱們能夠用新的觀察者取代現有的觀察者,主題不會受到任何影響。一樣的,也能夠在任什麼時候候刪除某些觀察者。server

有新類型的觀察者出現時,主題的代碼不須要修改。咱們能夠獨立地複用主題或觀察者。若是咱們在其餘地方須要使用主題或觀察者,能夠輕易地複用。由於兩者並不是緊耦合。對象

改變主題或觀察者其中一方,並不會影響另外一方。由於二者是鬆耦合的,因此只要他們之間的接口仍被遵照,咱們就能夠自由地改變他們。繼承

設計原則:爲了交互對象之間的鬆耦合設計而努力

3. 模式的實現

3.1 Java內置觀察者模式類圖

image.png

3.1.1 如何把對象變成觀察者…

如同之前同樣,實現觀察者接口(java.uitl.Observer),而後調用任何Observable對象的addObserver)方法。不想再當觀察者時,調用deleteObserver()方法就能夠了。接口

3.1.2 可觀察者/主題要如何送出通知……

首先,你須要利用擴展java.util.Observable接口產生「可觀察者」類,而後,需個步驟:
①先調用setChanged()方法,標記狀態已經改變的事實。
②而後調用兩種notifyObservers0方法中的一個:
notifyobservers()或 notifyobservers(object arg)

3.1.3 觀察者如何接收通知……

同之前同樣,觀察者實現了更新的方法,可是方法的簽名不太同樣:
image.png
若是你想「推」(push)數據給觀察者,你能夠把數據看成數據對象傳送給notifyObservers(arg)方法。不然,觀察者就必須從可觀察者對象中「拉」(pull)數據。

其中 setChanged()方法是用來標記狀態是否改變的,好讓notifyObservers()知道當它被調用時應該更新觀察者。若是調用notifyObservers)以前沒有先調用setChanged(),觀察者就「不會」被通知。讓咱們看看Observable內部,以瞭解這一切:
image.png

3.2 自定義實現

3.2.1 java.util.Observable的弊端

java.uitl.Observable實現了它的notifyObservers()方法,這致使了通知觀察者的次序不一樣於咱們先前的次序。誰也沒有錯,只是雙方選擇不一樣的方式實現罷了。可是能夠肯定的是,若是咱們的代碼依賴這樣的次序,就是錯的。爲何呢?由於一旦觀察者/可觀察者的實現有所改變,通知次序就會改變,極可能就會產生錯誤的結果。這絕對不是咱們所認爲的鬆耦合。

首先,由於Observable是一個「類」,你必須設計一個類繼承它。若是某類想同時具備Observable類和另外一個超類的行爲,就會陷入兩難,畢竟Java不支持多重繼承。
這限制了Observable的複用潛力(而增長複用潛力不正是咱們使用模式最原始的動機嗎?)。

再者,由於沒有Observable接口,因此你沒法創建本身的實現,和Java內置的Observer API搭配使用,也沒法將java.util的實現換成另外一套作法的實現(比方說,Observable將關鍵的方法保護起來若是你看看ObservableAP1,你會發現setChanged)方法被保護起來了(被定義成protected)。那又怎麼樣呢?這意味着:除非你繼承自Observable,不然你沒法建立Observable實例並組合到你本身的對象中來。這個設計違反了第二個設計原則:「多用組合,少用繼承」。

若是你可以擴展java.util.Observable,那麼Observable「可能」能夠符合你的需求。不然,你可能須要像本章開頭的作法那樣本身實現這一整套觀察者模式。

4. 模式的應用場景

在軟件系統中,當系統一方行爲依賴另外一方行爲的變更時,可以使用觀察者模式鬆耦合聯動雙方,使得一方的變更能夠通知到感興趣的另外一方對象,從而讓另外一方對象對此作出響應。

經過前面的分析與應用實例可知觀察者模式適合如下幾種情形。
一、對象間存在一對多關係,一個對象的狀態發生改變會影響其餘對象。
二、當一個抽象模型有兩個方面,其中一個方面依賴於另外一方面時,可將這兩者封裝在獨立的對象中以使它們能夠各自獨立地改變和複用。
三、實現相似廣播機制的功能,不須要知道具體收聽者,只需分發廣播,系統中感興趣的對象會自動接收該廣播。
四、多層級嵌套使用,造成一種鏈式觸發機制,使得事件具有跨域(跨越兩種觀察者類型)通知。

5. 總結

設計原則:

  • 封裝變化
  • 多用組合 少用繼承
  • 針對接口編程 而不是針對實現編程
  • 爲交互對象之間的鬆耦合而努力
相關文章
相關標籤/搜索