代码改变世界

C#实现发布订阅模式

2014-02-20 10:44  y-z-f  阅读(10398)  评论(1编辑  收藏  举报

首先给出项目的结构

 

IPublish.cs的源码:

 1 namespace NsWebChat.PublishSubscribe
 2 {
 3     /// <summary>
 4     /// 发布事件基础接口
 5     /// </summary>
 6     public interface IPublish
 7     {
 8         string PublishTag { get; set; }
 9         object PublishData { get; set; }
10     }
11 }

 

IPubSubCenter.cs的源码:

 1 namespace NsWebChat.PublishSubscribe
 2 {
 3     /// <summary>
 4     /// 订阅发布中心基础接口
 5     /// </summary>
 6     public interface IPubSubCenter
 7     {
 8         /// <summary>
 9         /// 订阅事件
10         /// </summary>
11         bool AddSubscribe(string tag, Func<ISubscribe, object, object> method, object data, string name);
12         bool AddSubscribe(string tag, Func<ISubscribe, object, object> method, string name);
13         bool AddSubscribe(Subscribe subscribe);
14         /// <summary>
15         /// 获得指定事件的订阅列表
16         /// </summary>
17         SubscribeList GetSubscribeList(string tag);
18         /// <summary>
19         /// 获得订阅
20         /// </summary>
21         Subscribe GetSubscribe(string tag, string name);
22         /// <summary>
23         /// 删除订阅
24         /// </summary>
25         void RemoveSubscribe(string tag, string name);
26 
27         /// <summary>
28         /// 发布事件
29         /// </summary>
30         IEnumerable<Object> Publish(string tag, object data);
31         IEnumerable<Object> Publish(string tag);
32         IEnumerable<Object> Publish(Publish publish);
33     }
34 }

 

ISubscribe.cs的源码:

 1 namespace NsWebChat.PublishSubscribe
 2 {
 3     /// <summary>
 4     /// 订阅事件基础接口
 5     /// </summary>
 6     public interface ISubscribe
 7     {
 8         /// <summary>
 9         /// 订阅的事件
10         /// </summary>
11         string SubscribeTag { get; set; }
12         /// <summary>
13         /// 订阅的名称
14         /// </summary>
15         string SubscribeName { get; set; }
16         /// <summary>
17         /// 响应发布时传递的参数
18         /// </summary>
19         object Data { get; set; }
20         /// <summary>
21         /// 响应发布的方法
22         /// </summary>
23         Func<ISubscribe, object, object> SubscribeMethod { get; set; }
24         /// <summary>
25         /// 调用订阅方法
26         /// </summary>
27         object Invoke(object val);
28     }
29 }

 

Publish.cs的源码:

 1 namespace NsWebChat.PublishSubscribe
 2 {
 3     /// <summary>
 4     /// 发布事件基类
 5     /// </summary>
 6     public class Publish : IPublish
 7     {
 8         private string _publishTag;
 9         private object _publishData;
10 
11         public Publish()
12         {
13         }
14 
15         public Publish(string tag)
16             : this(tag, new object())
17         {
18 
19         }
20 
21         public Publish(string tag, object val)
22         {
23             _publishTag = tag;
24             _publishData = val;
25         }
26 
27         public string PublishTag
28         {
29             get
30             {
31                 return _publishTag;
32             }
33             set
34             {
35                 _publishTag = value;
36             }
37         }
38 
39         public object PublishData
40         {
41             get
42             {
43                 return _publishData;
44             }
45             set
46             {
47                 _publishData = value;
48             }
49         }
50     }
51 }

 

PubSubCenter.cs的源码:

  1 namespace NsWebChat.PublishSubscribe
  2 {
  3     /// <summary>
  4     /// 订阅发布中心基类
  5     /// </summary>
  6     public class PubSubCenter : IPubSubCenter
  7 
  8     {
  9         private Dictionary<string, SubscribeList> _pubsubList = new Dictionary<string, SubscribeList>();
 10 
 11         public bool AddSubscribe(string tag, Func<ISubscribe, object, object> method, object data ,string name)
 12         {
 13             Subscribe subscribe = new Subscribe();
 14             subscribe.Data = data;
 15             subscribe.SubscribeMethod = method;
 16             subscribe.SubscribeTag = tag;
 17             subscribe.SubscribeName = name;
 18             return AddSubscribe(subscribe);
 19         }
 20 
 21         public bool AddSubscribe(string tag, Func<ISubscribe, object, object> method, string name)
 22         {
 23             return AddSubscribe(tag, method, new object(),name);
 24         }
 25 
 26         public bool AddSubscribe(Subscribe subscribe)
 27         {
 28             if (subscribe == null)
 29             {
 30                 return false;
 31             }
 32             else
 33             {
 34                 if (String.IsNullOrEmpty(subscribe.SubscribeName))
 35                 {
 36                     return false;
 37                 }
 38                 Subscribe subscribet = GetSubscribe(subscribe.SubscribeTag, subscribe.SubscribeName);
 39                 if (subscribet != null)
 40                 {
 41                     return false;
 42                 }
 43                 else
 44                 {
 45                     if (_pubsubList.ContainsKey(subscribe.SubscribeTag))
 46                     {
 47                         _pubsubList[subscribe.SubscribeTag].Add(subscribe);
 48                     }
 49                     else
 50                     {
 51                         SubscribeList list = new SubscribeList();
 52                         list.Add(subscribe);
 53                         _pubsubList.Add(subscribe.SubscribeTag, list);
 54                     }
 55                     return true;
 56                 }
 57             }
 58         }
 59 
 60         public SubscribeList GetSubscribeList(string tag)
 61         {
 62             if (_pubsubList.ContainsKey(tag))
 63             {
 64                 return _pubsubList[tag];
 65             }
 66             else
 67             {
 68                 return new SubscribeList();
 69             }
 70         }
 71 
 72         public Subscribe GetSubscribe(string tag, string name)
 73         {
 74             if (_pubsubList.ContainsKey(tag))
 75             {
 76                 foreach (Subscribe item in _pubsubList[tag])
 77                 {
 78                     if (item.SubscribeName == name)
 79                     {
 80                         return item;
 81                     }
 82                 }
 83                 return null;
 84             }
 85             else
 86             {
 87                 return null;
 88             }
 89         }
 90 
 91         public void RemoveSubscribe(string tag, string name)
 92         {
 93             Subscribe subscribe = GetSubscribe(tag, name);
 94             _pubsubList[tag].Remove(subscribe);
 95         }
 96 
 97         public IEnumerable<object> Publish(string tag, object data)
 98         {
 99             if (_pubsubList.ContainsKey(tag))
100             {
101                 foreach (Subscribe item in _pubsubList[tag])
102                 {
103                     yield return item.Invoke(data);
104                 }
105             }
106             else
107             {
108                 yield break;
109             }
110         }
111 
112         public IEnumerable<object> Publish(string tag)
113         {
114             return Publish(tag, new object());
115         }
116 
117         public IEnumerable<object> Publish(Publish publish)
118         {
119             return Publish(publish.PublishTag, publish.PublishData);
120         }
121     }
122 }

 

Subscribe.cs源码:

 

 1 namespace NsWebChat.PublishSubscribe
 2 {
 3     /// <summary>
 4     /// 订阅事件基类
 5     /// </summary>
 6     public class Subscribe : ISubscribe
 7     {
 8         private object _data;
 9         private Func<ISubscribe, object, object> _subscribeMethod;
10         private string _subscribeTag;
11         private string _subscribeName;
12 
13         public Subscribe()
14         {
15         }
16 
17         public Subscribe(string tag, Func<ISubscribe, object, object> method)
18             : this(tag, method, "")
19         {
20 
21         }
22 
23         public Subscribe(string tag, Func<ISubscribe, object, object> method, object data)
24             : this(tag, method, data, "")
25         {
26 
27         }
28 
29         public Subscribe(string tag, Func<ISubscribe, object, object> method,string name)
30             : this(tag, method, new object(), name)
31         {
32 
33         }
34 
35         public Subscribe(string tag, Func<ISubscribe, object, object> method, object data,string name)
36         {
37             _data = data;
38             _subscribeTag = tag;
39             _subscribeMethod = method;
40             _subscribeName = name;
41         }
42 
43         public object Data
44         {
45             get
46             {
47                 return _data;
48             }
49             set
50             {
51                 _data = value;
52             }
53         }
54 
55         public Func<ISubscribe, object, object> SubscribeMethod
56         {
57             get
58             {
59                 return _subscribeMethod;
60             }
61             set
62             {
63                 _subscribeMethod = value;
64             }
65         }
66 
67         public object Invoke(object val)
68         {
69             return SubscribeMethod(this, val);
70         }
71 
72         public string SubscribeTag
73         {
74             get
75             {
76                 return _subscribeTag;
77             }
78             set
79             {
80                 _subscribeTag = value;
81             }
82         }
83 
84         public string SubscribeName
85         {
86             get
87             {
88                 return _subscribeName;
89             }
90             set
91             {
92                 _subscribeName = value;
93             }
94         }
95     }
96 }

 

SubscribeList.cs的源码:

 1 namespace NsWebChat.PublishSubscribe
 2 {
 3     /// <summary>
 4     /// 订阅列表
 5     /// </summary>
 6     public class SubscribeList : IList<Subscribe>
 7     {
 8         private List<Subscribe> subscribes = new List<Subscribe>();
 9 
10         public int IndexOf(Subscribe item)
11         {
12             return subscribes.IndexOf(item);
13         }
14 
15         public void Insert(int index, Subscribe item)
16         {
17             subscribes.Insert(index, item);
18         }
19 
20         public void RemoveAt(int index)
21         {
22             subscribes.RemoveAt(index);
23         }
24 
25         public Subscribe this[int index]
26         {
27             get
28             {
29                 return subscribes[index];
30             }
31             set
32             {
33                 subscribes[index] = value;
34             }
35         }
36 
37         public void Add(Subscribe item)
38         {
39             subscribes.Add(item);
40         }
41 
42         public void Clear()
43         {
44             subscribes.Clear();
45         }
46 
47         public bool Contains(Subscribe item)
48         {
49             return subscribes.Contains(item);
50         }
51 
52         public void CopyTo(Subscribe[] array, int arrayIndex)
53         {
54             subscribes.CopyTo(array, arrayIndex);
55         }
56 
57         public int Count
58         {
59             get
60             {
61                 return subscribes.Count;
62             }
63         }
64 
65         public bool IsReadOnly
66         {
67             get { return false; }
68         }
69 
70         public bool Remove(Subscribe item)
71         {
72             return subscribes.Remove(item);
73         }
74 
75         public IEnumerator<Subscribe> GetEnumerator()
76         {
77             return subscribes.GetEnumerator();
78         }
79 
80         System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
81         {
82             return subscribes.GetEnumerator();
83         }
84     }
85 }

 

下面是单元测试的源码(PubSubCenterTest.cs):

  1 namespace WebChatUnitTest
  2 {
  3     [TestClass]
  4     public class PubSubCenterTest
  5     {
  6         public object Test1(ISubscribe subscribe, object data)
  7         {
  8             Assert.IsTrue(subscribe.Data == data);
  9             return data;
 10         }
 11 
 12         public object Test2(ISubscribe s, object d)
 13         {
 14             return d;
 15         }
 16 
 17         public object Test3(ISubscribe s, object d)
 18         {
 19             return d;
 20         }
 21 
 22         public object Test4(ISubscribe s, object d)
 23         {
 24             return d;
 25         }
 26 
 27         public object Test5(ISubscribe s, object d)
 28         {
 29             return s.SubscribeName;
 30         }
 31 
 32         //测试删除订阅
 33         [TestMethod]
 34         public void TestRemoveSubscribe()
 35         {
 36             PubSubCenter pbc = new PubSubCenter();
 37             pbc.AddSubscribe("t1", Test5, "1");
 38             pbc.AddSubscribe("t1", Test5, "2");
 39             pbc.RemoveSubscribe("t1", "2");
 40             List<string> al = new List<string>();
 41             foreach (string item in pbc.Publish("t1"))
 42             {
 43                 al.Add(item);
 44             }
 45             Assert.IsTrue(al.Count == 1);
 46             Assert.IsTrue(al[0] == "1");
 47             pbc.AddSubscribe("t1", Test5, "2");
 48             pbc.RemoveSubscribe("t1", "1");
 49             al.Clear();
 50             foreach (string item in pbc.Publish("t1"))
 51             {
 52                 al.Add(item);
 53             }
 54             Assert.IsTrue(al.Count == 1);
 55             Assert.IsTrue(al[0] == "2");
 56         }
 57 
 58         //测试重载版本的订阅发布
 59         [TestMethod]
 60         public void TestMoreSubscribeAndPublish()
 61         {
 62             PubSubCenter pbc = new PubSubCenter();
 63             Subscribe subscribe = new Subscribe("t1", Test2, "2", "1");
 64             Subscribe subscribe2 = new Subscribe("t1", Test2, "2");
 65             Subscribe subscribe3 = new Subscribe();
 66             subscribe3.SubscribeMethod = Test2;
 67             subscribe3.SubscribeName = "3";
 68             subscribe3.SubscribeTag = "t1";
 69             pbc.AddSubscribe(subscribe);
 70             pbc.AddSubscribe(subscribe2);
 71             pbc.AddSubscribe(subscribe3);
 72             pbc.AddSubscribe("t1", Test2, "4");
 73             pbc.AddSubscribe("t1", Test2, "2", "5");
 74             List<object> al = new List<object>();
 75             foreach (object item in pbc.Publish("t1"))
 76             {
 77                 al.Add(item);
 78             }
 79             Assert.IsTrue(al.Count == 5);
 80             Assert.IsNotNull(al[0]);
 81             Assert.IsNotNull(al[1]);
 82             Assert.IsNotNull(al[2]);
 83             Assert.IsNotNull(al[3]);
 84             Assert.IsNotNull(al[4]);
 85             al.Clear();
 86             foreach (object item in pbc.Publish("t1","2"))
 87             {
 88                 al.Add(item);
 89             }
 90             Assert.IsTrue(al.Count == 5);
 91             Assert.IsNotNull(al[0]);
 92             Assert.IsNotNull(al[1]);
 93             Assert.IsNotNull(al[2]);
 94             Assert.IsNotNull(al[3]);
 95             Assert.IsNotNull(al[4]);
 96 
 97             Publish pub = new Publish("t1");
 98             al.Clear();
 99             foreach (object item in pbc.Publish(pub))
100             {
101                 al.Add(item);
102             }
103             Assert.IsTrue(al.Count == 5);
104             Assert.IsNotNull(al[0]);
105             Assert.IsNotNull(al[1]);
106             Assert.IsNotNull(al[2]);
107             Assert.IsNotNull(al[3]);
108             Assert.IsNotNull(al[4]);
109 
110             pub = new Publish("t1", "2");
111             al.Clear();
112             foreach (object item in pbc.Publish(pub))
113             {
114                 al.Add(item);
115             }
116             Assert.IsTrue(al.Count == 5);
117             Assert.IsNotNull(al[0]);
118             Assert.IsNotNull(al[1]);
119             Assert.IsNotNull(al[2]);
120             Assert.IsNotNull(al[3]);
121             Assert.IsNotNull(al[4]);
122 
123             pub = new Publish();
124             pub.PublishData = "2";
125             pub.PublishTag = "t1";
126             al.Clear();
127             foreach (object item in pbc.Publish(pub))
128             {
129                 al.Add(item);
130             }
131             Assert.IsTrue(al.Count == 5);
132             Assert.IsNotNull(al[0]);
133             Assert.IsNotNull(al[1]);
134             Assert.IsNotNull(al[2]);
135             Assert.IsNotNull(al[3]);
136             Assert.IsNotNull(al[4]);
137         }
138 
139         //测试重名订阅事件
140         [TestMethod]
141         public void TestSameNameSubscribe()
142         {
143             PubSubCenter pbc = new PubSubCenter();
144             pbc.AddSubscribe("t1", Test2, "2");
145             pbc.AddSubscribe("t1", Test2, "2");
146             pbc.AddSubscribe("t1", Test2, "3");
147             List<string> al = new List<string>();
148             foreach (string item in pbc.Publish("t1", "123"))
149             {
150                 al.Add(item);
151             }
152             Assert.IsTrue(al.Count == 2);
153             Assert.IsTrue(al[0] == "123");
154             Assert.IsTrue(al[1] == "123");
155         }
156 
157         //测试多方法订阅单事件
158         [TestMethod]
159         public void TestMoreSubscribeToOnePublish()
160         {
161             PubSubCenter pbc = new PubSubCenter();
162             pbc.AddSubscribe("t1", Test2, "1");
163             pbc.AddSubscribe("t1", Test3, "2");
164             pbc.AddSubscribe("t1", Test4, "3");
165             List<string> al = new List<string>();
166             foreach (string item in pbc.Publish("t1", "2"))
167             {
168                 al.Add(item);
169             }
170             Assert.IsTrue(al.Count == 3);
171             Assert.IsTrue(al[0] == "2");
172             Assert.IsTrue(al[1] == "2");
173             Assert.IsTrue(al[2] == "2");
174         }
175 
176         //测试单方法订阅多事件
177         [TestMethod]
178         public void TestOneSubscribeToMorePublish()
179         {
180             PubSubCenter pbc = new PubSubCenter();
181             pbc.AddSubscribe("t1", Test1, "2", "t1");
182             pbc.AddSubscribe("t2", Test1, "3", "t2");
183             pbc.AddSubscribe("t3", Test1, "4", "t3");
184             pbc.AddSubscribe("t4", Test1, "5", "t4");
185             IList<String> al = new List<String>();
186             foreach(String item in pbc.Publish("t1","2"))
187             {
188                 al.Add(item);
189             }
190             Assert.IsTrue(al.Count == 1);
191             Assert.IsTrue(al[0] == "2");
192             al.Clear();
193             foreach (String item in pbc.Publish("t2", "3"))
194             {
195                 al.Add(item);
196             }
197             Assert.IsTrue(al.Count == 1);
198             Assert.IsTrue(al[0] == "3");
199             al.Clear();
200             foreach (String item in pbc.Publish("t3", "4"))
201             {
202                 al.Add(item);
203             }
204             Assert.IsTrue(al.Count == 1);
205             Assert.IsTrue(al[0] == "4");
206             al.Clear();
207             foreach (String item in pbc.Publish("t4", "5"))
208             {
209                 al.Add(item);
210             }
211             Assert.IsTrue(al.Count == 1);
212             Assert.IsTrue(al[0] == "5");
213         }
214     }
215 }