本文适合有一定经验的程序员阅读。本文假定读者你是懂面向对象的封装继承多态的。
文章的例子,以常见的“美食”为例来演示。文章的代码以中文演示,是为了让您看得方便,生产中,建议英文。
多态
它的规矩是简单而易见的,通常使用abstract和virtual来标记。所以,在C#中,您只需要根据这2个关键字,便可以认出它是多态。
多态,可以针对方法、属性、事件、索引器使用。
以美食为例,我们知道,美食存在多种做法,我们的业务会划分中西餐,而中餐和西餐的做法是不同的。所以,美食的类应该根据需求封装如下:
由于美食存在中餐和西餐的制作方法不同,所以,我们需要给方法Make()打上virtual关键字,以便根据实际情况给出不一样的做法:
好的,这是一个很简单的例子,对于懂面向对象特性或者仅懂abstract及virtual关键字的读者来说,这小儿科。
那么:您知道什么情况下该加virtual关键字,什么情况下不加吗?
这是窗体Winform组件Control的基类Component,我想问下为什么给Site加了virtual,而Container却不加?
为什么Dispose()不加virtual,而Dispose(bool)却加了virtual?
virtual的用法是简单的,每个人都会,加上它即可以。用它可以很好的进行程序扩展。但加了virtual是有性能开销的,比不加的开销要大些。为了更好的追求程序设计,您不应该随意添加virtual。
程序设计的最小、最少原则
这不是一个教程里,至少不是上了台面的原则。就是说,我们的程序设计在做任何设计的时候,都应往最小、最少的方向考虑,这适用于很多方面。
比如,一个方法体的代码行数,超出30行,您就要思考是否耦合了2种或者更多的业务逻辑。
比如,通篇都是public,您是否确定真的全部都应该public,就没有需要internal、private的吗?
比如,判断条件(if/else)过多的时候,我是否没有进行良好的设计,没有做好抽象?
比如,当我的设计类,被别人继承后,我的方法或者属性,是否需要开放修改,还是过多开放?
等等等等,很多情况,都是您需要考虑的。
多态,什么情况下加virtual,什么情况下不加?
回过头来看Winform的Component类的设计,它开放了Site属性的virtual,那么代表它在设计时,一定有他们的考量,该属性存在有可能要让子类修改的必要,所以加virtual。而Container,可能仅需要传达数据,它是通过其它地方传递过来的,无法提供修改可能,所以禁止重写。
对于Dispose来说,它用于资源释放,而释放通常仅需要提供调用即可,因为它的重写可能性存在于针对本类的非托管资源来操作,所以,它要设计为保护方法是虚的。您还需要知道一点:public的Dispose()方法,将调用protected的Dispose(bool)方法,知道这点很重要。也就是说,它变相的使用了virtual。
加virtual的一些原则参考:
1.除非你有明确的理由,确信本类是可以扩展的,并且方法、属性、索引器、事件等有被重写的必要理由。才添加virtual关键字。
2.多态的范围,应尽可能缩小,如果有必要,可以将其虚化范围限制为protected,而不必要一定是public。然后public的公共成员,应调用protected的受保护成员来实现扩展。
3.所有密封类sealed无需多态。
举例子:
像ABP(AspNet Boilerplate),它所有的服务方法(Service)均要求声明为virtual,以便获得事务。这是它的理由。您也需要理由。
祝您用餐愉快。