事件模式
基于事件和委托,FCL可以非常广泛地使用Observer模式。FCL的设计者充分认识到此模式的巨大潜力,并在整个框架中将其应用于用户界面和非UI特定的功能。但是,用法与基本Observer模式稍有不同,框架小组将其称为事件模式。
通常,将此模式表示为事件通知进程中所涉及的委托、事件和相关方法的正式命名约定。虽然CLR或标准编译器并没有强制要求利用事件和委托的所有应用程序和框架都采用这种模式,但Microsoft建议这样做。
其中的第一条约定也可能是最重要的约定是主体公开的事件的名称。对于它所表示的状态变化而言,此名称应该是不言自明的。切记,此约定以及所有其他此类约定本身就是主观性的。目的是为那些利用您的事件的人员提供清晰的说明。事件模式的其他部分利用正确的事件命名,因而此步骤对模式来说至关重要。
回到我们的示例,让我们分析一下这种约定对Stock类产生的影响。派生事件名称的适当方法是,利用在主体类中修改的字段的名称作为根。因为在Stock类中修改的字段名称是_askPrice,所以合理的事件名称应该是AskPriceChanged。很明显,此事件的名称比StateChangedInStockClass等具有更强的描述性。因此,AskPriceChanged事件名称符合第一条约定。
事件模式中的第二条约定是正确命名委托及其签名。委托名称应该包含事件名称(通过第一个约定选择的)及附加词Handler。此模式要求委托指定两个参数,第一个参数提供对事件发送方的引用,第二个参数向观察者提供环境信息。第一个参数的名称就是sender。必须将此参数键入为System.Object。这是由于以下事实:可能将委托绑定到系统中任何类上的任何潜在方法。第二个参数的名称(甚至比第一个参数更简单)为e。必须将此参数键入为System.EventArgs或某种派生类(有时比此内容还多)。虽然委托的返回类型取决于您的实现需要,但大多数实现此模式的委托根本不返回任何值。
需要稍加注意委托的第二个参数e。此参数允许主体对象将任意环境信息传递给观察者。如果不需要此类信息,则使用System.EventArgs实例就足够了,因为此类的实例表示没有环境数据。否则,应该使用相应的实现构造从System.EventArgs派生的类以提供此数据。必须按照具有附加词EventArgs的事件名称来命名该类。
请参考我们的Stock类,此约定要求将处理AskPriceChanged事件的委托命名为AskPriceChangedHandler。此外,应该将此委托的第二个参数命名为AskPriceChangedEventArgs。因为我们需要将新的股价传递给观察者,所以我们需要扩展System.EventArgs类,以将该类命名为AskPriceChangedEventArgs并提供实现来支持传递此数据。
事件模式中的最后一个约定是负责引发事件的主体类上方法的名称和可访问性。此方法的名称应该包含事件名称以及添加的On前缀。应该将此方法的可访问性设置为保护。此约定仅适用于非密封(在VB中不可继承)类,因为它作为派生类调用在基类中注册的观察者的已知的调用点。
将此最后一条约定应用于Stock类,即可完成事件模式。因为Stock类不是密封的,所以我们必须添加一种方法来引发事件。按照该模式,此方法的名称为OnAskPriceChanged。下面的C#代码示例显示应用于Stock类的事件模式的完整视图。请注意我们的System.EventArgs类的专门用法。
事件模式示例(C#)
public class Stock {
//declare a delegate for the event public delegate void AskPriceChangedHandler(object sender, AskPriceChangedEventArgs e); //declare the event using the delegate public event AskPriceChangedHandler AskPriceChanged;
//instance variable for ask price object _askPrice;
//property for ask price public object AskPrice {
set { //set the instance variable _askPrice=value;
//fire the event OnAskPriceChanged(); }
}//AskPrice property
//method to fire event delegate with proper name protected void OnAskPriceChanged() {
AskPriceChanged(this,new AskPriceChangedEventArgs(_askPrice));
}//AskPriceChanged
}//Stock class
//specialized event class for the askpricechanged event public class AskPriceChangedEventArgs:EventArgs {
//instance variable to store the ask price private object _askPrice;
//constructor that sets askprice public AskPriceChangedEventArgs(object askPrice) { _askPrice=askPrice; }
//public property for the ask price public object AskPrice { get { return _askPrice; } }
}//AskPriceChangedEventArgs
|
结论 基于这里对Observer模式的分析,我们可以清楚地看到此模式提供了一个完美的机制,能够在应用程序中的对象之间划定清晰的界限。虽然通过回调进行实现(使用IObserver和IObservable接口)相当简单,但CLR的委托和事件概念可处理大多数“繁重的工作”,并降低主体和观察者之间的耦合级别。实际上,通过正确地使用此模式,在确保应用程序可演变性方面就会向前迈出一大步。当您的UI和业务要求随时间发生变化时,Observer模式可确保能够简化您的工作。
在开发灵活的应用程序方面,设计模式是一个非常强大的工具(如果有效地加以运用)。撰写本文是为了说明模式方法的有效性,并重点说明.NET框架中使用的一种模式。将来的文章将继续探究FCL中的模式,并简要介绍一些用于生成有效Web服务的模式。
查看本文来源