今天学习了下观察者模式,在软件设计过程中,常常有类似这样的情况:许多部分(对象)与某一部分(对象)之间有种状态的依赖关系,即某一对象的状态发生改变时,要通知到所有的对象。比如:有一个天气预报观察站A,许多网站向它订阅了(通过某些协议)天气提供服务,当天气预报观察站A得到了最新天气信息时,就会通知到所有与它订阅过的网站,所有订阅过天气预报服务的网站就会实时更新天气信息;某一天,有另外一家观察站,设备更先进,信息更准确,价格更便宜,于是这些网站中某一个网站退订了观察站A的服务了,当观察站A再有信息更新的时候,只会通知到当前订阅的所有网站(不包括刚退订的网站)。这就是观察者模式,此例中,这些订阅天气预报的网站就充当了观察者角色。本文就主要关注如何实现这样的订阅服务:
首先,我们假设所有提供服务的机构都属于一个机构统一管理(这个机构提供所有的服务,如天气预报、杂志订阅……),将它抽象出来,定义一个抽象的提供者类Provider,包含订阅、退订、更新时通知所有订阅者三个方法,类关系视图如下所示:
各部分实现如下所示:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public abstract class Provider { protected List<ICustomer> customer = new List<ICustomer>(); //向使用者提供订阅方法(渠道) public void AddCustomer(ICustomer cus) { customer.Add(cus); } //向使用者提供退订方法(渠道) public void RemoveCustomer(ICustomer cus) { customer.Remove(cus); } //通知订阅者 public abstract void Update(); }
再定义一个模拟观察站A(WeatherProvider)继承自抽象的提供者(Provider),观察站A(WeatherProvider)继承来自提供者(Provider)的订阅、退订方法,并实现了更新时通知订阅者的方法,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class WeatherProvider:Provider { //提供天气预报的观察站名 private string providerName; //气温 private string temperature; public string Temperature { get { return temperature; } set { temperature = value; } } public string ProviderName { get { return providerName; } set { providerName = value; } } public WeatherProvider(string name, string temp) { this.providerName = name; this.temperature = temp; } //通知所有订阅者 public override void Update() { foreach (ICustomer cus in this.customer) { cus.SendMessage(providerName, temperature); } } }
现在我们模拟一些用户群体,每个用户都必须要实现下从提供服务处获取服务数据的方法(本文比如:只提供观察站名和当前气温),为了所有订阅者统一管理,定义一个接口:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public interface ICustomer { void SendMessage(string providerName,string temp); }
此接口规定所有订阅者接受更新天气的方法。所有订阅者必须继承自此接口,规定必须实现接受更新天气的方法:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
public class Customer:ICustomer { public Customer(string name) { this.name = name; } public string name { get; set; } public void SendMessage(string providerName, string temp) { Console.WriteLine("Hello! " + this.name + ", We are " + providerName + " , the temperrature is " + temp + "\n"); } }
观察者模式使用演示:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class Program { static void Main(string[] args) { //可以扩展出不同等级用户提供不同的服务内容 ICustomer customerA = new Customer("腾讯网"); ICustomer customerB = new Customer("新浪网"); //可以扩展出除天气预报外不同提供服务机构 Provider provider = new WeatherProvider("国家天气预报观察站", "10"); //订阅 provider.AddCustomer(customerA); provider.AddCustomer(customerB); provider.Update(); Console.WriteLine("——————————————————————"); //退订 provider.RemoveCustomer(customerA); provider.Update(); Console.ReadKey(); } }
程序运行结果:
欢迎大牛们多多指点!