解釋: 函數
定義了一種一對多的依賴關係,讓多個觀察者對象同事監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知全部觀察者對象,使他們可以自動更新本身。優化
結構圖:3d
Subject類,主題通知者、抽象通知者。通常用一個抽象類或者一個接口實現。將全部對觀察者對象的引用保存在一個彙集裏,每個主題均可以有任何數量的觀察者。server
Observer類,抽象觀察者、更新接口。通常用一個抽象類或者一個接口實現。爲全部的具體觀察者定義一個接口,在獲得主題的通知時更新本身。對象
ConcreteSubject類,具體主題、具體通知者。一般用一個具體子類實現。將有關狀態存入具體觀察者對象。在具體主題的內部狀態改變時,給全部登記過的觀察者發出通知。blog
ConcreteObserver類,具體觀察者。一般用一個具體子類實現。實現抽象觀察者角色所要求的更新接口,以便使自己的狀態與主題的狀態相協調。能夠保存一個指向具體主題對象的引用。接口
客戶端代碼:事件
針對的問題:原型
將一個系統分隔成一系列相互協做的類有一個很很差的反作用。那就是須要維護相關對象間的一致性。咱們不但願爲了維持一致性而使各種緊密耦合。這樣會給維護、擴展、重用都帶來不便。event
優勢:
觀察者模式的關鍵對象:Subject和Observer。
一個Subject能夠有任意數目的依賴它的Observer,一旦Subject的狀態發生了變化,全部Observer均可以獲得通知。
Subject發出通知時,並不須要知道誰是它的觀察者(即,具體的觀察者是誰?)
任何一個具體觀察者不知道,不須要知道其餘觀察者的存在。
解除耦合。讓耦合的雙方都依賴於抽象,而不是依賴於具體。從而使得各自的變化都不會影響另外一邊的變化。依賴倒轉原則的最佳體現。
使用環境:
當一個對象的改變須要同時改變其餘對象的時候。且不知道具體有多少個對象有待改變。
當一個抽象模型有兩個方面,其中一方面依賴於另外一方面。觀察者模式能夠將這二者封裝在獨立的對象中,使他們各自獨立地改變和複用。
使用建議:
何時使用抽象類?何時使用接口?
當具體觀察者很類似,使用抽象類。這樣能夠共用一些代碼。用接口只是方法上的實現,沒什麼太大的意義。
當具體觀察者是風馬牛不相及的類,但它們都須要根據統治者的通知來作出Update()的操做,那使用接口就能夠實現。
缺點:
儘管用了依賴倒轉原則,可是「抽象通知者」仍是依賴「抽象觀察者」,即沒有了抽象觀察者,通知的功能格式完不成的。
每一個具體的觀察者,」更新「的方法不必定同名。
優化:
使用事件委託。去掉父類「抽象觀察者」,將」更新「方法名改成各自適合的方法名。
去除「抽象通知者」對「抽象觀察者」的依賴。將抽象通知類的「增長」、「減小」以及「通知」時遍歷抽象觀察者都去除。轉而讓客戶端使用委託來實現。解決耦合問題。
具體觀察類,更新方法名不一樣。
抽象通知者,不依賴抽象觀察,「增長」、「減小」、「通知」時遍歷抽象觀察者都不必了。
聲明一個委託
具體通知類,使用委託,實現不一樣方法名的「更新」。
客戶端:實現不一樣方法名的「更新」,實現抽象通知類與抽象觀察類的解綁,不用「增長」、「減小」,使用委託便可(一個委託能夠搭載多個方法,全部方法被依次喚起)。
對比優化前:耦合更加嚴重些。
委託和事件:
就是一種引用方法的類型。一旦爲委託分配了方法,委託將於該方法具備徹底相同的行爲。
委託方法的使用能夠像其餘任何方法同樣,具備參數和返回值。
委託能夠看作是對函數的抽象。是函數的‘類’,委託實例表明了一個具體的函數。delegate void EventHandler(),理解爲聲明瞭一個特殊的類;public event EventHandler Update(),理解爲聲明瞭一個時間委託方法叫「更新」;new EventHandler(tongshi1.CloseStockMarket),理解爲一個委託的實例,將tongshi1.CloseStockMarket()委託給huhansan.Update()了。
一個委託能夠搭載多個方法,全部方法被依次喚起。
更重要的是,委託對象所搭載的方法並不須要屬於同一個類。
前提:對託所搭載的全部方法必須具備相同的原型和形式(即,擁有相同的參數列表和返回值類型)。