|
|
如果你已經定義好某個類別,可以繼承這個類別,自然的,子類別就擁有父類別已定義好的功能,你可以在父類別的基礎上,擴充你想要的功能。 就功能面來說,繼承確實是有以上所提及的作用,然而,就語義來說,繼承具有是一種(is a)的關係,也就是你繼承自一個東西,你就是那種東西,以 繼承了什麼? 中的例子而言,SwordsMan與Magician不僅繼承了Sprite中的程式碼定義,其實,還繼承了是一種的關係,劍士是一種角色,魔法師也是一種角色,也就是說,繼承不單只是繼承父類別的程式定義,還繼承了種類。 在Java這類只支援單一繼承的語言中,是一種的關係更強烈且更具限制性。 假設今天你開發了一個照相機(Camera)類別: public class Camera { public Picture take() { .... } } 現在你想開發一款手機(Cellphone),擁有照相功能,你可能會想,因為你已經有照相機類別了,這個類別已具有照相的功能定義,繼承這個類別再增加撥打電話的功能,如此一來你就不用再重新於手機類別中,定義照相的功能了: public class Cellphone extends Camera { public void dial(String number) { ... } } 然而,仔細想想,手機是一種照相機嗎?或許就現階段而言,這可以解決問題,但如果將來,你打算開發一款手機,擁有MP3播放的功能,你想想之後,直接繼承手機好了: public class MP3Cellphone extends Cellphone { public void play() { .... } } 但如果是低價手機,不能擁有照相機的功能,這樣的需求就使得這種設計不適用了。顯然地,手機不是一種照相機,只是某個手機擁有照相的功能,MP3手機繼承自手機,手機繼承自照相機,那MP3手機會是一種照像機嗎? 未思考是否具有「是一種」的關係,而只是為了繼承某個類別既有的功能來進行擴充,就用了繼承的機制,往往會導致不適當的設計,要不就讓類別擁有了不該有的職責,要不就導致過深的繼承機制,要不就將來需求變更後擴充不易,而使得必須調整程式架構。 如果只是為了擁有某個已定義好的功能,繼承並非最優先的考量,而可以考慮看看複合(Composite)關係。例如,如果你想開發一個手機具有照相功能,也許你可以這麼設計: public class Cellphone { private Carema carema; public void setCarema(Carema carema) { this.carema = carema; } public Picture take() { return carema.take(); } public void dial(String number) { ... } } 在這樣的設計之下,手機不會是一種照相機,而只是內建照相機,這是有一個(has a)的關係。現在如果有款手機擁有播放MP3的功能,或許你可以定義一個MP3Player類別,然後如下設計: public class MP3Cellphone { private MP3Player player; public void setMP3Player() { this.player = player; } public void play() { player.play(); } public void dial(String number) { ... } } 顯然地,就解決了先前的需求。不過,現在發現,你重複撰寫了dial()方法。這時候,你可以思考,或許可以定義一個CellPhone父類別: public class Cellphone { public void dial(String number) { ... } } 如果是照相手機,本質上「是一種」手機內建照相機,所以現在照相手機可以如下設計: public class CaremaCellphone extends Cellphone { private Carema carema; public void setCarema(Carema carema) { this.carema = carema; } public Picture take() { return carema.take(); } } 就這方面來說,使用繼承時擁有「是一種」關係並不為過。而具有播發MP3功能的手機,則可以如下定義: public class MP3Cellphone extends Cellphone { private MP3Player player; public void setMP3Player() { this.player = player; } public void play() { player.play(); } } 優先思考利用複合關係,並在適當的時候才應用上繼承,謹慎思考關係到底是「有一個」或「是一種」,對於設計上才會擁有較大的彈性。 |