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设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...
随机推荐
- [转]cocos2d-x
Cocos2d-x 是一个支持多平台的 2D 手机游戏引擎,使用 C++ 开发,基于OpenGL ES,基于Cocos2d-iphone,支持 WOPhone, iOS 4.1, Android 2. ...
- SiteMapPath基本用法
1.添加一个网站地图项 Web.sitemap项 2.在 Web.sitemap项的写法如下: <?xml version="1.0" encoding="utf- ...
- 华为推送 简介 集成 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 如何清空IFRAME中的HTML
window.frames["ifra"].document.write(""); window.frames["ifra"].docume ...
- 【Spark】SparkStreaming-foreachrdd foreachpartition
SparkStreaming-foreachrdd foreachpartition foreachrdd foreachpartition_百度搜索 SparkStreaming之foreachRD ...
- Spearman(斯皮尔曼) 等级相关
Spearman相关系数又称秩相关系数,是利用两变量的秩次大小作线性相关分析,对原始变量的分布不作要求,属于非参数统计方法,适用范围要广些.对于服从Pearson相关系数的数据亦可计算Spearman ...
- express next function
nodejs 里面的next()这个函数调用的作用是什么呢? var express = require('express'); var app = express(); var myLogger = ...
- Everything常见问题及搜索技巧,附Demo
1 Everything 1.1 "Everything"是什么? "Everything"是一个运行于Windows系统,基于文件.文件夹名称的快速搜索引擎. ...
- 不可不知的Python模块: collections
原文:http://www.zlovezl.cn/articles/collections-in-python/ Python作为一个“内置电池”的编程语言,标准库里面拥有非常多好用的模块.比如今天想 ...
- [Functional Programming] Daggy
const daggy = require('daggy'); const {tagged, taggedSum} = daggy; const Coord = daggy.tagged('Coord ...