天涯一飘絮

导航

 

一、  扩展机制

记住,今后想增加更多的扩展性通常是可能的,但是想在去掉扩展性的同时不破坏已有代码是不可能的。

1、   非密封类

如果需要既简单又开销不大的扩展方法,那么没有声明任何虚成员或保护成员的非密封类是不错的选择。这种方法用户也喜欢

 

由于非密封类具有相对较低的测试开销,因此它提供的扩展性开销不会很高。

2、   保护成员

保护成员本身并不能提供任何的扩展性,但他们能够加强派生子类这一扩展机制。可以用他们来暴露高级的定制选项,同时可以避免不必要的使公有接口复杂化。

 

同时要注意,所谓受保护的并不是安全的,任何人都可以从非密封类派生子类型兵访问保护成员。

 

3、   事件与回调函数

回调函数是一种扩展机制,它使框架能够通过委托来调用用户代码,这些委托通常是作为方法的参数传递给框架的。

        List<string> names = new List<string>();

        names.RemoveAll(

            delegate(string name)

            {

              return name.StartsWith("Seattle");

            }

            );

事件是一种特殊的回调函数,它为用户提供了一致的语法,使得用户能够非常方便的把委托提供给框架。

 

与虚成员相比,回调函数可以用来提供相当强的扩展性。同时,由于不需要对面向对象的设计有非常深入的了解,因此回调函数和事件能够为更广泛的开发人员所接受。此外,回调函数提供动态扩展性,虚成员则只能提供静态扩展性。

回调函数的主要缺点在于,与虚成员相比显得太过重量级。通过委托进行调用的性能不如调用虚成员。另外,由于委托是对象,因此它们会消耗内存。

还应该清楚的是,如果让用户传入委托兵让框架调用,那么在框架执行的代码就有可能是任意的代码。

 

考虑使用回调函数让框架能够执行用户提供的代码。

考虑使用事件让用户定制框架的行为,这样就不需要用户对面向对象的设计有深入的了解。

要优先使用事件,而不是简单的回调函数,原因在于开发人员更熟悉事件。

避免在对性能要求很高的API中使用回调函数(CLR2.0调用委托比调用虚成员慢了快两倍)

要理解在调用委托时可以执行任何代码。这可能会引起安全,正确以及兼容的问题。

 

4、   虚成员

虚成员可以被覆盖,从而改变子类型的行为。从提供扩展性来看,虚成员与回调函数旗鼓相当,但从执行性能和内存消耗来看。虚成员更胜一筹。此外,如果要为已有的类型创建一个特殊的版本,那么使用虚成员会感觉更自然。

 

与回调函数相比,虚成员的主要缺点在于它的行为只能静态修改,而回调函数可以动态修改。

虚成员和回调函数一样,设计,测试以及维护的开销都非常高。基于这点,应该考虑限制虚成员的扩展性。只有在当前有明确需求的情况下,才应该通过虚成员来提供扩展。

 

不要使用虚成员,除非有合适的理由。同时对设计,测试,维护虚成员的开销有清楚的认识。

要在保证兼容性的前提下对虚成员进行修改是很难的。另外,虚成员比非虚成员要慢,主要是因为编译器无法内联对虚成员的调用。

 

考虑只有在绝对必须的时候才使用虚成员提供扩展,并使用Template Method模式。

要优先使用受保护的虚成员,而不是公有虚成员。公有虚成员应该调用受保护的虚成员了来提供扩展(如果必要)

5、   抽象(抽象类型与抽象接口)

抽象就是描述一个协定,单兵部位该协定提供完整的类型。抽象通常实现为抽象类或接口,并带有一些参考文档,来描述实现该协定的类型必须具备哪些语义。

一个有意义并且有用的抽象能够经受住时间的考研,单同时也非常难以设计,主要困难在于确定合适的成员。抽象的设计开销极高。但是,抽象提供了极其强大的扩展性,这是通常其他扩展机制所无法比你的。

 

要在设计抽象时仅售的选择抽象类或者抽象接口。

考虑为抽象的具体实现提供参考测试。

二、  基类

严格的说,当一个类有另一个类派生自它时,这个类就成为了积累,但是我们这里讨论的积累,被限定为这样的一个类:其设计目的不是为了直接使用或提供常用抽象,而是为了让其他类通过集成它来重用它的默认实现。

一般来说,基类本身并不适合来提供抽象,这是因为它们倾向于包含太多的实现细节。

积累能为需要实现抽象的用户提供有价值的帮助,但是他们同时也可能成为一种沉重的义务。他们扩大了接触面,加深了继承层次的深度,从概念上说,这让框架变得更加复杂。因此,只有在积累能给框架的用户提供许多价值时候,才应该使用,如果仅仅有助于框架的实现者,则不应该使用基类,把需要的功能委托给一个ieneibu实现是更好的办法。

 

考虑使积累成为抽象类,即使他们兵不包含任何抽象成员。这能够清楚的告诉用户,设计这些类的目的完全是为了让用户从它进行派生。

考虑把基类与用于主要场景的类型分开,放到单独的命名空间下。

三、  密封

面向对象框架的特性之一就是用户能够对框架爱进行扩展和定制,所使用的方法可能连框架的设计者都不曾预料到。

 

不要把类密封起来,除非有恰当的理由。

把类密封起来的恰当理由包括:

1、   类为静态类

2、   类的保护成员保存了需要高度保密的机密信息。

3、   类继承了许多虚成员。

4、   类是attribute需要能在运行的时候快速查找。

 

不要在密封类中声明保护成员或虚成员

考虑在覆盖成员时将其密封。


 

posted on 2009-01-15 11:11  冰云  阅读(208)  评论(0编辑  收藏  举报