技术开发 频道

Observer模式深度探索

  除了这些接口外,框架还经常为主体提供一个通用基类,减少了支持Observer模式所需的工作。基类实现IObservable接口,以提供支持观察者实例存储和通知所需的基础结构。下面的C#代码示例简要介绍一个名为ObservableImpl的基类。尽管可能任何容器都可以完成这一任务,但该类在Register和UnRegister方法中将观察者存储委托给哈希表实例(为了方便起见,我们在示例中使用哈希表作为容器,它只使用一个方法调用来撤消注册特定的观察者实例)。还要注意添加了NotifyObservers方法。此方法用于通知哈希表中存储的观察者。在调用此方法时,将枚举该容器,并对观察者实例调用Notify方法。

  我们的示例应用程序使用以下方法来利用此基类基础结构:修改Stock类以扩展ObservableImpl类,而不是提供其自己的特定IObservable接口实现。因为ObservableImpl类实现了IObservable接口,所以不需要对StockDisplay类进行任何更改。实际上,这种方法简化了Observer模式的实现,在保持类之间松散耦合关系的同时,使多个主体重复使用相同的功能。
 
  下面的.net观察者示例重点说明了IObservable和IObserver接口以及ObservableBase类在我们的股票应用程序中的使用情况。除了Stock和StockDisplay类外,此示例使用MainClass将观察者和主体实例关联起来,并修改Stock实例的AskPrice属性。此属性负责调用基类的NotifyObservers方法,而该方法又向该实例通知相关的状态变化。

  观察者示例

//represents a stock in an application public class Stock:ObservableImpl { //instance variable for ask price object _askPrice; //property for ask price public object AskPrice { set { _askPrice=value; base.NotifyObservers(_askPrice); }//set }//AskPrice property }//Stock //represents the user interface in the application public class StockDisplay:IObserver { public void Notify(object anObject){ Console.WriteLine("The new ask price is:" + anObject); }//Notify }//StockDisplay public class MainClass{ public static void Main() { //create new display and stock instances StockDisplay stockDisplay=new StockDisplay(); Stock stock=new Stock(); //reGISter the grid stock.Register(stockDisplay); //loop 100 times and modify the ask price for(int looper=0;looper < 100;looper++) { stock.AskPrice=looper; } //unregister the display stock.UnRegister(stockDisplay); }//Main }//MainClass
  .net框架中的Observer模式
 
  基于我们对Observer模式的了解,让我们将注意力转向此模式在.NET框架中的使用情况。您们当中非常熟悉FCL中所公开类型的人将会注意到,框架中没有IObserver、IObservable或ObservableImpl类型。虽然您的确可以在.NET应用程序中使用这些构造,但引入委托和事件可提供新的、功能强大的方法来实现Observer模式,而不必开发专用于支持该模式的特定类型。事实上,因为委托和事件是CLR的一级成员,所以将此模式的基本构造添加到.NET框架的核心中。因此,FCL在其结构中广泛使用Observer模式。
 
  介绍委托和事件内部工作方式的文章非常多,我们在此不再赘述。我们只需说明委托是面向对象(和类型安全)版的函数指针就够了。委托实例保存对实例或类方法的引用,允许匿名调用绑定方法。事件是在类上声明的特殊构造,可在运行时发布被关注对象的状态变化。事件表示我们前面用于实现Observer模式的注册、撤消注册和通知方法的形式抽象(CLR和多种不同的编译器对它提供支持)。委托是在运行时注册到特定事件中的。在引发事件时,将调用所有注册的委托,以使它们能够收到事件的通知。
 
  按照Observer模式定义的术语,声明事件的类就是主体。与我们以前使用的IObservable接口和ObservableImpl类不同,主体类不需要实现给定接口或扩展基类。主体只需要公开一个事件,而不需要执行任何其他操作。观察者创建的工作略多一些,但灵活性却提高得非常多(我们将在后面讨论)。观察者并不实现IObserver接口和将其自身注册到主体中,而是必须创建特定的委托实例,并将此委托注册到主体事件中。观察者必须使用具有事件声明所指定类型的委托实例,否则,注册就会失败。在创建此委托实例的过程中,观察者将传递该主体向委托通知的方法(实例或静态)名称。在将委托绑定到方法后,可以将其注册到主体的事件中。类似地,也可以从事件中撤消注册此委托。主体通过调用事件向观察者提供通知。
 
  如果您不熟悉委托和事件,则实现Observer模式似乎需要做很多工作,尤其是与我们以前使用的IObserver和IObservable接口相比。但是,它比听起来要简单一些,并且实现起来要容易得多。下面的C#和Visual Basic .NET代码示例重点说明了在我们的示例应用程序中支持委托和事件所需的类修改。注意,没有Stock或StockDisplay类用于支持该模式的任何基类或接口。
 
  在熟悉了委托和事件后,您就会清楚地看到它们的巨大潜力。与IObserver和IObservable接口以及ObservableImpl类不同,使用委托和事件可大大减少实现此模式所需的工作量。CLR和编译器为观察者容器管理提供了基础,并且为注册、撤消注册和通知观察者提供了一个通用调用约定。也许,委托的最大优点是其能够引用任何方法的固有特性(条件是它符合相同的签名)。这允许任何类用作观察者,而与它所实现的接口或它专用的类无关。虽然使用IObserver和IObservable接口可减少观察者和主体类之间的耦合关系,但使用委托可完全消除这些耦合关系。

0
相关文章