observe pattern 觀察者模式

先看下觀察者模式的定義:

? ? ? The Observer Pattern defines a one-to-many denpendency between objects so that when one object changes state, all of its dependents are notified and updated automatically.:觀察者模式定義了對象間一對多依賴關系,使得當一個對象改變狀態,則所有依賴于它的對象都會得到通知并被自動更新。

? ? ? 觀察者模式又叫發布-訂閱(Publish--Subscribe)模式,模型—視圖(Model/View)模式,源—監聽器(Source/Listener)模式等。

? ? ? 觀察者模式定義了一種一對多的關系,讓多個觀察者同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有觀察者對象,使他們能夠自動能夠更新自己。

? ? ? 實現觀察者模式比較直觀的一種是“注冊-----通知----撤銷注冊”的形式。

首先,觀察者(Observer)將自己注冊到主題對象(Subject)中,主題對象將觀察者存放在一個容器(Container)中.

其次,主題對象發生了某種變化,從容器中得到所有注冊過的觀察者,將變化通知觀察者。

最后,觀察者告訴主題對象要撤銷觀察,主題對象從容器中將觀察者去除。

? ? ? 觀察者將自己注冊到主題對象的容器中時,主題對象不應該過問觀察者的具體類型,而是使用觀察者的接口。這樣做的優點是:假定程序中還有別的觀察者,那么只要這個觀察者也是相同的接口實現即可。一個主題對象可以對應多個觀察者,當主題對象發生變化的時候,他可以將消息一一通知給所有的觀察者。基于接口,而不是具體的實現------這一點為程序提供了更大的靈活性。

? ? ? 舉個例子:貓叫了一聲,驚醒了主人,嚇跑了老鼠。這個例子就可以用觀察者模式來實現。貓是主題對象,主人和老鼠是觀察者。具體實現類圖如下:

C#代碼實現:

public interface IObserver

? ? {

? ? ? ? void Update();

? ? }

? ? public interface ISubject

? ? {

? ? ? ? void AddObserver(IObserver obs);

? ? ? ? void RemoveObserver(IObserver obs);

? ? ? ? void Notify();

? ? }

? ? public class Mouse : IObserver

? ? {

? ? ? ? public void Update()

? ? ? ? {

? ? ? ? ? ? Console.WriteLine("Mouse is escaped");

? ? ? ? }

? ? }

? ? public class Master : IObserver

? ? {

? ? ? ? public void Update()

? ? ? ? {

? ? ? ? ? ? Console.WriteLine("Master is waken");

? ? ? ? }

? ? }

? ? public class Cat : ISubject

? ? {

? ? ? ? List<IObserver> list = new List<IObserver>();

? ? ? ? public void AddObserver(IObserver obs)

? ? ? ? {

? ? ? ? ? ? list.Add(obs);

? ? ? ? }

? ? ? ? public void RemoveObserver(IObserver obs)

? ? ? ? {

? ? ? ? ? ? list.Remove(obs);

? ? ? ? }

? ? ? ? public void Notify()

? ? ? ? {

? ? ? ? ? ? Console.WriteLine("Cat is crying");

? ? ? ? ? ? foreach (IObserver obs in list)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? obs.Update();

? ? ? ? ? ? }

? ? ? ? }

}

static void Main(string[] args)

{

? ? IObserver mouse = new Mouse();

? ? IObserver master = new Master();

? ? ISubject cat = new Cat();

? ? cat.AddObserver(mouse);

? ? cat.AddObserver(master);

? ? cat.Notify();

}

