发布博文
随想
读书
音乐
其他
我想爱,想吃,还想在一瞬间变成天上半明半暗的云。
我想爱,想吃,还想在一瞬间变成天上半明半暗的云。
我想爱,想吃,还想在一瞬间变成天上半明半暗的云。
我想爱,想吃,还想在一瞬间变成天上半明半暗的云。

.net观察者模式(IObservable,IObserver)

1149
高光翔
2018-09-20 20:53

ggggg.jpg

观察者模式被定义为解决一个对象对多个对象的依赖问题。当一个对象的状态发生改变,它会自动通知其它依赖对象。.net框架中提供了IObservable<T>接口和IObserver<T>接口来实现观察者模式,IObservable<T>相当于Subject(主题)接口,下面我们就以代吗来说明下如何利用.net框架提供的观察者模式接口。

代码参考了《Head First设计模式》书中的观察者模式章节的业务场景,实现天气数据的实时推送,不同的天气数据展示板订阅天气数据主题,主题在数据更新后,实时推送给已订阅的天气数据展览版。书中给出了观察者模式的基础实现以及Java Api内置的观察者模式实现。下面我们给出.net Api内置的观察者模式实现。

       WeatherData类包含气温,湿度,气压等属性。

    class WeatherData
    {
        /// <summary>
        /// 气温
        /// </summary>
        public string temperature { get; set; }
        /// <summary>
        /// 湿度
        /// </summary>
        public string humility { get; set; }
        /// <summary>
        /// 气压
        /// </summary>
        public string pressure { get; set; }
    }

     WeatherDataPublisher类实现了IObservable接口,实现了Subscribe订阅方法。

class WeatherDataPublisher:IObservable<WeatherData>
    {
        List<IObserver<WeatherData>> observers = new List<IObserver<WeatherData>>();
        /// <summary>
        /// 订阅主题,将观察者添加到列表中
        /// </summary>
        /// <param name="observer"></param>
        /// <returns></returns>
        public IDisposable Subscribe(IObserver<WeatherData> observer)
        {
            observers.Add(observer);
            return new Unsubscribe(this.observers,observer);
        }
        /// <summary>
        /// 取消订阅类
        /// </summary>
        private class Unsubscribe : IDisposable
        {
            List<IObserver<WeatherData>> observers;
            IObserver<WeatherData> observer;
            public Unsubscribe(List<IObserver<WeatherData>> observers
            , IObserver<WeatherData> observer)
            {
                this.observer = observer;
                this.observers = observers;
            }
 
            public void Dispose()
            {
                if (this.observers != null)
                {
                    this.observers.Remove(observer);
                }
            }
        }
        /// <summary>
        /// 通知已订阅的观察者
        /// </summary>
        /// <param name="weatherData"></param>
        private void Notify(WeatherData weatherData)
        {
            foreach (var observer in observers)
            {
                observer.OnNext(weatherData);
            }
        }
        /// <summary>
        /// 接收最新的天气数据
        /// </summary>
        /// <param name="weatherData"></param>
        public void ReciveNewData(WeatherData weatherData)
        {
            Notify(weatherData);
        }
    }

下面我们建立一个抽象类WeatherDisplayBase实现了IObserver接口,所有的天气展示板(观察者)继承这个抽象类,需实现OnNext方法,即接收到新数据推送后要进行的数据处理展示工作,并且可重写OnCompletedOnError方法。

    abstract class WeatherDisplayBase : IObserver<WeatherData>
    {
        public virtual void OnCompleted()
        {
        }
        public virtual void OnError(Exception error)
        {
        }
        public abstract void OnNext(WeatherData value);
    }

      CurrentConditionDisplay类为当前天气状况展示板,继承WeatherDisplayBase抽象类,展示最新的天气数据。

class CurrentConditionDisplay:WeatherDisplayBase
{
    public override void OnNext(WeatherData value)
    {
         Console.WriteLine("------------------");
         Console.WriteLine("当前天气状况板");
         Console.WriteLine(string.Format("温度:{0}\n湿度:{1}\n气压:{2}", 
             value.temperature, value.humility, value.pressure));
    }
 }

       StatisticsConditionDisplay类为气温统计展示板,继承WeatherDisplayBase抽象类,展示历史最高温度,最低温度,平均温度。

    class StatisticsConditionDisplay : WeatherDisplayBase
    {
        List<float> temperatures = new List<float>();
        public override void OnNext(WeatherData value)
        {
            float temperature;
            if (float.TryParse(value.temperature, out temperature))
            {
                temperatures.Add(temperature);
            }
            Console.WriteLine("------------------");
            Console.WriteLine("温度统计板");
            Console.WriteLine(string.Format("平均温度:{0}\n最高温度:{1}\n最低温度:{2}", 
                temperatures.Average(), temperatures.Max(), temperatures.Min()));
        }
    }
class Program
    {
        static void Main(string[] args)
        {
            WeatherDataPublisher publisher = new WeatherDataPublisher();
            CurrentConditionDisplay currentDisplay=new CurrentConditionDisplay();
            StatisticsConditionDisplay statisticsDisplay 
            = new StatisticsConditionDisplay();
            //订阅当前天气展示板
            IDisposable currentDisplayUnsubscriber= 
            publisher.Subscribe(currentDisplay);
            //订阅气温统计展示板
            IDisposable statisticsDisplayUnsubscriber = 
            publisher.Subscribe(statisticsDisplay);
            
            for (int i = 0; ; i++)
            {
                WeatherData weatherData = new WeatherData();
               Console.WriteLine("请输入温度,湿度,压力");
               string input = Console.ReadLine();
               var array= input.Split(',');
               weatherData.temperature = array[0];
               weatherData.humility = array[1];
               weatherData.pressure = array[2];
               Console.WriteLine("");
                //将输入的新的天气数据传给天气数据发布器
               publisher.ReciveNewData(weatherData);
               Console.WriteLine("=============================");
            }
        }
}

      我们运行代码,并输入最新的温度,湿度,压力,已注册的天气展示板即可更新最新的数据。

温度.png

天气展示板从主题订阅后,在主题更新最新数据后,即可推送给各个观察者。后续如果再添加新的天气展示板,只需要实现IObserver接口,并通知主题注册即可。

参考:

https://www.cnblogs.com/heqichang/archive/2012/08/24/2653821.html

      https://docs.microsoft.com/zh-cn/dotnet/api/system.iobserver-1?redirectedfrom=MSDN&view=netframework-4.7.2


Insert title here Insert title here
打  赏