优雅OOP(2) - 继承与复合

2009.10.21

三大基石之二  继承与复合

       讲过了封装,我们说继承和复合,继承与复合的核心思想是重用现有的代码,用一些已有的类去创建新的类。但其意义远不只这些。

       普通的书籍总是强调继承与复合是为了重用代码,但实际上它的意义深远不仅仅在这么一个小小的方面,而是更加接近于面向对象思想对复杂模型的抽象上、      
                                                          -《As3殿堂之路》

1.继承

       继承,Inheritance,是一种看起来很神奇的代码重用方式。声明一个新类(class)作为现有类的子类,然后,这个新类就自然而然地具有了现有类的功能。

       继承其实是一种很好理解的思想,它意味着新类看起来和其父类相似,新类拥有父类的所有功能,并可以添加和重写原有的功能。

       一个例子,蝴蝶是昆虫类的子类,具有昆虫的所有特征(六条腿,有触角等),同时也有着自己的特点(可以飞行,有着别的昆虫没有的漂亮翅膀)。

       除了这一点,继承(这里只限于公有继承)还产生了另一种奇妙的东西叫做向上转换或向上映射(Upcasting)。就是说在代码中可以将子类对象作为父类对象来使用。例如,我们可以在任何说到昆虫的地方用蝴蝶代替,因为蝴蝶具昆虫的所有特征。不过我们却不指望随便一只昆虫都长着蝴蝶那样美丽的翅膀。【有关具体的继承语法和子类当做父类使用的代码示例请查阅相关教材,这里只是重点讲下思想】

       向上转换不仅符合继承的定义,也符合我们客观世界的规律。需要注意的是,C++中的私有继承和保护继承方式会破坏向上转换这一特性,因此,在一些面向对象语言中没有提供私有继承和保护继承的机制。当然私有继承和保护继承也有着它们自己的特点,它们多用于对父类本质实现的继承,而忽略了对父类对外接口的继承,这里不再多说了。

       其实,这里所提到的继承思想在人类的生活中并不常见(程序设计中继承也较难掌握),多出现在人类对自然界的分类。我们观察周围的世界发现,人们更喜欢用的是复合和一种特殊形式的继承(对抽象类的继承,会在多态中讲到。如汽车继承于交通工具这个抽象类)。

2.复合

       复合,Composition,即将各个部分组合在一起。程序设计中就是用已有类的对象来产生新的类。

       桌子由木板和钉子组合而成,台灯使用灯座,灯管,电线,接头等拼起来的。我们发现自己周围的很多东西都是由更小的其它东西拼凑构成的,就像积木一样。相信你小的时候也曾拆开过许多你觉得好奇的东西,去一看究竟。去看看这个新的类(class)到底是由那些其他的类构成的。其实在你很小的时候你已经理解了复合。

       程序设计中,复合体现在生成的新类里用到了现有类的实例,具体的代码例子在这里也不给出了,相信你一看就能明白。

       复合使生成新类更加简便和直观,实现也非常容易,相比继承这种通过已有类构造新类的方法,大多数人(包括在现实生活中)更喜欢复合。

3.何时用继承,何时用复合?

       在实际编程中,使用复合的频率要远远超过继承,对于OOP新手而言,要慎用继承,勤用复合。有些极端的OOP人士推崇复合憎恨继承,声称继承是“邪恶”的,一切都是复合。虽然是极端之言,博大家一笑,但实际应用中复合确实比继承灵活,而且更加直白。

       虽然继承号称面向对象的三大基石之一,但不正确的使用继承不仅仅是代码维护的灾难,也是真是逻辑的扭曲。因此,在看完了下面的一段后,你还是暂时不明白何时用复合何时用继承的话,请优先考虑复合。

   a.需要用到向上转换时请考虑继承。

   b.用“has a”和“is a”来区分复合和继承。即考虑新类是有一个(has a)现有类的对象(如新类为汽车,现有类为轮胎,请考虑复合),或是新类是一个(is a)现有类的特殊情况(如蝴蝶和昆虫,考虑继承)。

三大基石之一 - 封装
本文地址:http://imyuao.com/entries/blog/posh_oop2
三大基石之三 - 多态

Go Back

Comment