成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

為什么更推薦使用組合而非繼承關系?

開發 前端
不知道大家項目中繼承用的多嗎?其實在JDK中就有許多違反這條原則的地方,比如棧Stack?類并不是Vector?,不應該有繼承關系,但是實際上就是繼承自Vector。

?前言

最近在看公司項目的代碼,看到了大量的繼承體系,而且還是繼承了多層,維護、閱讀都十分的困難。在查閱了一些資料以后,包括《Effective Java》一書中的第16條提到“組合優先于繼承”。那繼承到底會暴露什么問題呢?為什么更推薦優先使用組合呢?

繼承帶來的問題

老實講,項目中為什么大量使用繼承,估計初版設計的人是想實現代碼的復用,但是的確帶來不少的問題。

繼承是面向對象重要特性之一,語義上是表達 is-a的關系,但是它會破壞封裝性。我們舉個例子:

假設我們要設計一個關于鳥的類。我們將“鳥類”這樣一個抽象的事物概念,定義為一個抽象類 AbstractBird?,默認有eat吃東西的行為。所有更細分的鳥,比如麻雀、鴿子、鴕鳥等,都繼承這個抽象類。

public class AbstractBird { 
//... 省略其他屬性和方法...
public void eat() { //... }
}

// 鴕鳥
public class Ostrich extends AbstractBird {

}

但是,這時候搞不清楚情況的人根據需求給AbstractBird?添加一個fly()的行為。但是對于鴕鳥這個子類來說,并不會飛,你如果不做任何處理,相當于讓鴕鳥有了飛翔的功能,不符合設計。聰明的你想到了,那就重寫以下吧,拋出一個異常,如下所示:

public class AbstractBird { 
//... 省略其他屬性和方法...
public void eat() { //... }

public void fly() { //... }
}

// 鴕鳥
public class Ostrich extends AbstractBird {
//... 省略其他屬性和方法...
public void fly() {
throw new UnSupportedMethodException("I can't fly.'");
}
}

這種設計思路雖然可以解決問題,但不夠優美。因為除了鴕鳥之外,不會飛的鳥還有很多,比如企鵝。對于這些不會飛的鳥來說,我們都需要重寫 fly()?方法,拋出異常。而且真正好的設計,對于鴕鳥和企鵝來說,就不應該暴露給他們fly()這種不該暴露的接口,增加外部調用的負擔。

這里只提到了fly()?,如果還有下蛋egg()?、唱歌sing()這么多行為,總不能都冗雜在父類里吧。關鍵像我們的項目同事,基本上把所有的類都寫到了父類中,真的特別難以維護。

小結一下繼承帶來的問題:

子類繼承了父類所有的行為,會讓子類無意的暴露的不必要的接口,破壞封裝性。

如果繼承層級比較多,那么代碼的復雜度、可閱讀型就可想而知的難了。

另外一個點,就是非常不好做單元測試。

針對于這種問題,組合能怎么解決呢?

組合的好處

組合,顧名思意,就是把另外一個對象做成當前這個對象的一部分,是組成我的一部分,它也能很好的實現代碼的復用,語義上表達的是has-a的意思,我有xxx的能力,我有xxx的功能。

那我們看看針對上面的例子,用組合的方式該如何實現呢?

  • 定義接口
public interface Eatable {
void eat()
}
public interface Flyable {
void fly()
}

public class EatAbility implements Eatable {
@Override
public void eat() {
System.out.println("I can eat");
}
} //

public class FlyAbility implements Flyable {
@Override
public void fly() {
System.out.println("I can fly");
}
} //
  • 組合鴕鳥類
public class Ostrich implements Eatable {// 鴕鳥
private Eatable eatable = new EatAbility(); // 組合
//... 省略其他屬性和方法...
@Override
public void eat() {
eatable.eat(); // 委托
}
}

你看對于鴕鳥這個子類來說,只暴露了它有的能力,那就是eat?,沒有暴露fly的接口。

從理論上講,通過組合、接口、委托三個技術手段,我們完全可以替換掉繼承,在項目中不用或者少用繼承關系,特別是一些復雜的繼承關系。

繼承真的無用武之地了?

既然面向對象中有繼承這玩意,說明它并非一無是處的。

如果類之間的繼承結構穩定(不會輕易改變),繼承層次比較淺(比如,最多有兩層繼承關系),繼承關系不復雜,我們就可以大膽地使用繼承。反之,系統越不穩定,繼承層次很深,繼承關系復雜,我們就盡量使用組合來替代繼承。

除此之外,還有一些設計模式會固定使用繼承或者組合。比如,裝飾者模式(decorator pattern?)、策略模式(strategy pattern?)、組合模式(composite pattern?)等都使用了組合關系,而模板模式(template pattern)使用了繼承關系。

總結

不知道大家項目中繼承用的多嗎?其實在JDK中就有許多違反這條原則的地方,比如棧Stack?類并不是Vector?,不應該有繼承關系,但是實際上就是繼承自Vector。不管如何,在項目中決定使用繼承而不是組合前,一定要考慮清楚,子類是否真的是父類的子類型?以后父類會不會經常變動的可能?父類的某些API是否存在缺陷,如果有的話也會隨著子類擴散出去。

責任編輯:武曉燕 來源: JAVA旭陽
相關推薦

2012-03-06 20:51:04

iOS

2024-09-24 08:18:13

2024-01-30 07:55:03

KubernetesAPI服務器

2023-07-04 16:28:23

2024-11-29 08:20:22

Autowired場景項目

2009-07-22 09:02:45

Scala組合繼承

2022-06-26 23:03:14

Go標準庫語言

2021-12-09 07:54:19

IDL字段兼容

2024-11-12 10:30:54

Docker部署數據庫

2024-06-04 00:10:00

開發拷貝

2025-05-16 02:00:00

HashMapJava代碼

2024-09-12 08:32:42

2015-07-31 16:29:15

DockerJavaLinux

2019-04-24 08:00:00

HTTPSHTTP前端

2020-09-08 16:00:58

數據庫RedisMemcached

2021-12-27 07:10:26

ClassmethodStaticmetho函數

2023-11-06 13:04:59

Python日志庫

2025-02-14 00:00:25

C#后端RPS

2022-09-26 10:26:27

FieldIDEASpring

2024-06-14 08:00:46

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久性色 | 国产精品亚洲一区 | 亚洲成人激情在线观看 | 日韩在线欧美 | 日韩在线视频一区二区三区 | 成人免费大片黄在线播放 | 国产日产欧产精品精品推荐蛮挑 | 国产黄色一级片 | 99精品一级欧美片免费播放 | 免费观看的黄色网址 | 成人在线免费观看视频 | 欧美一区二区三区视频 | 久久久久无码国产精品一区 | 中文一区 | 国产国产精品 | 亚洲区视频 | www.久久精品视频 | 嫩草网| 日韩欧美国产精品一区二区三区 | 男人的天堂在线视频 | www.色午夜.com| 亚洲一区二区久久 | 第一区在线观看免费国语入口 | 7799精品视频天天看 | 九九成人| 99精品欧美一区二区三区综合在线 | av天天看 | 亚洲网在线| 久草视频网站 | 毛片视频免费观看 | 国产一区二区影院 | 日本aa毛片a级毛片免费观看 | 欧美一级二级视频 | 国产高清在线精品一区二区三区 | 国产亚洲一区二区三区在线观看 | 成人网av | 亚洲视频在线播放 | 国产精品久久久久久久久久妞妞 | 成人国产精品视频 | 日韩欧美一级片 | 精品国产一区二区久久 |