C#实现发布订阅模式
首先给出项目的结构
IPublish.cs的源码:
namespace NsWebChat.PublishSubscribe
{
/// <summary>
/// 发布事件基础接口
/// </summary>
public interface IPublish
{
string PublishTag { get; set; }
object PublishData { get; set; }
}
}
IPubSubCenter.cs的源码:
namespace NsWebChat.PublishSubscribe
{
/// <summary>
/// 订阅发布中心基础接口
/// </summary>
public interface IPubSubCenter
{
/// <summary>
/// 订阅事件
/// </summary>
bool AddSubscribe(string tag, Func<ISubscribe, object, object> method, object data, string name);
bool AddSubscribe(string tag, Func<ISubscribe, object, object> method, string name);
bool AddSubscribe(Subscribe subscribe);
/// <summary>
/// 获得指定事件的订阅列表
/// </summary>
SubscribeList GetSubscribeList(string tag);
/// <summary>
/// 获得订阅
/// </summary>
Subscribe GetSubscribe(string tag, string name);
/// <summary>
/// 删除订阅
/// </summary>
void RemoveSubscribe(string tag, string name); /// <summary>
/// 发布事件
/// </summary>
IEnumerable<Object> Publish(string tag, object data);
IEnumerable<Object> Publish(string tag);
IEnumerable<Object> Publish(Publish publish);
}
}
ISubscribe.cs的源码:
namespace NsWebChat.PublishSubscribe
{
/// <summary>
/// 订阅事件基础接口
/// </summary>
public interface ISubscribe
{
/// <summary>
/// 订阅的事件
/// </summary>
string SubscribeTag { get; set; }
/// <summary>
/// 订阅的名称
/// </summary>
string SubscribeName { get; set; }
/// <summary>
/// 响应发布时传递的参数
/// </summary>
object Data { get; set; }
/// <summary>
/// 响应发布的方法
/// </summary>
Func<ISubscribe, object, object> SubscribeMethod { get; set; }
/// <summary>
/// 调用订阅方法
/// </summary>
object Invoke(object val);
}
}
Publish.cs的源码:
namespace NsWebChat.PublishSubscribe
{
/// <summary>
/// 发布事件基类
/// </summary>
public class Publish : IPublish
{
private string _publishTag;
private object _publishData; public Publish()
{
} public Publish(string tag)
: this(tag, new object())
{ } public Publish(string tag, object val)
{
_publishTag = tag;
_publishData = val;
} public string PublishTag
{
get
{
return _publishTag;
}
set
{
_publishTag = value;
}
} public object PublishData
{
get
{
return _publishData;
}
set
{
_publishData = value;
}
}
}
}
PubSubCenter.cs的源码:
namespace NsWebChat.PublishSubscribe
{
/// <summary>
/// 订阅发布中心基类
/// </summary>
public class PubSubCenter : IPubSubCenter {
private Dictionary<string, SubscribeList> _pubsubList = new Dictionary<string, SubscribeList>(); public bool AddSubscribe(string tag, Func<ISubscribe, object, object> method, object data ,string name)
{
Subscribe subscribe = new Subscribe();
subscribe.Data = data;
subscribe.SubscribeMethod = method;
subscribe.SubscribeTag = tag;
subscribe.SubscribeName = name;
return AddSubscribe(subscribe);
} public bool AddSubscribe(string tag, Func<ISubscribe, object, object> method, string name)
{
return AddSubscribe(tag, method, new object(),name);
} public bool AddSubscribe(Subscribe subscribe)
{
if (subscribe == null)
{
return false;
}
else
{
if (String.IsNullOrEmpty(subscribe.SubscribeName))
{
return false;
}
Subscribe subscribet = GetSubscribe(subscribe.SubscribeTag, subscribe.SubscribeName);
if (subscribet != null)
{
return false;
}
else
{
if (_pubsubList.ContainsKey(subscribe.SubscribeTag))
{
_pubsubList[subscribe.SubscribeTag].Add(subscribe);
}
else
{
SubscribeList list = new SubscribeList();
list.Add(subscribe);
_pubsubList.Add(subscribe.SubscribeTag, list);
}
return true;
}
}
} public SubscribeList GetSubscribeList(string tag)
{
if (_pubsubList.ContainsKey(tag))
{
return _pubsubList[tag];
}
else
{
return new SubscribeList();
}
} public Subscribe GetSubscribe(string tag, string name)
{
if (_pubsubList.ContainsKey(tag))
{
foreach (Subscribe item in _pubsubList[tag])
{
if (item.SubscribeName == name)
{
return item;
}
}
return null;
}
else
{
return null;
}
} public void RemoveSubscribe(string tag, string name)
{
Subscribe subscribe = GetSubscribe(tag, name);
_pubsubList[tag].Remove(subscribe);
} public IEnumerable<object> Publish(string tag, object data)
{
if (_pubsubList.ContainsKey(tag))
{
foreach (Subscribe item in _pubsubList[tag])
{
yield return item.Invoke(data);
}
}
else
{
yield break;
}
} public IEnumerable<object> Publish(string tag)
{
return Publish(tag, new object());
} public IEnumerable<object> Publish(Publish publish)
{
return Publish(publish.PublishTag, publish.PublishData);
}
}
}
Subscribe.cs源码:
namespace NsWebChat.PublishSubscribe
{
/// <summary>
/// 订阅事件基类
/// </summary>
public class Subscribe : ISubscribe
{
private object _data;
private Func<ISubscribe, object, object> _subscribeMethod;
private string _subscribeTag;
private string _subscribeName; public Subscribe()
{
} public Subscribe(string tag, Func<ISubscribe, object, object> method)
: this(tag, method, "")
{ } public Subscribe(string tag, Func<ISubscribe, object, object> method, object data)
: this(tag, method, data, "")
{ } public Subscribe(string tag, Func<ISubscribe, object, object> method,string name)
: this(tag, method, new object(), name)
{ } public Subscribe(string tag, Func<ISubscribe, object, object> method, object data,string name)
{
_data = data;
_subscribeTag = tag;
_subscribeMethod = method;
_subscribeName = name;
} public object Data
{
get
{
return _data;
}
set
{
_data = value;
}
} public Func<ISubscribe, object, object> SubscribeMethod
{
get
{
return _subscribeMethod;
}
set
{
_subscribeMethod = value;
}
} public object Invoke(object val)
{
return SubscribeMethod(this, val);
} public string SubscribeTag
{
get
{
return _subscribeTag;
}
set
{
_subscribeTag = value;
}
} public string SubscribeName
{
get
{
return _subscribeName;
}
set
{
_subscribeName = value;
}
}
}
}
SubscribeList.cs的源码:
namespace NsWebChat.PublishSubscribe
{
/// <summary>
/// 订阅列表
/// </summary>
public class SubscribeList : IList<Subscribe>
{
private List<Subscribe> subscribes = new List<Subscribe>(); public int IndexOf(Subscribe item)
{
return subscribes.IndexOf(item);
} public void Insert(int index, Subscribe item)
{
subscribes.Insert(index, item);
} public void RemoveAt(int index)
{
subscribes.RemoveAt(index);
} public Subscribe this[int index]
{
get
{
return subscribes[index];
}
set
{
subscribes[index] = value;
}
} public void Add(Subscribe item)
{
subscribes.Add(item);
} public void Clear()
{
subscribes.Clear();
} public bool Contains(Subscribe item)
{
return subscribes.Contains(item);
} public void CopyTo(Subscribe[] array, int arrayIndex)
{
subscribes.CopyTo(array, arrayIndex);
} public int Count
{
get
{
return subscribes.Count;
}
} public bool IsReadOnly
{
get { return false; }
} public bool Remove(Subscribe item)
{
return subscribes.Remove(item);
} public IEnumerator<Subscribe> GetEnumerator()
{
return subscribes.GetEnumerator();
} System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return subscribes.GetEnumerator();
}
}
}
下面是单元测试的源码(PubSubCenterTest.cs):
namespace WebChatUnitTest
{
[TestClass]
public class PubSubCenterTest
{
public object Test1(ISubscribe subscribe, object data)
{
Assert.IsTrue(subscribe.Data == data);
return data;
} public object Test2(ISubscribe s, object d)
{
return d;
} public object Test3(ISubscribe s, object d)
{
return d;
} public object Test4(ISubscribe s, object d)
{
return d;
} public object Test5(ISubscribe s, object d)
{
return s.SubscribeName;
} //测试删除订阅
[TestMethod]
public void TestRemoveSubscribe()
{
PubSubCenter pbc = new PubSubCenter();
pbc.AddSubscribe("t1", Test5, "");
pbc.AddSubscribe("t1", Test5, "");
pbc.RemoveSubscribe("t1", "");
List<string> al = new List<string>();
foreach (string item in pbc.Publish("t1"))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsTrue(al[] == "");
pbc.AddSubscribe("t1", Test5, "");
pbc.RemoveSubscribe("t1", "");
al.Clear();
foreach (string item in pbc.Publish("t1"))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsTrue(al[] == "");
} //测试重载版本的订阅发布
[TestMethod]
public void TestMoreSubscribeAndPublish()
{
PubSubCenter pbc = new PubSubCenter();
Subscribe subscribe = new Subscribe("t1", Test2, "", "");
Subscribe subscribe2 = new Subscribe("t1", Test2, "");
Subscribe subscribe3 = new Subscribe();
subscribe3.SubscribeMethod = Test2;
subscribe3.SubscribeName = "";
subscribe3.SubscribeTag = "t1";
pbc.AddSubscribe(subscribe);
pbc.AddSubscribe(subscribe2);
pbc.AddSubscribe(subscribe3);
pbc.AddSubscribe("t1", Test2, "");
pbc.AddSubscribe("t1", Test2, "", "");
List<object> al = new List<object>();
foreach (object item in pbc.Publish("t1"))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
al.Clear();
foreach (object item in pbc.Publish("t1",""))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]); Publish pub = new Publish("t1");
al.Clear();
foreach (object item in pbc.Publish(pub))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]); pub = new Publish("t1", "");
al.Clear();
foreach (object item in pbc.Publish(pub))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]); pub = new Publish();
pub.PublishData = "";
pub.PublishTag = "t1";
al.Clear();
foreach (object item in pbc.Publish(pub))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
Assert.IsNotNull(al[]);
} //测试重名订阅事件
[TestMethod]
public void TestSameNameSubscribe()
{
PubSubCenter pbc = new PubSubCenter();
pbc.AddSubscribe("t1", Test2, "");
pbc.AddSubscribe("t1", Test2, "");
pbc.AddSubscribe("t1", Test2, "");
List<string> al = new List<string>();
foreach (string item in pbc.Publish("t1", ""))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsTrue(al[] == "");
Assert.IsTrue(al[] == "");
} //测试多方法订阅单事件
[TestMethod]
public void TestMoreSubscribeToOnePublish()
{
PubSubCenter pbc = new PubSubCenter();
pbc.AddSubscribe("t1", Test2, "");
pbc.AddSubscribe("t1", Test3, "");
pbc.AddSubscribe("t1", Test4, "");
List<string> al = new List<string>();
foreach (string item in pbc.Publish("t1", ""))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsTrue(al[] == "");
Assert.IsTrue(al[] == "");
Assert.IsTrue(al[] == "");
} //测试单方法订阅多事件
[TestMethod]
public void TestOneSubscribeToMorePublish()
{
PubSubCenter pbc = new PubSubCenter();
pbc.AddSubscribe("t1", Test1, "", "t1");
pbc.AddSubscribe("t2", Test1, "", "t2");
pbc.AddSubscribe("t3", Test1, "", "t3");
pbc.AddSubscribe("t4", Test1, "", "t4");
IList<String> al = new List<String>();
foreach(String item in pbc.Publish("t1",""))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsTrue(al[] == "");
al.Clear();
foreach (String item in pbc.Publish("t2", ""))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsTrue(al[] == "");
al.Clear();
foreach (String item in pbc.Publish("t3", ""))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsTrue(al[] == "");
al.Clear();
foreach (String item in pbc.Publish("t4", ""))
{
al.Add(item);
}
Assert.IsTrue(al.Count == );
Assert.IsTrue(al[] == "");
}
}
}
C#实现发布订阅模式的更多相关文章
- 15天玩转redis —— 第九篇 发布/订阅模式
本系列已经过半了,这一篇我们来看看redis好玩的发布订阅模式,其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果 ...
- 第五章 --- 关于Javascript 设计模式 之 发布-订阅模式
先来个最简单的 发布订阅模式 document.body.addEventListener('click',function(){ alert(123); }); document.body.clic ...
- NetMQ(三): 发布订阅模式 Publisher-Subscriber
ZeroMQ系列 之NetMQ 一:zeromq简介 二:NetMQ 请求响应模式 Request-Reply 三:NetMQ 发布订阅模式 Publisher-Subscriber 四:NetMQ ...
- C# 委托和事件 与 观察者模式(发布-订阅模式)讲解 by天命
使用面向对象的思想 用c#控制台代码模拟猫抓老鼠 我们先来分析一下猫抓老鼠的过程 1.猫叫了 2.所有老鼠听到叫声,知道是哪只猫来了 3.老鼠们逃跑,边逃边喊:"xx猫来了,快跑啊!我是老鼠 ...
- 4.js模式-发布-订阅模式
1. 发布-订阅模式 var observe = (function(){ var events = {}, listen, trigger, remmove; listen = function(k ...
- RabbitMQ/JAVA (发布/订阅模式)
发布/订阅模式即生产者将消息发送给多个消费者. 下面介绍几个在发布/订阅模式中的关键概念-- 1. Exchanges (转发器) 可能原来我们都是基于一个队列发送和接收消息.现在介绍一下完整的消息传 ...
- Javascript中理解发布--订阅模式
Javascript中理解发布--订阅模式 阅读目录 发布订阅模式介绍 如何实现发布--订阅模式? 发布---订阅模式的代码封装 如何取消订阅事件? 全局--发布订阅对象代码封装 理解模块间通信 回到 ...
- ActiveMQ发布订阅模式
ActiveMQ的另一种模式就SUB/HUB即发布订阅模式,是SUB/hub就是一拖N的USB分线器的意思.意思就是一个来源分到N个出口.还是上节的例子,当一个订单产生后,后台N个系统需要联动,但有一 ...
- redis的发布订阅模式
概要 redis的每个server实例都维护着一个保存服务器状态的redisServer结构 struct redisServer { /* Pubsub */ // 字典,键为频道, ...
- 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码
最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...
随机推荐
- IP地址和CIDR
IP地址(IPV4) IPV4的地址是一个32位的二进制数,由网络ID和主机ID两部分组成,用来在网络中唯一的标识一台计算机.IP地址通常用四组3位的十进制数表示,中间用.分割,例如:192.168. ...
- ADB与AVD的常见问题
一.adb问题常用解决方法 若是模拟器启动正常,但是adb检测不到模拟器,我们给他一套不解释连招,下面教大家几招基础拳法. 1.基础拳法一:循环自动检测 下图那个小按钮,点它,狠狠的点它,然后点运行, ...
- main函数的参数argc和argv
版权声明:本文为博主原创文章,转载请注明CSDN博客源地址!共同学习,一起进步~ https://blog.csdn.net/Eastmount/article/details/20413773 该篇 ...
- Effective Java - Item 1: Consider static factory methods instead of constructors
考虑使用静态工厂方法来替代构造方法, 这样的做的好处有四点. 1. 更好的表意 有的构造方法实际上有特殊的含义, 使用静态工厂方法能更好的表达出他的意思. 例如 BigInteger(int, int ...
- JEECG 命名规范
举例讲解代码规范 例如:表名 :jeecg_sys_demo 第一部分:代码文件命名规则如下: 首先:表名采用驼峰写法转换为Java代码使用单词 jeecg_sys_demo => Jeecg ...
- IIS7.5配置Gzip压缩解决方案(转)
开启配置HTTP压缩(GZip) 在IIS7中配置Gzip压缩相比IIS6来说实在容易了许多,而且默认情况下就是启用GZip压缩的.如果没有,则可以再功能视图下找到“压缩”项,进入之后就会看到“静态内 ...
- 读书笔记,《深入理解java虚拟机》,第二章,java内存区域与内存溢出异常
第二节,运行时数据区域. 在这个章节中,作者给出了一个java虚拟机运行时数据区的框图,图的左侧是方法区和堆,这两个数据区是所有的线程所共享的.然后是虚拟机栈.本地方法栈.还有程序计数器,这三个 ...
- 使用MultipartEntity对文字、图片、视频进行综合上传
package com.home.upload; import java.io.File; import java.nio.charset.Charset; import java.util.Arra ...
- 滴滴大数据算法大赛Di-Tech2016参赛总结
https://www.jianshu.com/p/4140be00d4e3 题目描述 建模方法 特征工程 我的几次提升方法 从其他队伍那里学习到的提升方法 总结和感想 神经网络方法的一点思考 大数据 ...
- Axure-如何设置圆形组件
--打开Axure软件,在[选择部件库]窗口中找到如图中所示的矩形. --将矩形拖到设计布局中 --将鼠标悬停在矩形上就能看到右上角有一个小圆点 --点击小圆点就能选择不同的形状,如:圆形