继承

了解继承

在设计继承时,你会把共同的程序代码放在某个类中,然后告诉其它类说此类是它们的父类。当某个类继承另一个类的时候,也就是某类继承自父类。

以Java的方式说,这是“子类继承父类”。继承的关系意味着子类继承了父类的方法。当我们提成“类的成员”时,成员的意思就是实例变量和方法。

举例来说,如果Pantherman是SuperHero的子类,则Pantherman会自动继承SuperHero的实例变量和方法。包括了suits,tights,specialPower,useSpecialPower()。但Pantherman可以加入自己的实例变量和方法,也可以覆盖掉继承自SuperHero的方法。

FiredEggMan不需要任何独特的行为,所以它没有覆盖过任何的方法。然而Pantherman认为它的特殊能力需要特别处理过的方法,所以就覆盖了useSpecialPower()和putOnSuit()。

设计动物仿真程序的继承树

假设你要设计一个仿真系统程序,可以让用户设定将一群动物丢到某种环境中以观察会发生什么事情,现在没有必要写出程序,我们只在乎设计。

这个程序必须能够在任何时间加入新类型的动物。

我们首先要辨认出所有动物都有的、抽象的共同特征,然后以这些共同特征设计出能够让所有动物加以扩充的类。

①找出具有共同属性和行为的对象

这六种动物有什么共同点?这么问可以帮助我们执行第二个步骤。

这些类型有什么相关性?这么问有助于执行第四到第五个步骤。

②设计代表共同状态与行为的类

这些对象都是动物,因此我们可以用Animal作为共同父类的名称。

我们会把所有动物都需要的方法和实例变量都加进去。

用继承防止子类中出现重复的代码程序。

我们有5个实例变量:picture:动物JPEG图像的名称。food:此动物所吃的食物,现在只有meat和grass两种值。hunger:代表饥饿程序的int值,它会根据动物吃了多少东西而改变。boundaries:代表动物活动范围区域的长宽。loaction:动物在活动区域中的X与Y坐标。

还有4个方法:makeNoise():动物发出声音的行为程序。eat():动物遇到食物时的行为程序。sleep():睡眠的行为程序。roam():不在进食或睡眠时的行为程序。

Animal下有子类:Lion,Hippo,Tiger,Dog,Cat,Wolf。

③决定子类是否需要让某种行为(也就是方法的实现)有特定不同的运作方式

观察Animal这个类之后,我们认为eat()与makeNoise()应该由各个子类自行覆盖。

动物都以同样的方式进食吗?

假设我们都同意一件事,所有Animal类型上的实例变量都合用。狮子的picture带有它的图片路径,food的值时meat。猫的图片就是猫,猫的事务是meat(其实养过猫的人知道猫其实也会吃草)。所以实例变量没有问题,但是行为程序呢?

我们应该覆盖哪些方法呢?

狮子的叫声会和河马一样吗?也许你认为一样,但是我们会根据类型设计出不同的行为程序。当然我们也可以用实例变量来存放声音文件的路径值,而让makeNoise()方法都执行相同的动作。但是有时候行为的复杂程序不只是如此而已。

最好能够覆盖eat()与makeNoise()这两个方法,如此才能让每个动物定义出不同的进食和叫声行为。

④通过寻找使用共同行为的子类找出更多抽象化的机会

我们观察到Wolf和Dog可能有某些共同的行为,在Lion,Tiger,Cat之间也是。

寻找更多抽象化的机会

类的继承结构已经大致成型。我们让每个子类都去覆盖掉eat()和makeNoise()方法,因此狗不会喵喵叫(这对双方来说都是种侮辱),河马也不会抢狮子的食物。

但或许我们还能做更多的设计。我们必须观察Animal的子类,找寻是否有可以组织归纳使用共同程序代码的部分。看起来小红帽的好朋友大灰狼跟狗有共同的部分。猫、狮子和老虎也有共同的部分。

⑤完成类的继承层次

因为动物本来就有组织化的层次(界,门,纲,木,科,属,种),我们可以用这些层次来制作有意义的类设计。我们使用犬科和猫科动物的分类来作出Feline与Canine这两个类。

我们决定Canine使用共同的roam()方法,因为它们都以相同的方式移动。Feline之间也差不多,而Hippo则继续使用继承下来的roam()方法。

这个层次就完成了。

“是一个”和“有一个”

当一个类继承自另一个类时,我们会说这是子类继承父类。若你想要知道某物是否应该要继承另一物时,则可以用“IS-A”测试来检验。

三角形是一个多边形......嗯,没错。

外科医生是一个医生......OK。

