模式学习---用C#内置接口实现观察者模式

C#内部有二个泛型接口,IObservable<T>和IObserver<T>,IObservable是可观察的,就是主题Subject要实现的接口,IObserver是观察者要实现的接口,首先建一个WeatherData结构,这是主题要向观察者传递的数据。
public struct WeatherData
    {
        private double temperature;//温度
        private double humidity;//湿度

        public double Temperature
        {
            get => temperature;           
        }

        public double Humidity
        {
            get => humidity;           
        }

        public WeatherData(double temp,double humidity)
        {
            this.temperature = temp;
            this.humidity = humidity;
        }
    }
再建一个实现IObservable的类WeatherDataProvider,IObservable接口就一个很简单的方法 public IDisposable Subscribe(IObserver<T> observer),这个方法就是向内部的列表添加观察者,再返回一个可销毁的对象,所以要建一个私有的列表
 //观察者列表
        private List<IObserver<WeatherData>> observers;
还要在实现一个内部类,这个类用于返回可销毁的对象,所以要实现IDisposable接口,这个内部类很简单,就是保存一个观察者列表的引用,一个观察者的引用,在Dispose方法内从观察者列表中删除观察者,完整代码如下
private class Unsubscriber : IDisposable
        {
            private List<IObserver<WeatherData>> _observers;
            private IObserver<WeatherData> _observer;

            public Unsubscriber(List<IObserver<WeatherData>> observers, IObserver<WeatherData> observer)
            {
                this._observers = observers;
                this._observer = observer;
            }
            public void Dispose()
            {
                if (_observer != null && _observers.Contains(_observer))
                {
                    _observers.Remove(_observer);
                }
            }
        }
再实现方法Subscribe,向观察者列表添加观察者,再返回可销毁的内部类的一个实例。
 public IDisposable Subscribe(IObserver<WeatherData> observer)
        {
            if(!observers.Contains(observer))
            {
                observers.Add(observer);
            }
            return new Unsubscriber(observers, observer);
        }
再添加一个向观察者发送数据的方法,如果发生错误,就生成一个异常,所以建一个异常类,为简单,这个异常类啥也不做。
public class WeatherDataUnkownException:Exception
    {
    }
发送数据的方法
public void SendWeatherData(Nullable<WeatherData> weather)
        {
            foreach(var observer in observers)
            {
                if (!weather.HasValue)
                    observer.OnError(new WeatherDataUnkownException());
                else observer.OnNext(weather.Value);
            }
        }
或许我们还需要一个结束发送数据的方法,以通知每个观察者。
 public void EndTransmission()
        {
            foreach (var observer in observers.ToArray())
            {
                //调用每个观察者OnCompleted方法
                observer.OnCompleted();
            }              

            observers.Clear();
        }
完整代码如下
 public class WeatherDataProvider : IObservable<WeatherData>
    {
        //观察者列表
        private List<IObserver<WeatherData>> observers;

        public WeatherDataProvider()
        {
            observers = new List<IObserver<WeatherData>>();
        }

        private class Unsubscriber : IDisposable
        {
            private List<IObserver<WeatherData>> _observers;
            private IObserver<WeatherData> _observer;

            public Unsubscriber(List<IObserver<WeatherData>> observers, IObserver<WeatherData> observer)
            {
                this._observers = observers;
                this._observer = observer;
            }
            public void Dispose()
            {
                if (_observer != null && _observers.Contains(_observer))
                {
                    _observers.Remove(_observer);
                }
            }
        }
        public IDisposable Subscribe(IObserver<WeatherData> observer)
        {
            if(!observers.Contains(observer))
            {
                observers.Add(observer);
            }
            return new Unsubscriber(observers, observer);
        }

        public void SendWeatherData(Nullable<WeatherData> weather)
        {
            foreach(var observer in observers)
            {
                if (!weather.HasValue)
                    observer.OnError(new WeatherDataUnkownException());
                else observer.OnNext(weather.Value);
            }
        }

        public void EndTransmission()
        {
            foreach (var observer in observers.ToArray())
            {
                //调用每个观察者OnCompleted方法
                observer.OnCompleted();
            }              

            observers.Clear();
        }
    }
主题模型建好了,再建一个实现了IObserver<T>的观察者类,观察者类内部有保存一个私有的可销毁的对象private IDisposable unsubscriber,用于观察者取消订阅,每个观察者或许需要一个名称 private string instName。到今天我才明白,为什么叫观察者模式,观察者是变化的,除了要封装观察者外,订阅与取消订阅,主动权全在观察者,被观察者虽然保存有观察者列表,可以删除与添加,但并不主动用,被观察者只负责发送数据,这就是观察者模式。既然主动权全在观察者,所以观察者要建一个订阅的方法
 public virtual void Subscribe(IObservable<WeatherData> provider)
        {
            if (provider != null)
            {
                unsubscriber = provider.Subscribe(this);
            }
        }
用于取消订阅的方法
 public virtual void Unsubscribe()
        {
            unsubscriber.Dispose();
        }
下面就是三个实现IObserver<WeatherData>的三个方法
 public void OnCompleted()
        {
            Console.WriteLine($"天气数据发送完毕,不再向{instName}提供天气数据");
            Unsubscribe();
        }

        public void OnError(Exception error)
        {
            Console.WriteLine($"在向{instName}提供天气数据时,发生错误。");
        }

        public void OnNext(WeatherData value)
        {
            Console.WriteLine($"{instName}: 温度:{value.Temperature} 湿度:{value.Humidity}");
        }
我们来实现看看效果
static void Main(string[] args)
        {
            WeatherDataProvider provider = new WeatherDataProvider();
            WeatherDataReporter reporter1 = new WeatherDataReporter("东湖");

            reporter1.Subscribe(provider);

            WeatherDataReporter reporter2 = new WeatherDataReporter("汉口");
            reporter2.Subscribe(provider);

            WeatherDataReporter reporter3 = new WeatherDataReporter("汉阳");
            reporter3.Subscribe(provider);

            provider.SendWeatherData(new WeatherData(23, 35));
            Console.WriteLine("================================>");

            reporter1.Unsubscribe();
            provider.SendWeatherData(new WeatherData(28, 40));
            Console.WriteLine("===============================>");
            provider.EndTransmission();

            Console.WriteLine("\n运行结束");
            Console.ReadLine();
        }

效果图


运行正常,很好的实现了观察者模式。








猜你喜欢

转载自blog.csdn.net/fdc2017/article/details/80091219
今日推荐