C#设计模式之观察者模式实例讲解
前言
最近开始花点心思研究下设计模式,主要还是让自己写的代码可重用性高、保证代码可靠性。所谓设计模式,我找了下定义:是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
为什么要提倡“DesignPattern(设计模式)”?
根本原因是为了代码复用,增加可维护性。因此这次我们来学习下设计模式,最后会通过C#语言来实现这些设计模式作为例子,深刻理解其中的精髓。
定义
观察者模式,有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
特点
模式中具有的角色
1。抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
2。具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3。抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
4。具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
优缺点
优点:
一、通知通信
观察者模式支持广播通信。被观察者会向所有的注册过的观察者发出通知。
二、聚耦合
观察者模式在被观察者和观察者之间建立了一个抽象的耦合,被观察者并不知道任何一个具体的观察者,只是保存着抽象观察者的列表,每个具体观察者都符合一个抽象观察者的接口。
缺点:
一、时间复杂度
如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
二、内联不足
虽然观察者模式可以随时使观察者知道所观察的对象发送了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎样发生变化的。
三、容易出现循环调用
如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃,在使用观察者模式应特别注意这点。
实现思路
下面以xmfdsh发布一篇博客的例子来说明观察者模式的实现。关注了xmfdsh的朋友们,便可以通过观察者模式来实时得到博客进行了更新的信息。当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以各自独立地改变和复用的情况下。从方面的这个词中可以想到,观察者模式肯定在AOP(面向方面编程)中有所体现。因此这种需求使用观察者模式来解决就再恰当不过了。
观察者向目标“订阅”它的改变,而目标发生改变后就“通知”所有已经“订阅”了它的改变的观察者,从而执行“订阅”的内容。这种机制的好处在于降低耦合度,分工明确,目标只负责在自身状态发生改变或做出某种行为时向自身的订阅清单发出“通知”,而不是直接调用观察者的行为(方法);观察者只负责向目标“订阅”它的变化,以及定义自身在收到目标“通知”后所需要做出的具体行为(也就是订阅的内容)
//订阅号抽象类 publicabstractclassBlog { //保存订阅者列表 privateList<IObserver>observers=newList<IObserver>();
publicstringSymbol{get;set;}//描写订阅号的相关信息 publicstringInfo{get;set;}//描写此次update的信息 publicBlog(stringsymbol,stringinfo) { this.Symbol=symbol; this.Info=info; }
//对同一个订阅号,新增和删除订阅者的操作 publicvoidAddObserver(IObserverob) { observers.Add(ob); } publicvoidRemoveObserver(IObserverob) { observers.Remove(ob); }
publicvoidUpdate() { //遍历订阅者列表进行通知 foreach(IObserverobinobservers) { if(ob!=null) { ob.Receive(this); } } } }
//具体订阅号类 publicclassMyBlog:Blog { publicMyBlog(stringsymbol,stringinfo) :base(symbol,info) { } }
//订阅者接口 publicinterfaceIObserver { voidReceive(Blogtenxun); }
//具体的订阅者类 publicclassSubscriber:IObserver { publicstringName{get;set;} publicSubscriber(stringname) { this.Name=name; }
publicvoidReceive(Blogxmfdsh) { Console.WriteLine("订阅者{0}观察到了{1}{2}",Name,xmfdsh.Symbol,xmfdsh.Info); } }
//客户端测试 classProgram { staticvoidMain(string[]args) { Blogxmfdsh=newMyBlog("xmfdsh","发布了一篇新博客");
//添加订阅者 xmfdsh.AddObserver(newSubscriber("王尼玛")); xmfdsh.AddObserver(newSubscriber("唐马儒")); xmfdsh.AddObserver(newSubscriber("王蜜桃")); xmfdsh.AddObserver(newSubscriber("敖尼玛"));
//更新信息 xmfdsh.Update(); //输出结果,此时所有的订阅者都已经得到博客的新消息 Console.ReadLine(); } }