首先给出项目的结构

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. 对Java通配符的个人理解(以集合为例)

    对Java通配符的个人理解(以集合为例) 前言:最近在学习Java,当学到了泛型的通配符时,不是很理解PECS(Producer Extends Consumer Super)原则,以及<? e ...

  2. [转]php cli命令 自定义参数传递

    FROM :http://www.cnblogs.com/zcy_soft/archive/2011/12/10/2283437.html 所有的PHP发行版,不论是编译自源代码的版本还是预创建的版本 ...

  3. codevs 2190 有理逼近

    2190 有理逼近  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 黄金 Gold   题目描述 Description 对于一个素数P,我们可以用一系列有理分数(分子.分母都是 ...

  4. 【转】从QDataStream向QByteArray中写入数据时的注意点(QT)

    最近发现从QDataStream向QByteArray中写入数据常常是写不进去的,通过查看QT的源码: QDataStream &operator>>(QDataStream &a ...

  5. mysql-5.7.18解压版启动mysql服务

    1.下载mysql社区版 2.解压到D:\Program Files 3.在D:\Program Files\mysql-5.7.18-winx64\bin下,新建文件my.ini,内容如下: [cl ...

  6. 从数据库中取 datetime类型,界面展示 yyyy-MM-dd

    //处理提问时间,去掉时分秒 if(array!=null && array.size()>0){ for(int i=0;i<array.size();i++){ JSO ...

  7. Cognos11第三方权限认证之OpenDJ

      一.安装OpenDJ 安装java环境,配置OPENDJ_JAVA_HOME环境变量指向java,然后傻瓜安装,出现下面的界面则说明安装成功 注意安装的过程中会指定管理用户cn的密码,默认的cn是 ...

  8. Struts2之server端验证

    声明:在我的教程中有些东西,没有提及到.不是我不知道,而是在我个人来看对你们不是太重要的知识点.你们在看课本时有了解到即可.我不会面面俱到的都给你们提及.我写博文的目的是把我这一年的开发经验通过学习s ...

  9. curl_setopt — 设置 cURL 传输选项

    curl_setopt (PHP 4 >= 4.0.2, PHP 5, PHP 7) curl_setopt — 设置 cURL 传输选项 bool curl_setopt ( resource ...

  10. 【python】安装py3-bencode 及小例程

    C:\Users\horn1\Desktop\python\35-bencode-ng>pip install py3-bencodeCollecting py3-bencode Downloa ...