国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java中的繼承與組合

2019-11-14 23:37:22
字體:
來源:轉載
供稿:網友
java中的繼承與組合

本文主要說明Java中繼承與組合的概念,以及它們之間的聯系與區別。首先文章會給出一小段代碼示例,用于展示到底什么是繼承。然后演示如何通過“組合”來改進這種繼承的設計機制。最后總結這兩者的應用場景,即到底應該選擇繼承還是組合。

1、繼承

  假設我們有一個名為Insect(昆蟲)的類,這個類包含兩個方法:1)移動move(); 2)攻擊attack()。

  代碼如下:

12345678910111213141516171819202122232425262728293031323334class 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(); //假設昆蟲在攻擊前必須要先移動一次System.out.println("Attack");}}

  現在,你想要定義一個名為Bee(蜜蜂)的類。Bee(蜜蜂)是Insect(昆蟲)的一種,但實現了不同于Insect(昆蟲)的attack()和move方法。這時候我們可以用繼承的設計機制來實現Bee類,就像下面的代碼一樣:

1234567891011121314class 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();}}
123456public class InheritanceVSComposition {public static void main(String[] args) {Insect i = new Bee(1, "red");i.attack();}}

  InheritanceVSComposition作為一個測試類,在其main方法中生成了一個Bee類的實例,并賦值給Insect類型的引用變量 i。所以調用i的attack方法時,對應的是Bee類實例的attack方法,也就是調用了Bee類的attack方法。

  類的繼承結構圖如下,非常簡單:

輸出:

123FlyFlyAttack

  Fly被打印了兩次,也就是說move方法被調用了兩次。但按理來講,move方法只應當被調用一次,因為無論是昆蟲還是蜜蜂,一次攻擊前只移動一次。

  問題出在子類(即Bee類)的attack方法的重載代碼中,也就是super.attack()這一句。因為在父類(即Insect類)中,調用attack方法時會先調用move方法,所以當子類(Bee)調用super.attack()時,相當于也同時調用了被重載的move方法(注意是子類被重載的move方法,而不是父類的move方法)。

  為了解決這個問題,我們可以采取以下辦法:

  1. 刪除子類的attack方法。這么做會使得子類的attack方法的實現完全依賴于父類對于該方法的實現(因為子類繼承了父類的attack方法)。如果父類的attack方法不受控制而產生了變更。比如說,父類的attack方法中調用了另外的move方法,那么子類的attack方法也會產生相應的變化,這是一種很糟糕的封裝。
  2. 也可以重寫子類的attack方法,像下面這樣:
1234public void attack() {move();System.out.println("Attack");}

  這樣保證了結果的正確性,因為子類的attack方法不再依賴于父類。但是,子類attack方法的代碼與父類產生了重復(重復的attack方法會使得很多事情變得復雜,不僅僅是多打印了一條輸出語句)。所以第二種辦法也不行,它不符合軟件工程中關于重用的思想。

  如此看來,繼承機制是有缺點的:子類依賴于父類的實現細節,如果父類產生了變更,子類的后果將不堪設想。

2、組合

  在上面的例子中,可以用組合的機制來替代繼承。我們先看一下運用組合如何實現。

  attack這一功能不再是一個方法,而是被抽象為一個接口。

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

  通過對Attack接口的實現,就可以在實現類當中定義不同類型的attack。

1234567891011121314151617181920class 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方法。

12345678910111213141516171819202122232425class 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類,它具有attack的功能,所以它實現了attack接口:

1234567891011121314151617// 這個封裝類封裝了一個Attack類型的對象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();}}

  類圖:

  測試類代碼,將AttackImpl的實例作為Attack類型的參數傳給Bee類的構造函數:

123456789101112public 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 attackBee b = new Bee(1, "black", new AttackImpl("fly", "sting"));b.attack();}}
1234flymoveflysting
3、什么時候該用繼承,什么時候該用組合?

  以下兩條原則說明了應該如何選擇繼承與組合:

  • 如果存在一種IS-A的關系(比如Bee“是一個”Insect),并且一個類需要向另一個類暴露所有的方法接口,那么更應該用繼承的機制。
  • 如果存在一種HAS-A的關系(比如Bee“有一個”attack功能),那么更應該運用組合。

  總結來說,繼承和組合都有他們的用處。只有充分理解各對象和功能之間的關系,才能充分發揮這兩種機制各自的優點。

文章出處:http://www.lupaworld.com/article-242748-1.html


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 西吉县| 宜川县| 天气| 邹平县| 新蔡县| 嵊泗县| 蒙城县| 湘潭县| 福泉市| 舞阳县| 丰都县| 蒲江县| 新宁县| 垫江县| 泰宁县| 东海县| 镇赉县| 会宁县| 石阡县| 兴山县| 马山县| 双鸭山市| 万载县| 高尔夫| 涟源市| 新干县| 合川市| 新安县| 贵阳市| 珲春市| 福泉市| 万盛区| 阳曲县| 阿坝| 岗巴县| 温泉县| 增城市| 宣恩县| 裕民县| 黔江区| 石屏县|