观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖着都会收到通知并自动更新。
设计原则 为了交互对象之间的松耦合设计而努力
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ObserverPattern 9 { 10 11 //创建发送者的接口 12 public interface IObserver 13 { 14 void update(float temp, float humidity, float pressure); 15 } 16 //主题接口,供注册和解除监听 17 public interface ISubject 18 { 19 void registerObserver(IObserver o); 20 void removeObserver(IObserver o); 21 void notifyObserver(); 22 } 23 //显示接口 24 public interface IDisplayElement 25 { 26 void display(); 27 } 28 29 //源,实现监听者的添加删除以及发送消息 30 public class WeatherData : ISubject 31 { 32 public ArrayList observers; 33 public float temperature; 34 public float humidity; 35 public float pressure; 36 37 38 public WeatherData() 39 { 40 observers = new ArrayList(); 41 } 42 43 44 public void registerObserver(IObserver o) 45 { 46 observers.Add(o); 47 } 48 49 public void removeObserver(IObserver o) 50 { 51 observers.Remove(o); 52 } 53 //给每个监听者发送消息 54 public void notifyObserver() 55 { 56 for (int i = 0; i < observers.Count; i++) 57 { 58 (observers[i] as IObserver).update(temperature, humidity, pressure); 59 } 60 } 61 62 //触发消息 63 public void measurementsChanged() 64 { 65 notifyObserver(); 66 } 67 //设置消息值 68 public void setMeasurements(float temperature, float humidity, float pressure) 69 { 70 this.temperature = temperature; 71 this.humidity = humidity; 72 this.pressure = pressure; 73 74 measurementsChanged(); 75 } 76 77 } 78 79 //监听者之一 80 public class CurrentConditionsDisplay : IObserver, IDisplayElement 81 { 82 83 84 85 public float temperature; 86 public float humidity; 87 public float pressure; 88 private ISubject WeatherData; 89 public CurrentConditionsDisplay(ISubject WeatherData) 90 { 91 this.WeatherData = WeatherData; 92 WeatherData.registerObserver(this);//把自己注册进去监听 93 } 94 95 //weather会调用这个方法 96 public void update(float temp, float humidity, float pressure) 97 { 98 this.temperature = temp; 99 this.humidity = humidity; 100 this.pressure = pressure; 101 display(); 102 } 103 //显示 104 public void display() 105 { 106 Console.WriteLine("Current conditions:" + temperature + "F degrees and " + humidity + "humidity"); 107 } 108 109 110 } 111 }
微软提供的观察者模式:
发布源要实现 IObservable<T> 接口(定义基于推送的通知的提供程序)
1 // 摘要: 2 // 定义基于推送的通知的提供程序。 3 // 4 // 类型参数: 5 // T: 6 // 提供通知信息的对象。 7 public interface IObservable<out T> 8 { 9 // 摘要: 10 // 通知提供程序:某观察程序将要接收通知。 11 // 12 // 参数: 13 // observer: 14 // 要接收通知的对象。 15 // 16 // 返回结果: 17 // 对允许观察者在提供程序发送完通知前停止接收这些通知的接口的引用。 18 IDisposable Subscribe(IObserver<T> observer); 19 }
订阅者要实现 IObserver<in T>
1 // 摘要: 2 // 提供用于接收基于推送的通知的机制。 3 // 4 // 类型参数: 5 // T: 6 // 提供通知信息的对象。 7 public interface IObserver<in T> 8 { 9 // 摘要: 10 // 通知观察者,提供程序已完成发送基于推送的通知。 11 void OnCompleted(); 12 // 13 // 摘要: 14 // 通知观察者,提供程序遇到错误情况。 15 // 16 // 参数: 17 // error: 18 // 一个提供有关错误的附加信息的对象。 19 void OnError(Exception error); 20 // 21 // 摘要: 22 // 向观察者提供新数据。 23 // 24 // 参数: 25 // value: 26 // 当前的通知信息。 27 void OnNext(T value); 28 }
示例代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace ObserverPattern 8 { 9 //坐标结构体 10 public struct Location 11 { 12 double lat, lon; 13 14 public Location(double latitude, double longitude) 15 { 16 this.lat = latitude; 17 this.lon = longitude; 18 } 19 20 public double Latitude 21 { get { return this.lat; } } 22 23 public double Longitude 24 { get { return this.lon; } } 25 } 26 27 28 29 /// <summary> 30 /// 这是个订阅者 31 /// </summary> 32 public class LocationReporter : IObserver<Location> 33 { 34 private IDisposable unsubscriber; 35 private string instName; 36 37 public LocationReporter(string name) 38 { 39 this.instName = name; 40 } 41 42 public string Name 43 { get { return this.instName; } } 44 /// <summary> 45 /// 订阅 46 /// </summary> 47 /// <param name="provider"></param> 48 public virtual void Subscribe(IObservable<Location> provider) 49 { 50 if (provider != null) 51 unsubscriber = provider.Subscribe(this); 52 } 53 // 通知观察者,提供程序已完成发送基于推送的通知。 54 public virtual void OnCompleted() 55 { 56 Console.WriteLine("The Location Tracker has completed transmitting data to {0}.", this.Name); 57 this.Unsubscribe(); 58 } 59 // 通知观察者,提供程序遇到错误情况。 60 public virtual void OnError(Exception e) 61 { 62 Console.WriteLine("{0}: The location cannot be determined.", this.Name); 63 } 64 // 向观察者提供新数据。 65 public virtual void OnNext(Location value) 66 { 67 Console.WriteLine("{2}: The current location is {0}, {1}", value.Latitude, value.Longitude, this.Name); 68 } 69 /// <summary> 70 /// 解除订阅 71 /// </summary> 72 public virtual void Unsubscribe() 73 { 74 unsubscriber.Dispose(); 75 } 76 } 77 78 /// <summary> 79 /// 源,实现推送消息的接口 IObservable<Location> 80 /// </summary> 81 public class LocationTracker : IObservable<Location> 82 { 83 /// <summary> 84 /// 实例化一个通知列表 85 /// </summary> 86 public LocationTracker() 87 { 88 observers = new List<IObserver<Location>>(); 89 } 90 91 private List<IObserver<Location>> observers; 92 /// <summary> 93 /// 新增订阅者 94 /// </summary> 95 /// <param name="observer">提供了实现接收者接口的实例</param> 96 /// <returns></returns> 97 public IDisposable Subscribe(IObserver<Location> observer) 98 { 99 if (!observers.Contains(observer)) 100 observers.Add(observer); 101 return new Unsubscriber(observers, observer); 102 } 103 104 private class Unsubscriber : IDisposable 105 { 106 private List<IObserver<Location>> _observers; 107 private IObserver<Location> _observer; 108 109 public Unsubscriber(List<IObserver<Location>> observers, IObserver<Location> observer) 110 { 111 this._observers = observers; 112 this._observer = observer; 113 } 114 115 public void Dispose() 116 { 117 if (_observer != null && _observers.Contains(_observer)) 118 _observers.Remove(_observer); 119 } 120 } 121 /// <summary> 122 /// 传送新的消息 123 /// </summary> 124 /// <param name="loc"></param> 125 public void TrackLocation(Nullable<Location> loc) 126 { 127 foreach (var observer in observers) 128 { 129 if (!loc.HasValue) 130 observer.OnError(new LocationUnknownException()); 131 else 132 observer.OnNext(loc.Value); 133 } 134 } 135 /// <summary> 136 /// 通知观察者,消息已经发送完了 137 /// </summary> 138 public void EndTransmission() 139 { 140 foreach (var observer in observers.ToArray()) 141 if (observers.Contains(observer)) 142 observer.OnCompleted(); 143 144 observers.Clear();//清空订阅者 145 } 146 } 147 /// <summary> 148 /// 定义发生错误时处理方法 149 /// </summary> 150 public class LocationUnknownException : Exception 151 { 152 internal LocationUnknownException() 153 { } 154 } 155 }
调用:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //实例化观察者1 2 ObserverPattern.LocationReporter lreporter1 = new ObserverPattern.LocationReporter("Observer1"); 3 //实例化观察者2 4 ObserverPattern.LocationReporter lreporter2 = new ObserverPattern.LocationReporter("Observer2"); 5 //实例化观察者3 6 ObserverPattern.LocationReporter lreporter3 = new ObserverPattern.LocationReporter("Observer3"); 7 //发布源 8 ObserverPattern.LocationTracker ltracker = new ObserverPattern.LocationTracker(); 9 10 lreporter1.Subscribe(ltracker);//观察者1订阅了源 11 lreporter2.Subscribe(ltracker);//观察者2订阅了源 12 lreporter3.Subscribe(ltracker);//观察者3订阅了源 13 ltracker.TrackLocation(new ObserverPattern.Location(1, 2));//源发布消息,订阅者们都会收到消息 14 ltracker.TrackLocation(new ObserverPattern.Location(3, 32)); 15 ltracker.TrackLocation(null); 16 ltracker.EndTransmission();//完成订阅,清空所有的订阅者 17 18 ltracker.TrackLocation(new ObserverPattern.Location(1, 2));//这个时候将不会有任何人接收到消息了 19 Console.ReadLine();