一直找不到一种能够让很多对象都能在几乎同时接收到通知的方法。介绍下目前在用的,希望能够抛砖引玉。
首先随便贴一下观察者模式的两接口,观察者模式自行搜索设计模式。
public interface ISubject<T> where T : class { /// <summary> /// /// </summary> /// <param name="action">为true表示注册,false表示注销</param> int RegistNotify(bool action, IObserver<T> ob); } public interface IObserver<T> where T : class { void MessageNotify(T message); }
ISubject接口对象作为通知发起者,IObserver接口对象即为要接收通知的对象了。
写个类实现IOserver接口。
class Observer : ObserverPattern.IObserver<Msg> { public Observer(ISubject<Msg> sub) { sub.RegistNotify(true, this); // 注册 } void ObserverPattern.IObserver<Msg>.MessageNotify(Msg message) { DateTime cur = DateTime.Now; // 当接收到通知时记录下当前时间 Debug.WriteLine("s : " + cur.Second + " ms : " + cur.Millisecond); } }
建了个窗体实现ISubject接口。
public partial class Form1 : Form, ISubject<Msg> { List<ObserverPattern.IObserver<Msg>> m_observers; public Form1() { InitializeComponent(); this.Load += Form1_Load; } private void Form1_Load(object sender, EventArgs e) { m_observers = new List<ObserverPattern.IObserver<Msg>>(); Observer ob = new Observer(this); Observer ob2 = new Observer(this); Observer ob3 = new Observer(this); Observer ob4 = new Observer(this); Observer ob5 = new Observer(this); Observer ob6 = new Observer(this); Observer ob7 = new Observer(this); Observer ob8 = new Observer(this); Observer ob9 = new Observer(this); Observer ob10 = new Observer(this); Observer ob11 = new Observer(this); Observer ob12 = new Observer(this); Observer ob13 = new Observer(this); Observer ob14 = new Observer(this); Observer ob15 = new Observer(this); Observer ob16 = new Observer(this); Observer ob17 = new Observer(this); } int ISubject<Msg>.RegistNotify(bool action, ObserverPattern.IObserver<Msg> ob) { if (action) { m_observers.Add(ob); return 0; } m_observers.Remove(ob); return 0; } private void button1_Click(object sender, EventArgs e) { Msg message = new Msg() { Ident = 1, Data = null }; foreach (var ob in m_observers) { Task.Factory.StartNew(() => ob.MessageNotify(message)); } } private void button2_Click(object sender, EventArgs e) { Msg message = new Msg() { Ident = 2, Data = null }; foreach (var ob in m_observers) { new Thread(() => { ob.MessageNotify(message); }) { IsBackground = true, }.Start(); } } } }
加载了17个观察者。
分别用任务方式和线程方式发起通知。此例中观察者少所以差别不太明显,但如果观察者多的话频繁创建线程肯定消耗资源。推荐任务方式,但还是没达到我想要的效果,比如在5ms内能通知到100个观察者?[突然想到网络发包这么快,有时间通过这个点思考下。]
以下是输出:
任务方式,耗时208ms--------------------------------------------
s : 31 ms : 350
s : 31 ms : 350
s : 31 ms : 372
s : 31 ms : 418
s : 31 ms : 420
s : 31 ms : 422
s : 31 ms : 423
s : 31 ms : 396
s : 31 ms : 425
s : 31 ms : 446
s : 31 ms : 469
s : 31 ms : 490
s : 31 ms : 513
s : 31 ms : 536
s : 31 ms : 558
s : 31 ms : 349
s : 31 ms : 396
线程方式,耗时225ms--------------------------------------------
s : 46 ms : 523
线程 0x10854 已退出,返回值为 0 (0x0)。
s : 46 ms : 525
线程 0x10230 已退出,返回值为 0 (0x0)。
s : 46 ms : 548
线程 0xcc84 已退出,返回值为 0 (0x0)。
s : 46 ms : 570
线程 0xea48 已退出,返回值为 0 (0x0)。
s : 46 ms : 593
线程 0x10524 已退出,返回值为 0 (0x0)。
s : 46 ms : 618
线程 0x3308 已退出,返回值为 0 (0x0)。
s : 46 ms : 643
线程 0x10d58 已退出,返回值为 0 (0x0)。
s : 46 ms : 646
线程 0xe808 已退出,返回值为 0 (0x0)。
s : 46 ms : 648
线程 0xe684 已退出,返回值为 0 (0x0)。
s : 46 ms : 651
线程 0x10c5c 已退出,返回值为 0 (0x0)。
s : 46 ms : 674
线程 0xecc0 已退出,返回值为 0 (0x0)。
s : 46 ms : 675
线程 0x10508 已退出,返回值为 0 (0x0)。
s : 46 ms : 698
s : 46 ms : 735
s : 46 ms : 743
线程 0xe5d0 已退出,返回值为 0 (0x0)。
线程 0x10dd4 已退出,返回值为 0 (0x0)。
线程 0x10a80 已退出,返回值为 0 (0x0)。
s : 46 ms : 747
线程 0x10e30 已退出,返回值为 0 (0x0)。
s : 46 ms : 748
线程 0xf754 已退出,返回值为 0 (0x0)。
线程 0xe90c 已退出,返回值为 0 (0x0)。
线程 0x10bd4 已退出,返回值为 0 (0x0)。
线程 0x10ed4 已退出,返回值为 0 (0x0)。
线程 0xc958 已退出,返回值为 0 (0x0)。
线程 0xe5fc 已退出,返回值为 0 (0x0)。
线程 0x109fc 已退出,返回值为 0 (0x0)。
本来不想写太多,可还是花了点时间。最后填下标题的坑哈,毕竟全文一个委托都没提:
把IObserver接口中的MessageNotify(T message)用一个Action<T>替换就行了。具体情况具体分析,这里特意提观察者模式是想说明真的懒不想写随笔,还有重要的一点就是设计模式很值得学习。