跨语言继承

在过去,如果用一种语言子类编写组件,然后再用另一种语言子类来扩展该组件,这是非常困难的,或者说事实上是几乎不可能的。用C++编写一个类,再用VB来继承它以创建一个新的对象,像这样的事是绝对不可能发生的。如果没有父对象的或者至少头文件的源代码,我们同样也没办法使用一个已编译成二进制的组件(即使这组件是用同一种语言编写的)并从中派生出一个新的对象。

不过,由于有了CLR,我们就可以解决上述问题。与.NET类相关的元数据提供了足够多的信息(甚至是以已编译的形式),使我们可以从现有的类中派生出新类。CLR可以让我们做的另一件事情是一种不同的语言派生一个新类。过去要派生一个新类得拥有基类的源代码才行,而且编写新类所用的语言必须与基类所使用的语言相同。但是现在所有的CLR语言都编译成中间语言,所以用户可以使用任何一种CLR语言派生新类。

继承复用接口

当你继承了一个类时,你也创建了一个新的类。这个新的类不仅包含了已有类的所有成员(尽管private成员已经隐藏起来了,是不能访问的),更重要的是它复制了基类的接口。于是所有能够传给基类的消息也都可以传给派生类。由于我们根据它能接受什么消息来判断这是什么类,因此这就意味着派生类和基类是属于同一类型的。

既然基类和派生类具有相同的基本接口,那么这个接口的背后就必须跟着实现。也就是当对象收到某个消息的时候,它必须能执行一些代码。如果你只是继承了一个类,其他什么都不做,那么基类的方法会直接带进派生类,也就是说派生类的对象与基类的对象的类型相同而且行为也一样,这可就没有什么吸引力了。

用继承来进行设计

一旦理解了多态性,你就会觉得所有东西应该都是继承下来的,因为多态性实在是太聪明了。但是这样做会加重设计的负担;实际上,如果你一遇到“要用已有的类来创建新类”的情况就想到要用继承的话,事情就会毫无必要地变得复杂起来了。

较好的办法还是先考虑合成,特别是当你不知道该继承那个类的时候。合成并不强求你把设计搞成一个类系。此外它还更灵活,因为使用合成的时候,你可以动态地选择成员的类型(以及它们的行为)而使用继承的话,就得在编译时指明对象的确切类型。

但是程序运行时函数的reference可以连到另一个对象上,因为可以用其它对象来替换它,于是构造函数的行为就发生了变化。这样你就在运行时获得了高度的灵活性。这也被称为状态模式。反观继承,它不能让你在运行时继承不同的类;这个问题在编译的时候就已经定下来了。

用继承扩展interfere

实现多个接口的时候可能会遇到一些小问题。例如,Can和Action都有一个一模一样的fight()方法。这里没有问题,因为它们使用的是同一个方法。但是,有个难题要归因于覆写、实现和重载的不期而遇,以及“不能仅通过返回值来辨别重载的方法。如果把最后两行的注释去掉,就会出现错误。而且在要并的接口里面放上同名的方法,通常也会破坏程序的可读性,所以别这么做。

你可以用继承,往interface里面添加新的方法,也可以用继承把多个interface合并成一个新的interface。在这两种情况下,你所得到的都只是一个新的interface。但是我们用Dang对Monster做了一点扩展,然后生成一个新的interface,这样就实现了这个接口。

«1»