设计模式-观察者模式-观察者模式与事件模型的区别讨论-.Net内置的观察者模式

UP主在这里简要的介绍下观察者模式:(详细的介绍请大家自行阅读相关书籍)
在这里先给出观察者模式的一个简要的定义:
发布者+订阅者=观察者模式
是不是感觉这个事件模型很像,别着急,UP主在最后会进行观察者模式与事件模型的讨论,供大家批评。
观察者的准确定义是:
观察者模式 定义了对象之间的一对多依赖,这样一来,当一个对象发生改变时,他的所有依赖者都会收到通知并会自动更新。
另外,观察者模式可不只是 简单的 主题发布,观察者收到通知并执行 的过程,
观察者也可以从主题处 拉 来信息,不接收主题的某些信息,甚至可以选择不再注册主题。
这些特性请大家看文中给出的两个程序。
具体大家请看书上的简图:
在这里插入图片描述
观察者模式提供了一种对象设计,让主题与观察者之间松耦合,让对象间的依赖降到了最低,建立有弹性的OO系统,能够应对变化。
书中给出了一个松耦合的观察者的例,UP主把它写出来了:
在这里插入图片描述

//为了松耦合,一切对象皆在接口的层面上进行操作
//主测试程序
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPattern
{
    internal class Program
    {
        static void Main(string[] args)
        {
            WeatherData weatherData = new WeatherData();
            FirstConditionDisplay firstConditionDisplay = new FirstConditionDisplay(weatherData);
            SecondConditionDisplay secondConditionDisplay = new SecondConditionDisplay(weatherData);
            ThirdConditionDisplay thirdConditionDisplay = new ThirdConditionDisplay(weatherData);
            weatherData.SetMessurements(37, 25, 1.2f);
            Console.WriteLine("*****************************");
            weatherData.SetMessurements(5, 19, 1.0f);
            Console.WriteLine("*****************************");
            weatherData.RemoveObserver(secondConditionDisplay);
            weatherData.SetMessurements(41, 19, 1.0f);
            Console.WriteLine("*****************************");
            weatherData.RegisterObserver(secondConditionDisplay);
            weatherData.SetMessurements(0, 30, 1.0f);
            Console.WriteLine("*****************************");
            weatherData.NotifyObserver();
            Console.WriteLine("*****************************");
            Console.ReadKey();
        }
    }
}

//天气信息接口
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPattern
{
    public interface ISubject
    {
        void RegisterObserver(IObserver ob);
        void RemoveObserver(IObserver ob);
        void NotifyObserver();
    }
}

//天气数据类,也是主题类
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPattern
{
    public class WeatherData:ISubject
    {
        private ArrayList observers;
        private float temperature;
        private float humidity;
        private float pressure;
        public WeatherData()
        {
            observers = new ArrayList();
        }
        public void NotifyObserver()
        {
            for(int i =0; i <observers.Count; i++)
            {
                IObserver observer = (IObserver)observers[i];
                observer.Update(temperature, humidity, pressure);
            }
        }

        public void RegisterObserver(IObserver ob)
        {
            observers.Add(ob);
        }

        public void RemoveObserver(IObserver ob)
        {
            int i = observers.IndexOf(ob);
            if (i >= 0)
            {
                observers.RemoveAt(i);
            }
        }
        public void MessurementsChanged()
        {
            NotifyObserver();
        }
        public void SetMessurements(float temperature, float humidity, float pressure)
        {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            MessurementsChanged();
        }
    }
}

