菜鳥譯文(一)——Java中的繼承和組合

閱讀英文的能力對於程序員來講,是很重要的。這幾年也一直在學習英文,今天心血來潮,就在網上找了一篇簡短的博文翻譯一下。水平通常,能力有限,還請各位看官多多指點。java


譯文:
react

本文將會舉例說明Java中繼承和組合的概念。首先舉一個繼承的例子,而後展現一下如何用組合來改善繼承的設計。最後歸納一下如何在它們之間作出選擇。
程序員

 

1. 繼承 app

假設咱們有一個Insect類。這個類包含兩個方法:一個是move(),一個是attack()。
ide

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 attacking
        System.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();
    }
}

 

類層次結構關係圖就是如此簡單ui


輸出: this

Fly
Fly
Attack


"Fly"被打印了兩次,表示move()被調用了兩次。可是它應該被調用了一次纔對。 spa

問題出在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;
    }
 
    @Override
    public void move() {
        System.out.println(move);
    }
 
    @Override
    public 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 object
class 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();
    }
}

 

fly
move
fly
sting

 


3. 什麼時候用繼承,什麼時候用組合?

下面兩條內容,能夠告訴咱們如何在繼承與組合之間作出選擇:

  1. 若是存在一個「是」的關係,而且一個類要對另外一個類公開全部的接口,那麼繼承是更好的選擇
  2. 若是存在一個「有」的關係,那麼首選組合。

總之,繼承和組合都有其用途,和理解他們的優缺點是頗有必要的。


最後說一點本身的感覺吧,小弟自打初中開始學英語,成績就沒好過,最好成績也就剛及格吧。記得當年高考的時候lz的英語成績是55分(足以載入史冊的成績),個人英文水平有多差,你們可想而知了吧。後來承蒙恩師的諄諄教誨,一直沒有放棄英語的學習,如今依然天天都在學(雖然沒有掌握其精髓,可是學總比不學強)。之前遇到外國人根本張不開嘴,不知道說什麼,如今好多了,以前常常跟老外一塊兒踢球,沒事瞎白話幾句,感受也挺好玩的。之前看到英文的文章,直接關掉,如今也能靜下心來看下去了。


總之,學英語心態很重要,只要你不怕它,它就沒什麼好怕的。毛主席曾說過:「All the reactionaries are the Papertiger(一切反動派都是紙老虎)」。英語沒什麼好怕的,遇到老外你就跟他瞎扯唄,最不濟你倆打個平手——誰也聽不懂誰說什麼。還有更壞的結果嗎?無論怎樣咱都不會輸,那你還怕啥?看英文文章、書籍看不懂,那就更不用怕了,大不了弄個詞典唄,我大有道在手,還怕治不了你個小英文了。別猶豫了,上吧,少年!


原文連接: Inheritance vs. Composition in Java

相關文章
相關標籤/搜索