菜鸟译文(一)——Java中的继承和组合

来源:互联网 发布:python课程推荐 编辑:程序博客网 时间:2024/06/05 06:35

阅读英文的能力对于程序员来说,是很重要的。这几年也一直在学习英文,今天心血来潮,就在网上找了一篇简短的博文翻译一下。水平一般,能力有限,还请各位看官多多指点。


译文:

本文将会举例说明Java中继承和组合的概念。首先举一个继承的例子,然后展示一下如何用组合来改善继承的设计。最后概括一下如何在它们之间做出选择。

1. 继承

假设我们有一个Insect类。这个类包含两个方法:一个是move(),一个是attack()。

class Insect {private int size;private String color; public Insect(int size, String color) {this.size = size;this.color = color;} public int getSize() {return size;} public void setSize(int size) {this.size = size;} public String getColor() {return color;} public void setColor(String color) {this.color = color;} public void move() {System.out.println("Move");} public void attack() {move(); //assuming an insect needs to move before attackingSystem.out.println("Attack");}}


现在你想定义一个Bee类,它是Insect类型的,但是有着不同实现的attack()方法和move()方法。我们可以用继承来设计,如下所示:

class Bee extends Insect {public Bee(int size, String color) {super(size, color);} public void move() {System.out.println("Fly");} public void attack() {move();super.attack();}}public class InheritanceVSComposition {public static void main(String[] args) {Insect i = new Bee(1, "red");i.attack();}}



类层次结构关系图就是如此简单


输出:

FlyFlyAttack


"Fly"被打印了两次,表示move()被调用了两次。但是它应该被调用了一次才对。

问题出在super.attack()方法上。Insect的attack()方法调用move()方法。当子类调用super.attack()时,总是会调用重写的move()方法。


我们可以用下面的方法解决这个问题:

  1. 去掉子类的attack()方法。这将使子类取决于父类attack()方法的实现,如果父类中的attack()方法发生改变(这是你无法控制的),例如:父类的attack()方法使用其他的方式来实现,子类也需要跟着改变,这不是好的设计。
  2. 重写attack()方法,如下:
    public void attack() {move();System.out.println("Attack");}

    这样能保证正确的结果,因为子类不再依赖于父类 。然而, 代码变成了一个父类的复制品。(想象一下,attack()方法远比打印一个字符串要复杂的多)这违背了软件工程复用的原则。

这个继承的设计不好,因为子类依赖父类的具体实现,如果父类发生变化,子类将被破坏。

2. 组合

与继承相反,组合可以用于这种情况。让我们先看看使用组合的解决方法。

attack方法被抽象为一个接口。

interface Attack {public void move();public void attack();}

可以对Attack接口进行多种不同的实现。

class AttackImpl implements Attack {private String move;private String attack; public AttackImpl(String move, String attack) {this.move = move;this.attack = attack;} @Overridepublic void move() {System.out.println(move);} @Overridepublic void attack() {move();System.out.println(attack);}}

将attack方法抽出来,Insect就不再与attack相关联了。

class Insect {private int size;private String color; public Insect(int size, String color) {this.size = size;this.color = color;} public int getSize() {return size;} public void setSize(int size) {this.size = size;} public String getColor() {return color;} public void setColor(String color) {this.color = color;}}

Bee是一个Insect的类型,它可以攻击。

// This wrapper class wrap an Attack objectclass Bee extends Insect implements Attack {private Attack attack; public Bee(int size, String color, Attack attack) {super(size, color);this.attack = attack;} public void move() {attack.move();} public void attack() {attack.attack();}}



类图:




public class InheritanceVSComposition2 {public static void main(String[] args) {Bee a = new Bee(1, "black", new AttackImpl("fly", "move"));a.attack(); // if you need another implementation of move()// there is no need to change Insect, we can quickly use new method to attack Bee b = new Bee(1, "black", new AttackImpl("fly", "sting"));b.attack();}}

flymoveflysting

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

下面两条内容,可以告诉我们如何在继承与组合之间做出选择:

  1. 如果存在一个“是”的关系,并且一个类要对另一个类公开所有的接口,那么继承是更好的选择
  2. 如果存在一个“有”的关系,那么首选组合。

总之,继承和组合都有其用途,和理解他们的优缺点是很有必要的。


最后说一点自己的感受吧,小弟自打初中开始学英语,成绩就没好过,最好成绩也就刚及格吧。记得当年高考的时候lz的英语成绩是55分(足以载入史册的成绩),我的英文水平有多差,大家可想而知了吧。后来承蒙恩师的谆谆教诲,一直没有放弃英语的学习,现在依然每天都在学(虽然没有掌握其精髓,但是学总比不学强)。以前遇到外国人根本张不开嘴,不知道说什么,现在好多了,之前经常跟老外一起踢球,没事瞎白话几句,感觉也挺好玩的。以前看到英文的文章,直接关掉,现在也能静下心来看下去了。


总之,学英语心态很重要,只要你不怕它,它就没什么好怕的。毛主席曾说过:“All the reactionaries are the Papertiger(一切反动派都是纸老虎)”。英语没什么好怕的,遇到老外你就跟他瞎扯呗,最不济你俩打个平手——谁也听不懂谁说什么。还有更坏的结果吗?不管怎样咱都不会输,那你还怕啥?看英文文章、书籍看不懂,那就更不用怕了,大不了弄个词典呗,我大有道在手,还怕治不了你个小英文了。别犹豫了,上吧,少年!


原文链接: Inheritance vs. Composition in Java



7 0