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 }
Xamarin.Android -> Xamarin.IOS -> 混合 -> Xamarin.Forms