helloKitty是一只猫......算是吧。

澡盆是一个浴室......失败!

大肠没有洗干净......失败中的失败!

要确认你的设计是否正确,使用这样的测试来加以检验。如果不合理,表示你的设计有问题。

浴室和澡盆有关系,但不是继承上的关系。浴室和澡盆发生的是HAS-A的关系。如果“浴室有一个澡盆”成立的话,这表示浴室带有澡盆的实例变量,也就是浴室会有一个澡盆的引用,但是浴室并没有继承过澡盆。

浴室有一个澡盆且澡盆有一个泡泡,但这里没有继承关系。

IS-A测试使用在继承的任何地方,如果你的继承层次设计得很好,那么所有的子类都应该通过任一个上层父类的IS-A测试。

如果类Y是继承类X,且类Y是类Z的父类。那么Z应该能通过IS-A X的测试。

若Canine继承Animal,Wolf继承Canine。

你一定可以说,Wolf继承Animal,或者Wolf IS-A Aniaml,只要Animal位于Wolf之上,那么Wolf IS-A Aniaml就一定成立。

Wolf是一个Canine,因此Canine能做的事Wolf都能做,而Wolf是一个Animal,所以Animal能做的事Wolf也都能做。

就算Wolf覆盖掉某些来自Canine或Animal的方法也一样,对其它的程序来说,它们只要知道Wolf能够执行这4个方法就行,至于它是怎么做的,或是它是覆盖过哪个类的,则一点都不重要。至少有一件事可以确定,Wolf一定可以eat(),makeNoise(),sleep(),和roam()。

如何知道继承的设计是对的?

如果 X IS-A Y 合理,则这两者或许存在于同一个继承结构下,也有可能两者根本是相同的,或许刚好有相同的行为。

注意,继承概念下IS-A是个单向的关系。

三角形是一个多边形合理,所以你可以从多边形中扩充出三角形。但反过来说“多边形是一个三角形”并不合理,所以多边形并不是从三角型中extend出来的。要记得X IS-A Y

隐喻着X可以做出任何Y可以做的事情(且还可能做出更多的行为)。

public类型的成员会被继承;

private类型的成员不会被继承;

当子类把成员继承下来时会把它们当作是自己定义的一样。任一类的成员包含有自己定义出来的变量和方法再加上从父类所继承下来的所有东西,

 

你会用继承吗?你滥用继承了吗?

当某个类比其父类更具有更定意义时使用继承。例如说美国短毛猫是一种特定品种的猫,所以从猫中扩充出美国短毛猫时合理的。

在行为程序(实现程序代码)应该被多个相同基本类型类所共享时,应该要考虑使用继承。举例来说,方形、长方形、圆型、三角形都需要旋转,因此将这些功能放在它们的父类上是合理的,并且这样也比较好维护和扩充。然而,注意到虽然继承是面向对象程序设计的一项关键特征,但却不一定是达成重用行为程序的最佳方式。

若两者间的关系对于继承结构并不合理,则不要只是因为打算要重用其它类的代码而运用继承。例如,在设计钢琴对象时,不要因为想要借用河马对象的发生程序就让这两个八竿子打不着的对象产生继承上的关系。这完全不合理。(应该要创建发生对象,然后让钢琴和河马都用HAS-A的关系运用此对象才对。)

如果两者间不能通过IS-A测试就不要应用继承关系,一定要确认子类是父类的一种更特定的类型才可以。

继承到底有什么意义?、

通过设计继承的过程你可以累积面向对象的经验,通过提取出一组类间共同的抽象性,你能够排除掉重复的程序代码而将这个部分放在父类中。如此一来,如果有共同的部分需要改变,就只会有一个地方要修改而已,且这样的改变会应用到所有继承此行为的类,修改过后只需要重新编译即可,不必动子类。

换上改变过的父类,则所有扩充过它的类都会自动使用到新的版本。

①避免了重复的代码

②定义出共同的协议

继承可以让你确保某个父型之下的所有类都会有父型所持有的全部方法

也就是说,你会通过继承来定义相关类间的共同协议

当你在父类中定义方法时,它们会被子类继承,这样你就是在对其它程序代码声明:“我所有的子类都能用这些方法来执行这几项工作”。

也就是说你拟出了一份“合约”。

例如Animal类是在声明所有的Animal都可以执行这4个动作,这包括了方法的参数和返回类型。

当我们在说所有的动物时,是指Animal和所有继承Animal的子类,也就是在继承层次上方有Animal的任何一个类。

不过我们还没讨论到最精彩的部分———多态(polymorphism),这留到下一篇。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值