Golang Composition over Inheritance
Golang 是一門簡潔有力的程式語言,相較於其他程式語言,更傾向於使用組合(composition)而不是繼承(inheritance),語言設計之初更是沒有提供繼承的關鍵字,這種設計哲學讓 Golang 在現代軟體開發中脫穎而出。 繼承固然有其優點,但在建構複雜的物件關係時,容易產生過於龐大的繼承層級結構。這使得程式碼難以閱讀和維護,就像是一棵盤根錯節的大樹,牽一髮而動全身。 過深的繼承層級會導致知名的「脆弱基類問題」(fragile base class problem),使得程式碼難以修改和擴展。 組合則不同,它鼓勵建立小型、專注的 struct,然後像樂高積木一樣,將這些 struct 組合成更大的結構。這種方式讓程式碼模組化,更容易理解和修改。 彈性 Golang 的 type system 支援我們靈活地組合各種 struct。可以建立一個新的 struct,並在其中「嵌入」其他 struct 作為其欄位。 type Car struct { make string model string year int } type Driver struct { name string car Car } func main() { myCar := Car{"Toyota", "Camry", 2020} driver := Driver{"John", myCar} fmt.Println(driver.name) // 輸出: John fmt.Println(driver.car.make) // 輸出: Toyota } 在這個例子中,Driver 透過組合 Car 來建立更豐富的資料結構。Driver 「has-a」 Car,而不是 「is-a」 Car,這提供了更高的彈性,讓 Driver 可以更專注在自身的邏輯。 程式碼複用 組合促進了程式碼的複用。可以建立許多小型、可複用的 struct,然後將它們組合成各種不同的結構。 繼承也能實現程式碼複用,但它也可能導致不必要的耦合,使得程式碼難以修改,因為對父類別的修改可能會影響到所有子類別。 type Engine struct { power int fuelType string } type Wheels struct { count int material string } type Vehicle struct { engine Engine wheels Wheels brand string } func (v Vehicle) getBrand() string { return v.brand } func (v Vehicle) getEnginePower() int { return v.engine.power } 在這個例子中,Vehicle 透過組合 Engine 和 Wheels 來複用這兩個 struct 的欄位和功能。Vehicle 「has-a」 Engine and 「has-a」 Wheels,並可以新增自己的欄位和方法,例如 brand、getBrand() 和 getEnginePower()。這種方式讓 Vehicle 可以專注於自身的邏輯,同時又能複用 Engine 和 Wheels 的功能。 ...