物件導向設計 談談繼承與合成

2021-04-14 22:32:31 字數 3179 閱讀 4843

合成 vs 繼承

關聯class的兩種基本途徑的對比

出處:http://www.artima.com/designtechniques/compoinh.html

摘要這是我的design techniques的一部分,這裡我分析了兩者的構成(flexibility)和執行牽連(performance implications),並且我針對兩者分別給出了指導方針。

正文建立兩個類之間的關聯是軟體設計的眾多基本行為之一。繼承和合成是兩種基本的實現方法。儘管當你使用繼承的時候jvm可以幫你做很多事情,但是你仍然可以使用合成來達到同樣的目的。本篇將比較這兩種途徑且給出使用它們的指導方針。

首先,介紹繼承和合成的背景

關於繼承

class fruit

關於合成

class fruit

private fruit fruit = new fruit();

//......

}動態繫結,多型和改變

當你使用繼承來關聯兩個類的時候,你就可以利用動態繫結和多型的好處了。

動態繫結和多型最主要的好處之一是,他們可以幫助你更簡單的修改

**,包括新增新的子類。然而這些不能包括所有你需要改變的地方

修改superclass介面

在繼承關聯中,superclasses通常被稱為「脆弱的(fragile)」,因為對superclass的一點點的改動將波及到眾多應用程式的**。說的更明白些,superclass最脆弱的是它的介面。如果superclass是well-designed的――良好的介面設計,oo風格的實現,那麼任何supperclass的實現的改變將不會有任何影響。如果修改superclass的介面,那麼將波及到任何使用該superclass的地方和其subclass。

繼承有時被成為提供「弱封裝(week encapsulation)」,因為你直接使用subclass的地方都會受superclass介面的改變的影響。從某個角度來講,繼承是讓subclass重用superclass的**。

選擇合成?

繼承性的關聯很難來修改superclass的介面。合成則提供了easier-to-change的途徑。

通過繼承的**重用

class fruit

//將上面替換掉的新方法

public peel peel() }}

class example1

}通過合成的**重用

class fruit

//需求改變後,將上面方法修改後的新介面

public peel peel()

}private fruit fruit = new fruit();

public int peel()

}class example2

}在合成實現方式中,subclass變為front-end class,superclass變為back-end class。使用繼承,subclass自動繼承了superclass的non-private方法;使用合成,front-end class必須在自身的實現中明確的呼叫back-end class中的相應的方法。這種直接呼叫有時被稱為「推進(forwarding)」或「委派(delegating)」這個方法的呼叫到back-end物件。

比較合成與繼承

幾點對比:

    back-end class(合成)比superclass(繼承)更容易修改介面。就像前面舉例說明的那樣,back-end class介面的改變必將導致front-end class實現的改變,但不會影響到front-end class的介面,所以依賴front-end class的**將正常工作。作為對比,superclass介面的修改不僅波及subclass層,也會影響到所有直接使用superclass介面以及使用subclass介面的地方

    front-end class(合成)比subclass(繼承)更容易修改介面。正像superclass是脆弱(fragile)的,而subclass是堅硬(rigid)的。你不能只改變subclass的介面而不去確認新介面是否和父型別(supertypes)相容。例如,你不能在subclass中新增乙個與superclass方法同樣特徵但返回值型別不同的新方法。合成則允許你修改front-end class的介面,而不用關心back-class。

    合成允許你延遲back-end objects的建立,直到他們被需要的時候才建立,在front-end object的生命期內可以動態的改變back-end objects。對於繼承來說,一旦subclass被建立了,你就可以通過subclass object來獲取superclass的某些資源了,在subclass生命期內一直保持著superclass的物件,也就是說,subclass object一旦被建立,superclass就已知且不可改變了。

    新增subclasses(繼承)比新增front-end class(合成)更容易。因為繼承伴隨多型。如果你的一些**僅依賴superclass,那麼不用任何修改,你就能夠使用乙個新的subclass。對於合成來說就不可以,除非你使用帶有介面的合成(composition with inte***ces)。合成和介面的共同使用將提供乙個非常強大的設計工具。

    同使用subclass中從繼承superclass來的方法實現相比,合成中的直接的方法呼叫委派經常(often)有效能損耗。often的意思是說,因為效能依賴眾多因素,比如jvm優化並執行程式的能力。

    對於合成和繼承來說,修改任何class的實現都是簡單的。實現改變引起的連鎖反映被保留在同乙個class

在合成和繼承中作出選擇

怎麼作出選擇呢?這裡有乙個指導方針來讓我們趨向合成與繼承中的其中乙個

繼承是is-a的關係

當你認為已經有乙個is-a關係的時候,你需要問自己 乙個非常重要的問題,那就是這個「is-a 關係」是否在應用程式或**生命週期中保持不變的(constant)。舉例:當employee在某個時間段扮演的角色是person的時候,你可能認為 employee is-a person。如果person被解雇會怎樣?如果person即是employee又是supervisor會怎樣?這種暫時的is-a關係通常使用合成,而不是繼承。

不要僅僅為了得到**重用就使用繼承

如果你的確想重用**且沒有觀察到is-a關係,那麼使用合成

不要僅僅為了獲取多型就使用繼承

如果你卻是想要多型,但是沒有

自然的is-a關係,那麼使用帶有介面的合成(composition with inte***ces),這將在下個月介紹。 

物件導向設計原則 合成復用原則

合成復用原則又稱為組合 聚合復用原則 composition aggregate reuse principle,carp 其定義如下 合成復用原則 composite reuse principle,crp 盡量使用物件組合,而不是繼承來達到復用的目的。合成復用原則就是在乙個新的物件裡通過關聯關係...

談談物件導向

相信不少人也迷惑物件導向是什麼?該怎麼理解?這是乙個令人相當頭疼的問題,以前有個大神給我講過,在這裡整理一下,留作紀念,希望能幫到大家,也歡迎各位大牛指導。所謂物件,無賴的理解就是萬物皆物件,一般在大型專案中必須要使用物件導向程式設計 oop 優點是能夠更好地建立模型,使 更加清晰,易於維護,當然逼...

六 繼承與物件導向設計條款32 34

is a即 是一種 的關係,比如drive繼承自base,那麼我們有 例如,student繼承自乙個person類,那麼 void eat person p void study student s person p student s eat s 正確呼叫,每個s都是p的物件 study p 錯誤...