设计模式 ( 十七 ):Observer 观察者模式 -- 行为型
?
?
?
1.概述
一些面向?qū)ο蟮木幊谭绞?#xff0c;提供了一種構(gòu)建對象間復(fù)雜網(wǎng)絡(luò)互連的能力。當(dāng)對象們連接在一起時,它們就可以相互提供服務(wù)和信息。
通常來說,當(dāng)某個對象的狀態(tài)發(fā)生改變時,你仍然需要對象之間能互相通信。但是出于各種原因,你也許并不愿意因為代碼環(huán)境的改變而對代碼做大的修改。也許,你只想根據(jù)你的具體應(yīng)用環(huán)境而改進(jìn)通信代碼。或者,你只想簡單的重新構(gòu)造通信代碼來避免類和類之間的相互依賴與相互從屬。
2.問題
?
當(dāng)一個對象的狀態(tài)發(fā)生改變時,你如何通知其他對象?是否需要一個動態(tài)方案――一個就像允許腳本的執(zhí)行一樣,允許自由連接的方案?
?
3.解決方案
?????????????觀測模式:定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時, 所有依賴于它的對象都得到通知并被自動更新。
觀測模式允許一個對象關(guān)注其他對象的狀態(tài),并且,觀測模式還為被觀測者提供了一種觀測結(jié)構(gòu),或者說是一個主體和一個客體。主體,也就是被觀測者,可以用來聯(lián)系所有的觀測它的觀測者。客體,也就是觀測者,用來接受主體狀態(tài)的改變 觀測就是一個可被觀測的類(也就是主題)與一個或多個觀測它的類(也就是客體)的協(xié)作。不論什么時候,當(dāng)被觀測對象的狀態(tài)變化時,所有注冊過的觀測者都會得到通知。
觀測模式將被觀測者(主體)從觀測者(客體)種分離出來。這樣,每個觀測者都可以根據(jù)主體的變化分別采取各自的操作。(觀測模式和Publish/Subscribe模式一樣,也是一種有效描述對象間相互作用的模式。)觀測模式靈活而且功能強(qiáng)大。對于被觀測者來說,那些查詢哪些類需要自己的狀態(tài)信息和每次使用那些狀態(tài)信息的額外資源開銷已經(jīng)不存在了。另外,一個觀測者可以在任何合適的時候進(jìn)行注冊和取消注冊。你也可以定義多個具體的觀測類,以便在實(shí)際應(yīng)用中執(zhí)行不同的操作。
將一個系統(tǒng)分割成一系列相互協(xié)作的類有一個常見的副作用:需要維護(hù)相關(guān)對象間的一致性。我們不希望為了維持一致性而使各類緊密耦合,因為這樣降低了它們的可重用性。
?
?
4.適用性
?
在以下任一情況下可以使用觀察者模式:
? 當(dāng)一個抽象模型有兩個方面, 其中一個方面依賴于另一方面。將這二者封裝在獨(dú)立的對象中以使它們可以各自獨(dú)立地改變和復(fù)用。
? 當(dāng)對一個對象的改變需要同時改變其它對象 , 而不知道具體有多少對象有待改變。
? 當(dāng)一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之 , 你不希望這些對象是緊密耦合的。
?
5.結(jié)構(gòu)
?
?
6.模式的組成
?
觀察者模式包含如下角色:
目標(biāo)(Subject):?目標(biāo)知道它的觀察者。可以有任意多個觀察者觀察同一個目標(biāo)。 提供注冊和刪除觀察者對象的接口。
具體目標(biāo)(ConcreteSubject):??將有關(guān)狀態(tài)存入各ConcreteObserver對象。
觀察者(Observer):??為那些在目標(biāo)發(fā)生改變時需獲得通知的對象定義一個更新接口。當(dāng)它的狀態(tài)發(fā)生改變時, 向它的各個觀察者發(fā)出通知。
具體觀察者(ConcreteObserver): ??維護(hù)一個指向ConcreteSubject對象的引用。存儲有關(guān)狀態(tài),這些狀態(tài)應(yīng)與目標(biāo)的狀態(tài)保持一致。實(shí)現(xiàn)O b s e r v e r的更新接口以使自身狀態(tài)與目標(biāo)的狀態(tài)保持一致。
?
7.效果
?
Observer模式允許你獨(dú)立的改變目標(biāo)和觀察者。你可以單獨(dú)復(fù)用目標(biāo)對象而無需同時復(fù)用其觀察者, 反之亦然。它也使你可以在不改動目標(biāo)和其他的觀察者的前提下增加觀察者。
下面是觀察者模式其它一些優(yōu)點(diǎn):
1 )觀察者模式可以實(shí)現(xiàn)表示層和數(shù)據(jù)邏輯層的分離,并定義了穩(wěn)定的消息更新傳遞機(jī)制,抽象了更新接口,使得可以有各種各樣不同的表示層作為具體觀察者角色。
2 )在觀察目標(biāo)和觀察者之間建立一個抽象的耦合?:一個目標(biāo)所知道的僅僅是它有一系列觀察者 , 每個都符合抽象的Observer類的簡單接口。目標(biāo)不知道任何一個觀察者屬于哪一個具體的類。這樣目標(biāo)和觀察者之間的耦合是抽象的和最小的。因為目標(biāo)和觀察者不是緊密耦合的, 它們可以屬于一個系統(tǒng)中的不同抽象層次。一個處于較低層次的目標(biāo)對象可與一個處于較高層次的觀察者通信并通知它 , 這樣就保持了系統(tǒng)層次的完整。如果目標(biāo)和觀察者混在一塊 , 那么得到的對象要么橫貫兩個層次 (違反了層次性), 要么必須放在這兩層的某一層中(這可能會損害層次抽象)。
3) 支持廣播通信?:不像通常的請求, 目標(biāo)發(fā)送的通知不需指定它的接收者。通知被自動廣播給所有已向該目標(biāo)對象登記的有關(guān)對象。目標(biāo)對象并不關(guān)心到底有多少對象對自己感興趣 ;它唯一的責(zé)任就是通知它的各觀察者。這給了你在任何時刻增加和刪除觀察者的自由。處理還是忽略一個通知取決于觀察者。
4) 觀察者模式符合“開閉原則”的要求。
觀察者模式的缺點(diǎn)
1) 如果一個觀察目標(biāo)對象有很多直接和間接的觀察者的話,將所有的觀察者都通知到會花費(fèi)很多時間。
2) 如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話,觀察目標(biāo)會觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用,可能導(dǎo)致系統(tǒng)崩潰。
3) 觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對象是怎么發(fā)生變化的,而僅僅只是知道觀察目標(biāo)發(fā)生了變化。
4) ?意外的更新 因為一個觀察者并不知道其它觀察者的存在 , 它可能對改變目標(biāo)的最終代價一無所知。在目標(biāo)上一個看似無害的的操作可能會引起一系列對觀察者以及依賴于這些觀察者的那些對象的更新。此外 , 如果依賴準(zhǔn)則的定義或維護(hù)不當(dāng),常常會引起錯誤的更新 , 這種錯誤通常很難捕捉。
? ? ? 簡單的更新協(xié)議不提供具體細(xì)節(jié)說明目標(biāo)中什么被改變了 , 這就使得上述問題更加嚴(yán)重。如果沒有其他協(xié)議幫助觀察者發(fā)現(xiàn)什么發(fā)生了改變,它們可能會被迫盡力減少改變。
?
8.實(shí)現(xiàn)
?
在php的SPL支持觀察者模式,SPL 提供了 SplSubject 和 SplObserver 接口。
SplSubject 接口提供了attach()、detach()、notify() 三個方法。而 SplObserver 接口則提供了 update()方法。SplSubject 派生類維護(hù)了一個狀態(tài),當(dāng)狀態(tài)發(fā)生變化時 - 比如屬性變化等,就會調(diào)用 notify() 方法,這時,之前在 attach() 方法中注冊的所有 SplObserver 實(shí)例的 update() 方法就會被調(diào)用。接口定義如下:
?
?
?
我們擴(kuò)展上面的例子,根據(jù)目標(biāo)狀態(tài)而更新不同的觀察者:
?
?
?
?
?
9.與其他相關(guān)模式
?
1) 終結(jié)者模式Mediator: 通過封裝復(fù)雜的更新語義 , ChangeManager充當(dāng)目標(biāo)和觀察者之間的中介者。
2) 單間模式Singleton: ChangeManager可使用Singleton模式來保證它是唯一的并且是可全局訪問
的。
?
10.總結(jié)與分析
?
?
通過Observer模式,把一對多對象之間的通知依賴關(guān)系的變得更為松散,大大地提高了程序的可維護(hù)性和可擴(kuò)展性,也很好的符合了開放-封閉原則。?
參考:http://blog.csdn.net/hguisu/article/details/7556625轉(zhuǎn)載于:https://www.cnblogs.com/haore147/p/3888161.html
總結(jié)
以上是生活随笔為你收集整理的设计模式 ( 十七 ):Observer 观察者模式 -- 行为型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常见cmd命令,开发人员必备
- 下一篇: 按钮交互loading ---- 转圈圈