什麼是觀察者模式?設計模式
觀察者模式(有時又被稱爲發佈(Publish)-訂閱(Subscribe)模式、模型-視圖(View)模式、源-收聽者(Listener)模式或從屬者模式)是軟件設計模式的一種。在此種模式中,一個目標物件管理全部相依於它的觀察者物件,而且在它自己的狀態改變時主動發出通知。這一般透過呼叫各觀察者所提供的方法來實現。此種模式一般被用來實現事件處理系統。this
觀察者設計模式定義了對象間的一種一對多的依賴關係,以便一個對象的狀態發生變化時,全部依賴於它的對象都獲得通知並自動刷新。---百度百科spa
顧名思義,就是觀察某個對象和某對象被觀察的模式,觀察者Observer也是訂閱者Subscriber,也是監聽者,而主題Subject也是Publisher也是源。這種模式提供一對多的關係,多個觀察者對應1個Subject..net
咱們先來看一下簡單的例子,如下例子轉載自這裏,且稍做修改。一我的A觀察水是否煮沸,若水沸騰則關閉電源。其中,人A是Observer(觀察者),水是Subject(主題),當水沸騰時,將通知人水沸騰了。固然,現實中水不能直接跟人說「我沸騰啦……」,代碼裏面天然是要寫成一個方法的。設計
首先,有一個觀察者的類Person:code
public class Person { public void Update(string str) { System.Console.WriteLine(str + "關電源"); } }
有一個被觀察的類Water,被觀察者基本含有3個部分:server
public class Water { private Person _person; private bool _isBoiled; public Water() { _isBoiled = false; } public void SetBoiled() { _isBoiled = true; NotifyObserver(); } public void AddObserver(Person person) { this._person = person; } public void RemoveObserver() { if (_person != null) _person = null; } public void NotifyObserver() { if (_isBoiled && _person != null) { _person.Update("水開了,"); _isBoiled = false; } } }
在這個例子中只有一個觀察者person,觀察對象water的狀態。對象
class Program { static void Main(string[] args) { Person person = new Person(); Water water = new Water(); water.AddObserver(person); water.SetBoiled(); System.Console.ReadLine(); } }
上述例子是直接使用SetBoiled()來強制將狀態變成true,達到通知的目的,在與硬件交互時,多是自動探測溫度,當溫度達到100℃時,將_isboiled設爲true,這裏就直接強制賦值了。blog
咱們知道,觀察模式是對象間一對多的關係,以上述例子爲例,一壺水正在燒,可能A在觀察它的溫度,B在觀察它是否沸騰,可是在它的溫度變化時老是會通知全部的觀察者A、B……當水的狀態,而A/B也會相應做出一些動做來改變自身,那麼AB都將有共同的一個方法Update(),由於可能會有更多的觀察者CDEF……全部,咱們寫一個接口IObserver:繼承
public interface IObserver { void Update(PublisherBase publisher); }
那麼全部的觀察者都必須實現這個更新的操做,本例中包括溫度觀察者和沸騰觀察者:
public class TemperatureObserver : IObserver { public void Update(PublisherBase publisher) { Water water =(Water) publisher ; System.Console.WriteLine("溫度:" + water.GetTemperature() + " 狀態:" + water.GetStatus().ToString()); } }
public class BoiledObserver:IObserver { string doSomething; public BoiledObserver(string doSomething) { this.doSomething = doSomething; } public void Update(PublisherBase publisher) { Water water = (Water)publisher; if (water.GetTemperature() >= 100) { System.Console.WriteLine("狀態:" + water.GetStatus().ToString()); System.Console.WriteLine("BoiledObserver:" + doSomething); } else { System.Console.WriteLine("沒開"); } } }
由於Subject有了更多的觀察者,那麼它如今就須要維護一個List來維護衆多的觀察者對象了,固然,不管對象都多少個,Subject必然有維護這些對象的增刪通知操做:
public class SubjectBase { protected bool _isChanged; protected List<IObserver> _observers = new List<IObserver>(); public SubjectBase() { _isChanged = false; } public void AddObserver(IObserver observer) { _observers.Add(observer); } public void RemoveObserver(IObserver observer) { _observers.Remove(observer); } public void NotifyObserver() { if (_isChanged) { foreach (IObserver observer in _observers) { observer.Update( this); } } } }
被觀察者水繼承SubjectBase,因爲不能直接獲取水溫的變化,咱們人爲的提供水溫變化的方法類模仿這樣一個動做:
public class Water:SubjectBase { private double _temperature; private WaterStatus _status; public Water() { this._temperature = 0; this._status = WaterStatus.Cold; } public Water(IObserver observer) { this.AddObserver(observer); } public double GetTemperature() { return _temperature; } public WaterStatus GetStatus() { return _status; } public void Change(double temperature) { _temperature = temperature; if (_temperature < 40) _status = WaterStatus.Cold; else if (_temperature >= 40 && _temperature < 60) _status = WaterStatus.Warm; else if (_temperature >= 60 && _temperature < 100) _status = WaterStatus.Hot; else _status = WaterStatus.Boiled; this._isChanged = true; this.NotifyObserver(); } }
public enum WaterStatus { Cold, Warm, Hot, Boiled }
看一下如何調用,假設有1個溫度觀察者,2個沸騰觀察者,首先要把他們維護進觀察者列表,當水溫變化時,water將會Notify各個觀察者,而觀察者就會自動Update各自的行爲或狀態:
class Program { static void Main(string[] args) { TemperatureObserver tempObserver = new TemperatureObserver(); BoiledObserver boiledObserver1 = new BoiledObserver("關閉電源……"); BoiledObserver boiledObserver2 = new BoiledObserver("繼續保溫……"); Water water = new Water(tempObserver); water.AddObserver(boiledObserver1); water.AddObserver(boiledObserver2); water.Change(45); System.Console.WriteLine(); water.Change(80); System.Console.WriteLine(); water.Change(100); System.Console.WriteLine(); System.Console.ReadLine(); } }
運行的結果:
能夠看得出來,每次Change溫度以後,water會通知全部的觀察者。固然,在實際應用中,更常見的一個例子是,當後臺數據更新時,將自動更新前臺界面上的數據,這時候,前臺界面是觀察者,後臺數據是被觀察者。