前一篇,是《封装》的尾巴(点我),这一篇,是《派生》的前奏……(突然有一种七八月份的感觉)
8.1. 派生
类型和类型之间可以有很多关系,其中“派生”是最重要和最基础的一种关系。这里有一道小学语文题。
〖轻松一刻〗:做小学题,学类型的派生关系
请照着1和2中三个词语的关系,从A、B、C、D中选出一个你认为合适的词填在划线处:
1) 人类、白种人、黄种人; 2) 交通工具、小汽车、飞机; 3) 电脑、台式机、_____
备选答案:A)樟脑;B) 硬盘、C)拖拉机、D)笔记本。
除非你坚决认为我说的“笔记本”是纸簿,否则你应该不会选错。这就是“派生”的基本概念:B类型是一种特定的A类型。比如:“白种人是一种特定的人类”,或者“飞机是一种特定的交通工具”。此时可称B为“派生类”,A为“基类”,描述为:A类派生出B类,或者B类继承自A类。
你需要能够看得懂以下关系图:
请注意箭头的方向:由派生类指向基类,这是当前软件设计界流行的表示法。用C++的语法,可以表达为:
先不必太关心语法,只要能看出上面有三个,而不是一个class即可。但有读者马上要问了:真的需要把“Car”和“Airplane”全部设计为class吗?为什么它们不可以就是“交通工具”这个类的两个变量?示意为如下代码:
这种思路是:我设计了一个超强的“交通工具类”,它同时具备小汽车和飞机应用的功能,然后当需要时,我希望它是小汽车,它就是小汽车,希望它是飞机,它就是飞机。必须承认,前几年我坐某航空公司的飞机到北京,飞机降落机场时找不到停机位,于是庞大的铁鸟在首都机场上四处乱逛,当时我是感觉自己正坐在大巴士上……但这是错觉!现实中要设计生产一种既可以在市区像QQ车一样四处钻,又可以腾空而飞的玩意儿,怎么可能呢?
(有同学不服气:人家美国的变型金刚就是这样子的……)
这就是学习“派生”之后,你经常要向自己问的一个重要问题:你真的需要一个派生类吗?比如足球有真皮做的,也有塑胶做的,那么我们需要“足球(基类)”、“皮足球”和“塑胶足球”三个类吗?
别轻易说“要”或“不要”……复习一下“什么是封装”?封装一个类,既需要考虑事物内部的本质不变式,还需要考虑它的使用者是谁。
对于卖体育用品的商店,或者对于买家,通常是不需要将“皮足球”和“塑胶足球”分别定义成一个类。“皮”或“塑胶”只是足球一个属性:材料,我们可以用一个枚举来作简单区分。
足球当然还有其它属性,比如尺寸或颜色等等,都非常适于像这里的“价格”及“材料”一样,被仅仅当成足球的属性看待(设计为一个类的不同成员)。
对于足球的产家就不同了,他需要关心一个足球如何生产出来,所以可能会为Football类添加“制作”、“质检”等等和生产相关函数,而“皮球”和“塑胶球”在这些操作上,可能天差地别,这时分拆成三个类就非常自然:
这就回到了“飞机”与“小汽车”无法合二为一的情况了,工厂无法在同一条生产线同时生产真皮球和塑胶球,负责塑胶球的质检员,最好不要同时也负责真皮球的质检(当然,当然,我知道资本家可能不这么想)。当使用者是厂家时,足球class就和前面为买卖过程所做的设计大有不同:此时我们希望不同材质的球可以拥有自己的Make函数,从而可以避免去写一个超强的,必然也是超复杂的,无所不能的Make或QualityTest函数。
〖危险〗: 不要迷恋“变形金刚”,那只是童年一个梦……
每个C++程序员懂得“类”是要设计的……于是乎有些人设计设计再设计,代码里就出现一个“变形金刚”类。原来他们把所有逻辑全写到一个函数或一个类里面(变形金刚),然后通过各种开关,各种复杂的逻辑,去区分这个类什么时候是一个机器人,什么时候又是一只汽车……
其实,真正的设计,首先是懂得“拆分”,派生是拆分的方法之一。
当然,也要反复不管三七二十一,对象稍有区别,就被设计成两个类,这是一种“过度设计”。但对于初学者,有时候只是懒惰造就了一个个庞然大物——却振振有辞:我在设计一个伟大的变形金刚,请不要拿那种无趣的规则制约我的创造力!
醒醒噢,我们写的是代码,而不是科幻小说,请不要把代码写成一份无人理解的寂寞。
最后提一个问题:足球的尺寸,通常只需要做为一个属性设计,请读者思考什么情况下,足球的尺寸也会造成专门设计一个派生类才更合适?
如果您想与我交流,请点击如下链接成为我的好友:
http://student.csdn.net/invite.php?u=112600&c=f635b3cf130f350c