C#中已經實現了觀察者模式,那就是事件,事件封裝了委托,使得委托的封裝性更好,在類的內部定義事件,然后在客戶端對事件進行注冊:
public class Subject { public event Action<int> MyEvent; public async Task ExecuteEvent() { for (int i = 0; i < 100; i++) { await Task.Delay(TimeSpan.FromSeconds(0.1)); Console.Write("."); if (i>50) { MyEvent(i); return; } } } }
class Program { static void Main(string[] args) { Subject sub = new Subject(); sub.MyEvent += (a) => { Console.WriteLine($"the temprature is {a} now ,please shutdown!"); }; Task task= sub.ExecuteEvent(); Console.ReadKey(); } }
可以說在C#中實現觀察者模式是非常方便的。
觀察者模式的定義:觀察者模式定義了對象之間的一對多的依賴,這樣一來,當一個對象改變狀態時,他的所有依賴着都會收到通知並自動更新。
上面的例子可能比較簡單,Subject類充當的就是一個主題,或者叫發布者,使用+=注冊的lambda充當的就是一個訂閱者,也就是Observer,(lambda表達式會生成一個匿名的類,更准確的說實際上這個匿名的類就是一個Observer)將會有很多的類似於這樣的訂閱者來對Subject的MyEvent事件進行注冊,所以Subject和Observer是一對多的。當我們執行Subject中的ExecuteEvent方法時,就是在滿足一定條件后發出通知,而Observer就會去執行相應的動作,這就是觀察者模式。因為這個模式涉及到了對象和對象之間的依賴,這么這里又涉及到一個概念,那就是耦合。
設計原則:為了交互對象之間的松耦合而努力。
手動實現的觀察者模式(java)
還是以headfirst設計模式這本書上的例子為依據,這個例子講的是一個氣象站(ISubject)和很多布告板(Observer)的故事,先上類圖:
觀察者模式中有兩個角色,一個是Subject,主題角色,這個角色用來發布消息,另一個是Observer,觀察者,用來接收消息。Subject和Observer的關系是一對多。
/// <summary> /// 定義一個主題對象的接口,主題對象可以發出通知。 /// 被觀察者(IObserver)接受並做出相應的動作。 /// 主題對象和觀察者之間是一對多的關系。 /// </summary> public interface ISubject { void RegisterObserver(IObserver observer); void RemoveObserver(IObserver observer); void NotifyObservers(); } public interface IObserver { void Update(float temp, float humidity, float pressure); } public interface IDisplay { void Display(); } /// <summary> /// ConcreteSubject角色 /// </summary> public class WeatherData:ISubject { private readonly IList<IObserver> _observers=new List<IObserver>(); public float Temp { get; set; } public float Humidity { get; set; } public float Pressure { get; set; } public void RegisterObserver(IObserver observer) { _observers.Add(observer); } public void RemoveObserver(IObserver observer) { _observers.Remove(observer); } public void NotifyObservers() { foreach (IObserver item in _observers) { item.Update(Temp,Humidity,Pressure); } } public void SetMeasurements(float temp, float humidity, float pressure) { Temp = temp; Humidity = humidity; Pressure = pressure; NotifyObservers(); } } public class CurrentConditionDisplay:IObserver,IDisplay { private float _temperature; private float _humidity; private ISubject _weatherData; public CurrentConditionDisplay(ISubject weatherData) { _weatherData = weatherData; _weatherData.RegisterObserver(this); } public void Update(float temperature, float humidity, float pressure) { _temperature = temperature; _humidity = humidity; Display(); } public void Display() { Console.WriteLine($"out temperature is {_temperature},out humidity is {_humidity}"); } }