VincentPass

导航

 

1.初识观察者模式

  生活中大家一定遇到过这样的情况:某一件事情的状态改变,会相应的引起其他相关的变化。身在武林就说说武林的事吧,就说最近热播的电视剧《天涯明月刀》,看过这么一集,剧情大概是:“了因师太”和“国介方丈”假传向盟主的口令邀请武林各大门派到侠客山庄开“铲雪大会”,目的是铲除他们眼中的武林败类“傅红雪”。其实这就是一个观察者模式的典型例子啦。

  被观察者是:“了因师太”和“国介方丈”。(即:他们状态的改变的会影响其他的事情的变化)

  观察者是:武当派等等其他武林派别。(即:受被观察者状态改变的影响作出相应的变化)

GoF对观察者模式定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

  实际上,观察者模式又被成为发布/订阅模式,在这种模式中,一个目标物件(被观察者)管理所有相依于它的相关物件(观察者),并且在目标物件的状态改变时主动发出通知。这通常透过使用各相关物件所提供的方法来实现,观察者模式模式通常被用来作事件处理系统。

2.观察者模式实现

  我们不妨在举一个大家比较熟悉的例子:用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。

  现在大家应该对观察者模式理解的差不多了,那么观察者模式怎么实现呢? 观察者模式有很多实现方式,从根本上说,该模式必须包含两个角色:观察者被观察对象。在刚才的例子中,业务数据是被观察对象,用户界面是观察者。观察者和被观察者之间存在“观察”的逻辑关联,当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应。如果在用户界面、业务数据之间使用这样的观察过程,可以确保界面和数据之间划清界限,假定应用程序的需求发生变化,需要修改界面的表现,只需要重新构建一个用户界面,业务数据不需要发生变化。这样一说,似乎我们要实现观察者模式就要最少有:被观察者类观察者类。

  在实现观察者模式的多种形式中,比较直观的一种是使用一种“注册—通知—撤销注册”的形式。具体实现过程的关键步骤如下:

  注册:在被观察者对象中,放置一个容器来保存相关的观察者对象。

  通知:一旦被观察者对象中的状态发生改变,则通知容器中所有观察者对象做出相应的变化。

  撤销注册:将被观察者对象容器中某个要撤销的观察者对象删除。

  注:实际上这种实现方式不仅仅要包含被观察者类观察者类。因为观察者对象将自己注册到被观察者的容器中时,被观察者不应该过问观察者的具体类型,而是应该使用观察者的接口。这样的优点是:假定程序中还有别的观察者,那么只要这个观察者也是相同的接口实现即可。一个被观察者可以对应多个观察者,当被观察者发生变化的时候,他可以将消息一通知给所有的观察者。基于接口,而不是具体的实现,这一点为程序提供了更大的灵活性。也就是说还要包含所以观察者类的基类。这样便于扩展。还是看看观察者模式的类图吧:

           

  其中Subject是抽象被观察者,Observer是抽象的观察者类,Attach是向被观察者容器中加入观察者对象,Detach是从被观察者容器中删除相关的观察者对象,NOtify是具体的通知操作,通知所以容器中的观察者做出相应的操作(观察者中的Update)。这样的设计更符合依赖倒置原则,并且减小了系统的耦合性。现在写代码已经非常简单了吧。但是这样其实还是有问题的。

3.观察者模式 VS 委托

  我们再来对上面的观察者模式进行分析,可以发现,这种实现是有不足之处的:

  (1)并没有完全的解除系统的耦合。

  (2)所有观察者要完成的操作未必是一致的,即:未必都是Update操作,不同的观察者所要完成的事情未必一致。

  对于以上存在的两个问题,通过委托可以很少的解决。那么什么事委托呢?委托实际上和C++中的函数指针比较相似,实际上委托是一种引用方法的类型,一旦委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值,委托可以看成是函数的抽象,是函数的类,委托的实例将代表具体的函数,而且比较重要的是,委托可以搭载多个方法,所有方法别依次唤起。

  通过对于委托的介绍,我们想是不是可以通过委托来代替原来的被观察者类中的容器呢?这样就减小了耦合,因为被观察者中不需要保存观察者对象了。实际上是可以的,只需要在被观察者类声明一个委托,然后再客户端处,动态的为被观察者对象中的委托赋值,赋的值就是当被观察者状态发生改变时,观察者对象所要进行的操作,这样一来,即使观察者对象要完成的操作不一样,也可以很好的解决啦。我只能说,委托真是好啊~~~

4.使用观察者模式的场合和好处

  以下情况使可以考虑使用观察者模式:

  (1)当一个抽象模型有两个方面,其中一个方面依赖另一个方面,这时使用观察者模式可以将这两个者封装在独立的对象中使他们各自独立的改变和复用。

  (2)当一个对象的改变要影响到其他对象,而且不知道有多少的对象需要改变。

  (3)当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之, 你不希望这些对象是紧密耦合的。

  那么使用观察者模式有什么好处呢?主要是降低了系统中各个对象之间的耦合性,使得系统易于扩展。总的来说:

  (1)使用面向对象的抽象,观察者模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达到松耦合。

  (2)目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。观察者自己决定是否需要订阅通知。目标对象对此一无所知。

  (3)在C#中的Event。委托充当了抽象的Observer接口,而提供事件的对象充当了目标对象,委托是比抽象Observer接口更为松耦合的设计。

学习中的一点总结,欢迎拍砖哦^^
posted on 2012-07-15 10:36  VincentPass  阅读(2355)  评论(5编辑  收藏  举报