首先给出项目的结构

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#实现发布订阅模式的更多相关文章

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

    本系列已经过半了,这一篇我们来看看redis好玩的发布订阅模式,其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果 ...

  2. 第五章 --- 关于Javascript 设计模式 之 发布-订阅模式

    先来个最简单的 发布订阅模式 document.body.addEventListener('click',function(){ alert(123); }); document.body.clic ...

  3. NetMQ(三): 发布订阅模式 Publisher-Subscriber

    ZeroMQ系列 之NetMQ 一:zeromq简介 二:NetMQ 请求响应模式 Request-Reply 三:NetMQ 发布订阅模式 Publisher-Subscriber 四:NetMQ ...

  4. C# 委托和事件 与 观察者模式(发布-订阅模式)讲解 by天命

    使用面向对象的思想 用c#控制台代码模拟猫抓老鼠 我们先来分析一下猫抓老鼠的过程 1.猫叫了 2.所有老鼠听到叫声,知道是哪只猫来了 3.老鼠们逃跑,边逃边喊:"xx猫来了,快跑啊!我是老鼠 ...

  5. 4.js模式-发布-订阅模式

    1. 发布-订阅模式 var observe = (function(){ var events = {}, listen, trigger, remmove; listen = function(k ...

  6. RabbitMQ/JAVA (发布/订阅模式)

    发布/订阅模式即生产者将消息发送给多个消费者. 下面介绍几个在发布/订阅模式中的关键概念-- 1. Exchanges (转发器) 可能原来我们都是基于一个队列发送和接收消息.现在介绍一下完整的消息传 ...

  7. Javascript中理解发布--订阅模式

    Javascript中理解发布--订阅模式 阅读目录 发布订阅模式介绍 如何实现发布--订阅模式? 发布---订阅模式的代码封装 如何取消订阅事件? 全局--发布订阅对象代码封装 理解模块间通信 回到 ...

  8. ActiveMQ发布订阅模式

    ActiveMQ的另一种模式就SUB/HUB即发布订阅模式,是SUB/hub就是一拖N的USB分线器的意思.意思就是一个来源分到N个出口.还是上节的例子,当一个订单产生后,后台N个系统需要联动,但有一 ...

  9. redis的发布订阅模式

    概要 redis的每个server实例都维护着一个保存服务器状态的redisServer结构 struct redisServer {     /* Pubsub */     // 字典,键为频道, ...

  10. 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码

    最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...

随机推荐

  1. Asp.Net Core 文件上传处理

    本文主要介绍后台接收处理 1.在使用控制器接收 : [HttpPost] : public IActionResult UploadFiles(IList<IFormFile> files ...

  2. 【JAVA与C#比较】其它

    从语言方面的知识点来说,这应该是最后一篇有关java和C#的比较了.如果要了解两者具体各知识点的异同,请查看前面的相关文章,不过后面有可能存在,不能放到前面文章所列知识点的情况,应该就会补充到这里吧. ...

  3. MySql清空所有表数据【慎用】

    CREATE PROCEDURE `up_truncate_all_table`() BEGIN ; ); DECLARE cur1 CURSOR FOR SELECT table_name from ...

  4. logistic回归算法及其matlib实现

    一般来说,回归不用在分类问题上,因为回归是连续型模型,而且受噪声影响比较大.如果非要使用回归算法,可以使用logistic回归. logistic回归本质上是线性回归,只是在特征到结果的映射中多加入了 ...

  5. 2.1 jdk-spi的实现原理

    dubbo-spi是在jdk-spi的基础上进行重写优化,下面看一下jdk-spi. 一.作用 为接口自动寻找实现类. 二.实现方式 标准制定者制定接口 不同厂商编写针对于该接口的实现类,并在jar的 ...

  6. 微信小程序wxml文件中调用自定义函数

    想在微信小程序的wxml文件里自如的像vue那样调用自定义的方法,发现并不成功,得利用WXS脚本语言. WXS脚本语言是 WeiXin Script 脚本语言的简称,是JavaScript.JSON. ...

  7. 命令行修改mysql密码和远程访问

    http://jingyan.baidu.com/article/a3a3f8118cea488da2eb8a0a.html

  8. Spring Boot集成持久化Quartz定时任务管理和界面展示

    本文是对之前的一篇文章Spring+SpringMVC+mybatis+Quartz整合代码部分做的一个修改和补充, 其中最大的变化就是后台框架变成了Spring Boot. 本工程所用到的技术或工具 ...

  9. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(十六)Structured Streaming中ForeachSink的用法

    Structured Streaming默认支持的sink类型有File sink,Foreach sink,Console sink,Memory sink. ForeachWriter实现: 以写 ...

  10. (转)Unity3D工程版本管理方案

    自:http://blog.dou.li/unity3d%E5%B7%A5%E7%A8%8B%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86%E6%96%B9%E6%A1%88 ...