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}"); } }