//布告板接口, 也是观察者类的接口,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPattern
{
    public interface IObserver
    {
        void Update(float temperature, float humidity, float pressure);
    }
}
//展示布告板信息的接口,就一个函数,display
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPattern
{
    public interface IDisplayElement
    {
        void Display();
    }
}
//第一个观察者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPattern
{
    public class FirstConditionDisplay : IObserver, IDisplayElement
    {
        private float temperature;
        private float humidity;
        private float pressure;
        private ISubject weatherData;
        public FirstConditionDisplay(ISubject weatherData)
        {
            this.weatherData = weatherData;
            weatherData.RegisterObserver(this);
        }
        public void Display()
        {
            Console.WriteLine("1 号布告板:现在天气状况是:温度" + temperature + "°C , 湿度: " + humidity + "%,  压力:"+ pressure+ " * 100000 Pa");
        }

        public void Update(float temperature, float humidity, float pressure)
        {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            Display();
        }
    }
}
//第二个观察者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPattern
{
    public class SecondConditionDisplay : IObserver, IDisplayElement
    {
        private float temperature;
        private float humidity;
        private float pressure;
        private ISubject weatherData;
        public SecondConditionDisplay(ISubject weatherData)
        {
            this.weatherData = weatherData;
            weatherData.RegisterObserver(this);
        }
        public void Display()
        {
            Console.WriteLine("2 号布告板:现在天气状况是:温度" + temperature + "°C , 湿度: " + humidity + "%,  压力:" + pressure + " * 100000 Pa");
        }

        public void Update(float temperature, float humidity, float pressure)
        {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            Display();
        }
    }
}
//第三个观察者
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPattern
{
    public class ThirdConditionDisplay : IObserver, IDisplayElement
    {
        private float temperature;
        private float humidity;
        private float pressure;
        private ISubject weatherData;
        public ThirdConditionDisplay(ISubject weatherData)
        {
            this.weatherData = weatherData;
            weatherData.RegisterObserver(this);
        }
        public void Display()
        {
            Console.WriteLine("3 号布告板:现在天气状况是:温度" + temperature + "°C , 湿度: " + humidity + "%,  压力:" + pressure + " * 100000 Pa");
        }

        public void Update(float temperature, float humidity, float pressure)
        {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            Display();
        }
    }
}
//后面可以新建观察者,并可以在主测试函数里向发布者(主题)订阅。

另外,.NET C# 野提供了内置的观察者模式,有两个接口:
IObservable
IObserver
下面UP主也会一并给出C# 中内置的的观察者模式的应用:
在这里插入图片描述

//主测试函数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPatternUseObservable
{
    internal 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<3 ; 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("=============================");
            }
        }
    }
}

//天气数据类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

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

//天气数据发布类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPatternUseObservable
{
    internal 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>
        /// <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);
        }
    }
}
//观察者向主题取消订阅类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPatternUseObservable
{
    /// <summary>
    /// 取消订阅类
    /// </summary>
    public 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);
            }
        }
    }
}

//观察者类:布告板类抽象类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

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

//第一个观察者类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPatternUseObservable
{
    public  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()));
            Console.WriteLine("------------------");
        }
    }
}
//第二个观察者类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObserverPatternUseObservable
{
    public 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));
            Console.WriteLine("------------------");
        }
    }
}

那好,如果你都把上面的项目仔细的调试运行,你就会细细的发现文章开头所讲的概念了。
那么,问题来了,像不像事件模型?
是的,很像,我将一个简单的邮局发报纸的事件模型项目给写出来,如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 事件测试Demo
{
	public class Post
	{
		public delegate void EventHandler(object sender);
		public event EventHandler Evt;
		public void Run()
		{
			Console.WriteLine("邮局:新报纸出来喽");
			Evt(this);
		}
	}
	public class PersonA
	{
		public void PersonAReaction(object sender)   //A的事件处理程序
		{
			Console.WriteLine("PersonA:新报纸来啦,赶紧用来垫东西!");
		}
	}
	public class PersonB
	{
		public void PersonBReaction(object sender) //B的事件处理程序
		{
			Console.WriteLine("PersonB:新报纸来啦,赶紧阅读阅读看看有啥新闻!");
		}
	}
	public class PersonC
	{
		public void PersonCReaction(object sender)//C的事件处理程序
		{
			Console.WriteLine("PersonC:新报纸来啦,下一年的报纸费用还得付,怎么办,快没钱了!");
		}
	}
	class Program
	{
		static void Main(string[] args)
		{
			Post p = new Post();  //邮局
			PersonA a = new PersonA();  //订阅者A
			PersonB b = new PersonB();  //订阅者B
			PersonC c = new PersonC();  //订阅者C
			p.Evt += new Post.EventHandler(a.PersonAReaction); //订阅报纸
			p.Evt += new Post.EventHandler(b.PersonBReaction);  //订阅报纸
			p.Evt += new Post.EventHandler(c.PersonCReaction);  //订阅报纸
			//触发事件,发报纸喽
			p.Run();
			Console.ReadKey();
		}
	}
}


对观察者与事件之间做一下小小的讨论:

1.事件就是观察者模式的一种应用
2.观察者模式----> 事件
主题----> 事件源
主题状态----> 事件(事件源发送给监听者的信息)
观察者----> 监听者
3.实际运用中
目前实际运用中,我们的工具基本都提供好了接口调用,一般使用的话,我们只需要知道做三件事
1.定义参数----> 状态、传递个监听者的值
2.监听者的逻辑处理
3.找到发布事件的地方,发布事件即可

以下博客可以参考:
https://blog.csdn.net/qq_23980427/article/details/53443349
https://www.jianshu.com/p/6020dffeceed
https://www.cnblogs.com/aoguren/p/4680692.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值