? ? ? 在.NET中,利用事件和委托來實現Observer模式更為簡單,也是一中更好的解決方案。在C#的事件中,委托充當了抽象的Observer接口,而提供事件的對象充當了目標(Subject)對象。其實委托是比抽象Observer接口更為松耦合的設計,因為委托只要求掛接的方法的聲明部分必須符合委托聲明的格式,而不需要像接口一樣必須要求類去完全實現之。觀察者模式之所以叫觀察者模式,并不是因為內部使用了ISubject,IObserver等來實現,而是因為這個模式解決了如下問題:“觀察者模式定義了對象間的一種一對多依賴關系,使得每當一個對象改變狀態,則所以依賴于它的對象都會得到通知并被自動更新”。也就是說,所有解決這個問題的方法都可以稱作觀察者模式。而且接口的概念也絕對不局限于C#里面的interface,接口只是一個契約,用來規范代碼的行為,delegate也是一個接口,它規定了什么樣的方法可以加載到delegate對應的event中,這也是一個契約,只是這個契約要比interface更簡單。

下面我們用委托事件機制來實現上面的功能,代碼如下:

public class Cat

? ? ? ? {

? ? ? ? ? ? public delegate void NotifyEventHandler();

? ? ? ? ? ? public event NotifyEventHandler NotifyEvent;

? ? ? ? ? ? public void Notify()

? ? ? ? ? ? {

? ? ? ? ? ? ? ? if (NotifyEvent != null)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? Console.WriteLine("Cat is crying");

? ? ? ? ? ? ? ? ? ? NotifyEvent();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? public class Master

? ? ? ? {

? ? ? ? ? ? public void Update()

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Console.WriteLine("Master is waken");

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? public class Mouse

? ? ? ? {

? ? ? ? ? ? public void Update()

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Console.WriteLine("Mouse is escaping");

? ? ? ? ? ? }

? ? ? ? }

static void Main(string[] args)

{

? Cat cat = new Cat();

? Master master = new Master();

? Mouse mouse = new Mouse();

? Cat.NotifyEventHandler notifyMaster = new Cat.NotifyEventHandler(master.Update);

Cat.NotifyEventHandler notifyMouse = new Cat.NotifyEventHandler(mouse.Update);

? cat.NotifyEvent += notifyMaster;

? cat.NotifyEvent += notifyMouse;

? cat.Notify();

}

應用場景:

對一個對象狀態的更新,需要其他對象同步更新,而且其他對象的數量動態可以變化。

對象僅需要將自己的更新通知給其他對象,而不需要知道其他對象的細節。

優點:

Subject 和obserer之間是送耦合的,分別可以各自獨立改變。

Subject在發送廣播通知的時候,無須指定具體的Observer,Observer可以自己決定是否需要訂閱Subject的通知。

遵守大部分GRASP原則和常用設計原則,高內聚,低耦合。

缺點:

如果一個Subject被大量的Observer訂閱的話,在廣播通知的時候可能會有效率問題。

相關原則

我們知道設計原則遠比模式重要,學習設計模式的同時一定要注意體會設計原則的理念。現在我們看看觀察者模式都符合的設計原則。

Identify the aspects of your application that vary and separate them from what stays the same(找到系統中變化的部分,將變化的部分同其他穩定的部分隔開). 在觀察者模式的應用場景里面變化的部分是Subject的狀態和Observer的數量。使用Observer模式可以很好的將這兩部分隔離開,我們可以任意改變Observer的數量而不需要去修改Subject, 而Subject的狀態也可以任意修改,同樣不會對其Observer有任何影響。

Program to an interface ,not an implementation(面向接口編程,而不要面向實現編程)? Subject和Observer都使用接口來實現。Subject只需要跟蹤那些實現了IObserver接口的對象,所以其只依賴于IObserver;而所有Observer都通過ISubject接口來注冊,撤銷,接收通知,所有它們也只依賴于ISubject;所以是面向接口編程的,這樣的實現方式使得Subject和Observer之間完全沒有任何的耦合。

Favor composition over inheritance(優先使用對象組合,而非類繼承) 觀察者模式使用對象組合將Subject和若干Observer聯系起來。它們之間的關系不是通過類的繼承而是在運行時的動態組合。

原文轉載出處:

https://blog.csdn.net/jxcr1984/article/details/53265038

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容