观察者模式(发布、订阅)之(上) 李朝强 李朝强

什么是观察者模式?

摘自百度百科的说法:观察者模式(有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

 说白了,就是一个主题,可以有N多个观察者,一个观察者,也可以订阅N多个主题。当一个主题,发生改变时,会通知订阅它的观察者,观察者收到通知后,可以做相应的处理。观察者模式,是软件设计模式中的一种。接下里,我们介绍下,使用C#实现的观察者模式。附上代码。

      首先,我们新建一个名为AppObserver的控制台项目。结构如下:

 Strategy目录下新建两个接口,一个IObserver(观察者)、一个ISubject(主题)。让我们看看,这两个接口分别定义了什么?

/*
 * Created by http://www.lichaoqiang.com
 * User: 李朝强
 * Date: 2016/9/2
 * Time: 16:25
 *
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections.Generic;

namespace AppObserver.Strategy
{
	/// <summary>
	/// Description of ISubject.
	/// </summary>
	public interface ISubject
	{
		/// <summary>
		/// 主题
		/// </summary>
		string Title{get;set;}

		/// <summary>
		/// 观察者
		/// </summary>
		List<IObserver> Observers{get;}

		/// <summary>
		/// 添加订阅
		/// </summary>
		/// <param name="observer"></param>
		void AddObserver(IObserver observer);

		/// <summary>
		/// 发布
		/// </summary>
		void Publish();
	}
}

观察者接口(IObserver):

/*
 * Created by http://www.lichaoqiang.com
 * User: 李朝强
 * Date: 2016/9/2
 * Time: 16:27
 *
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections.Generic;

namespace AppObserver.Strategy
{
	/// <summary>
	/// Description of IObserver.
	/// </summary>
	public interface IObserver
	{

		/// <summary>
		/// 名称
		/// </summary>
		string Name{get;}

		/// <summary>
		/// 主题
		/// </summary>
		List<ISubject> Subjects{get;}

		/// <summary>
		/// 通知
		/// </summary>
		void Notify(ISubject subject);

		/// <summary>
		/// 订阅
		/// </summary>
		/// <param name="subject"></param>
		void Subscribe(ISubject subject);

		/// <summary>
		/// 取消订阅
		/// </summary>
		/// <param name="subject"></param>
		void Unsubscribe(ISubject subject);

	}
}

接下来,新建一个Support文件夹,提供对以上两个接口的实现。具体代码如下:

主题:

/*
 * Created by http://www.lichaoqiang.com
 * User: 李朝强
 * Date: 2016/9/2
 * Time: 16:34
 *
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections.Generic;
using AppObserver.Strategy;

namespace AppObserver.Support
{
	/// <summary>
	/// Description of Subject.
	/// </summary>
	public class Subject:ISubject
	{

		/// <summary>
		/// 构造函数
		/// </summary>
		public Subject()
		{
			Observers = new List<IObserver>();
		}

		#region ISubject implementation

		/// <summary>
		/// 添加观察者
		/// </summary>
		/// <param name="observer"></param>
		void ISubject.AddObserver(IObserver observer)
		{
			Observers.Add(observer);
		}

		/// <summary>
		/// 发布
		/// </summary>
		void ISubject.Publish()
		{
			if (null != Observers && Observers.Count > 0)
				foreach (var item in Observers) {item.Notify(this);}
		}

		/// <summary>
		/// 主题
		/// </summary>
		string ISubject.Title {
			get;
			set;
		}

		/// <summary>
		/// 观察者
		/// </summary>
		public	List<IObserver> Observers { get; private set; }
		#endregion

	}
}

观察者:

/*
 * Created by http://www.lichaoqiang.com
 * User: 李朝强
 * Date: 2016/9/2
 * Time: 16:37
 *
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections.Generic;
using AppObserver.Strategy;

namespace AppObserver.Support
{
	/// <summary>
	/// 观察者
	/// </summary>
	public class Observer:IObserver
	{

		/// <summary>
		/// 构造函数
		/// </summary>
		public Observer()
		{
			Subjects = new List<ISubject>();
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="name"></param>
		public Observer(String name)
			: this()
		{
			Name = name;
		}

		#region IObserver implementation

		/// <summary>
		/// 名字
		/// </summary>
		public string Name{ get; private set; }

		/// <summary>
		/// 通知
		/// </summary>
		void IObserver.Notify(ISubject subject)
		{
			//这里具体可以处理你的业务逻辑
			//我们可以通过扩展suject对象,来传递信息
			Console.WriteLine("【{0}】收到最新通知(Notify)主题:{1}", this.Name, subject.Title);
		}

		/// <summary>
		/// 订阅
		/// </summary>
		/// <param name="subject">主题</param>
		void IObserver.Subscribe(ISubject subject)
		{
			subject.AddObserver(this);
			Subjects.Add(subject);
		}

		/// <summary>
		/// 取消订阅
		/// </summary>
		/// <param name="subject">主题</param>
		void IObserver.Unsubscribe(ISubject subject)
		{

		}

		/// <summary>
		///获取已订阅的主题
		/// </summary>
		public	List<ISubject> Subjects { get; private set; }

		#endregion
	}
}

完成以上几步,就简单的实现了观察者模式。让我们一起来看看效果吧。

场景:张三和李四两个人,一个爱好体育和娱乐,一个爱好体育。于是,张三,拿起IiPhone 6s plus,打开App,点击并订阅了《体育频道》、《娱乐频道》两个栏目,李四看了,也马上掏出小米5s,以迅雷不及掩耳盗铃之势,打开相同的APP,也同样订阅了《体育频道》这档栏目。就在这个时候,远在千里之外的一座大都市,一个S身材的MZ,坐在办公桌前,准备好了资讯内容,准备这个时候,向广大粉丝,推送这些信息。于是,她先把准备好的体育信息,标题为“张继科XXXX”的主题,推送出去。然后,接着隔壁同事老王,负责《娱乐频道》的有痣青年,把主题为《王宝强XXXX》的信息,推送出去。这个时候,张三和李四的手机,不约而同的响起了一声清脆的声音。打开一看,效果如下:

张三和李四,顿时沉迷其中,认认真真的阅读起了这些内容。

 张三、李四虚构故事,以娱大家,博君一笑,夫复何求哈。

时间: 2024-11-08 11:27:56

观察者模式(发布、订阅)之(上) 李朝强 李朝强的相关文章

观察者模式与发布/订阅模式区别

在翻阅资料的时候,有人把观察者(Observer)模式等同于发布(Publish)/订阅(Subscribe)模式,也有人认为这两种模式还是存在差异,而我认为确实是存在差异的,本质上的区别是调度的地方不同. 观察者模式 比较概念的解释是,目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更新接口.具体观察者和具体目标继承各自的基类,然后具体观察者把自己注册到具体目标里,在具体目标发生变化时候,调度观察者的更新方法. 比如有个"天气中心"的具体目标A,专门监听天气变化,而有个

上海市旅游局官方微博发布了“史上最强99个免费景点攻略”

近日,上海市旅游局官方微博发布了"史上最强99个免费景点攻略",详细列举了沪.苏.浙.皖.赣等地的99个免费景点,以及上海至周边部分景点可免除的路桥费.该微博一发布就受到了众多网友的追捧,不少网友表示在"十一"黄金周期间将"按图索骥". 上海市旅游局官方微博"乐游上海"称,该攻略是根据各路"驴友"."摄友"和各地旅游局提供的信息编制,属于最全的华东免费地图.攻略列出的99个免费景点共分五

JavaScript中发布/订阅模式的简单实例

 1.Observer模式要求希望接收到主题通知者的观察者必须订阅内容改变的事件. 2.Subscribe/Publish模式使用了一个主题/事件通道,这个通道介于订阅者和发布者之间.该事件系统允许代码定义应用程序的特定事件,该事件可以传递自定义参数,自定义参数包含订阅者所需要的值.其目的是避免订阅者和发布者产生依赖关系. 与Observer模式不同之处在于它允许任何订阅者执行适当的事件处理程序来注册和接收发布者发出的通知. 好吧,不明觉厉.下面是我的理解: 1.观察者模式中,目标对象负责维护观

使用Java8实现观察者模式的方法(上)_java

观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式,是四人组(GoF,即 Erich Gamma.Richard Helm.Ralph Johnson 和 John Vlissides)在1994合著的<设计模式:可复用面向对象软件的基础>中提出的(详见书中293-313页).尽管这种模式已经有相当长的历史,它仍然广泛适用于各种场景,甚至成为了标准Java库的一个组成部分.目前虽然已经有大量关于观察者模式的文章,但它们都专注于在 Java 中的实现,却忽视了

JavaScript中发布/订阅模式的简单实例_javascript技巧

上次研究观察者模式,很多文章说它也叫Subscribe/Publish(发布/订阅模式).可在<Javascript设计模式>一书中,这两种模式还是有些区别的.书中原话如下: 1.Observer模式要求希望接收到主题通知者的观察者必须订阅内容改变的事件. 2.Subscribe/Publish模式使用了一个主题/事件通道,这个通道介于订阅者和发布者之间.该事件系统允许代码定义应用程序的特定事件,该事件可以传递自定义参数,自定义参数包含订阅者所需要的值.其目的是避免订阅者和发布者产生依赖关系.

分布式EventBus的Socket实现:发布订阅

在这篇文章中,EventBus实现 - 发布订阅 - XML加载 所适用的范围只是本机的事件传播,要是牵 涉到多台服务器之间的事件传播就不行了,解决办法有用msmq解决的,Node.js解决的,也有用redis的 发布订阅解决的,这次用C# socket来实现,能实现立刻推送事件到所有订阅了相关event的server上. 这次的子系统适用的场景如下: 主要分2个部分:各个server使用的Event Bus Broker以及Event Bus Server. Broker与Server之间的通

Apache Kafka是分布式发布-订阅消息系统

转自: http://www.infoq.com/cn/articles/apache-kafka?utm_source=infoq&utm_medium=popular_links_homepage 简介 Apache Kafka是分布式发布-订阅消息系统.它最初由LinkedIn公司开发,之后成为Apache项目的一部分.Kafka是一种快速.可扩展的.设计内在就是分布式的,分区的和可复制的提交日志服务. Apache Kafka与传统消息系统相比,有以下不同: 它被设计为一个分布式系统,易

MS SQL 2008 发布订阅配置错误总结

      最近在配置SQL 2008的发布订阅功能时,遇到了几个小错误,顺便归纳总结一下(以后碰到各类关于发布订阅的错误都将收录.更新到这篇文章),方便自己在以后碰到这类问题时,能够迅速解决问题.毕竟人的记忆能力有时效性,时间久了,有可能有些东西就模糊了或忘了,好记性不如烂笔头. 错误1:在数据库服务器上新建本地发布服务时报错.                                                         (图1) 报错的具体细节如下所示: TITLE: Ne

15天玩转redis —— 第九篇 发布/订阅模式

本系列已经过半了,这一篇我们来看看redis好玩的发布订阅模式,其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果博主发表了文章,那么100个人就会同时收到通知邮件,除了这个 场景还能找到其他场景么,当然有啦,你想想,如果你要在内存里面做一个读写分离的程序,为了维持数据的完整性,你是不是需要保证在写入 的时候,也要分发到各个读内存的程序中呢?所以说场景还是很多的,在于你的挖掘~~~ 下面还是从基本命令入手: 一

SQL Server 2008 R2的发布订阅配置实践

    纸上得来终觉浅,绝知此事要躬行.搞技术尤其如此,看别人配置SQL SERVER的复制,发布-订阅.镜像.日志传送者方面的文章,感觉挺简单,好像轻轻松松的,但是当你自己去实践的时候,你会发现还真不是那么一回事,毕 竟环境不同.数据库版本或经验关系,你实践的时候会或多或少碰到一些问题,有可能人家是多次实践后,绕开了那些"坑",毕竟写文章是事后总结,人家台上一 分钟,台下十年功.闲话不扯了,进入正题,本文虽然简单,但是趁现在有时间,也记录一下前几天配置Replication的发布订阅