歡迎來到物件導向程式設計(OOP)的世界!如果你已經成功掌握了類別(Class)與物件(Object)的概念,那麼你已經準備好邁向重要的一步:理解這些類別之間是如何互動的。
請將類別想像成大型機器中不同組件的藍圖。這一章就是要學習如何繪製連接這些組件的線路和螺栓,讓它們能作為一個統一的系統運作。掌握這些關係對於編寫高效、靈活且強大的程式碼至關重要!
1. 理解類別關係:為什麼需要連結它們?
在現實世界的系統中,沒有任何實體是完全孤立存在的。銀行帳戶需要客戶;汽車需要引擎;球隊需要球員。
物件導向程式設計(OOP)讓我們可以使用類別之間的正式關係來模擬這些現實世界的連結。你必須知道的兩種主要關係類型是繼承(Inheritance)和關聯(Association)。
小貼士: 理解這些關係有助於你設計出更容易偵錯和更新的系統(這與軟體開發中可維護性的概念息息相關)。
2. 繼承:一種「是一種」(Is-A)的關係
什麼是繼承?
繼承是一種基礎關係,其中一個類別基於另一個類別建立,並繼承其屬性和方法。它模擬的是一種「是一種」(Is-A)的關係。
例子:狗(Dog)是一種哺乳動物(Mammal)。汽車(Car)是一種交通工具(Vehicle)。
- 原始的類別稱為基底類別(Base Class)(也稱為父類別 Parent Class 或超類別 Superclass)。
- 新的、更具體的類別稱為子類別(Subclass)(也稱為衍生類別 Derived Class 或子類別 Child Class)。
主要優點是什麼?程式碼重用!如果所有動物都會吃,你只需要在基底類別(Animal)中定義一次 eat() 方法,所有子類別(Dog, Cat, Bird)就會自動繼承它。
類比:交通工具藍圖
想像你有一份通用交通工具(Vehicle)(基底類別)的詳細藍圖。這份藍圖包含了像 start_engine() 這樣的方法,以及 colour 和 speed 這樣的屬性。
當你要建立一份汽車(Car)(子類別)的藍圖時,你不需要重寫所有內容。你只需要說:「汽車繼承自交通工具」,然後加入汽車特有的東西,例如 number_of_doors。
受保護存取修飾詞(折衷方案)
在基底類別中定義屬性或方法時,我們使用存取修飾詞(Access Modifiers)(如 public 或 private)來控制可見性(這是封裝 Encapsulation 的一部分)。
受保護(Protected)存取修飾詞(在圖表中用 # 表示)在繼承中相當特別:
- 公開(Public,
+):任何人都可以存取。 - 私有(Private,
-):僅能在定義該類別的內部存取。 - 受保護(Protected,
#):可在定義該類的基底類別內部,以及所有子類別中存取,但外部物件無法存取。
為什麼要使用 Protected? 它允許子類別管理或修改父類別的核心功能,同時又避免程式的其他部分對這些功能進行隨意竄改。
覆寫方法(Overriding Methods)
有時候,子類別會繼承一個方法,但其實作方式需要與基底類別不同。這時候就需要覆寫(Overriding)。
覆寫是指在基底類別中定義的方法,在子類別中被重新定義(修改),從而使子類別實例的行為不同。
覆寫的逐步範例:
- 交通工具(Vehicle)(基底類別)有一個方法:
calculate_fuel_economy()。 - 電動車(ElectricCar)(子類別)繼承了這個方法。
- 由於電動車不使用汽油,子類別覆寫了
calculate_fuel_economy(),改為計算能源消耗(例如每公里的千瓦時 kWh/km)。 - 當你在電動車物件上呼叫此方法時,會執行子類別的版本。
重點總結:繼承
繼承模擬的是「是一種」(Is-A)關係。它涉及基底類別和子類別,能實現專門化和程式碼重用。覆寫允許子類別改變繼承來的行為。受保護 (#) 修飾詞則僅授予基底類別及其子類別存取權限。
3. 關聯:一種「擁有」(Has-A)的關係
什麼是關聯?
關聯是兩個物件之間更廣泛、更寬鬆的關係,其中一個物件僅僅是使用或包含另一個物件。它模擬的是一種「擁有」(Has-A)的關係。
如果物件 A 使用物件 B,我們就說物件 A 與物件 B 相關聯。
你知道嗎?關聯是一種比繼承弱得多的關係。物件即使沒有與之相關聯的物件,也可以運作得很好。
例子:足球模擬系統(根據課程大綱背景)
- 我們有球隊(Team)類別和球員(Player)類別。
- 球隊「是一種」球員嗎?不。
- 球隊「擁有」球員嗎?是的,一個球隊物件包含或使用了多個球員物件。
只要物件需要互動或連結,但其中一個並非另一個的特殊版本時,我們就會使用關聯。
重點總結:關聯
關聯模擬的是「擁有」(Has-A)關係。這意味著一個物件會使用另一個物件。當物件是獨立的實體但需要協同工作時(例如,客戶 Customer 擁有一個 地址 Address),就會使用關聯。
4. 視覺化關係:類別圖
為了清楚傳達類別之間的連結方式,程式設計師會使用圖表(通常基於 UML – 統一塑模語言)。你需要熟悉繼承和關聯的符號,以及如何標示存取層級。
存取指定符號
這些符號標示了類別框中屬性和方法的可見性:
+:公開存取(Public)(任何人皆可存取)-:私有存取(Private)(僅類別本身可存取)#:受保護存取(Protected)(類別及其子類別可存取)
類別結構範例(圖表)
類別名稱(Class Name)
- 私有屬性(private_attribute)
# 受保護屬性(protected_attribute)
+ 公開屬性(public_attribute)
- 私有方法(private_method())
+ 公開方法(public_method())
繼承標記法(專門化)
繼承由一條實線表示,箭頭末端是一個空心的封閉三角箭頭,指向基底類別。
箭頭指向父類別:「子類別依賴父類別的定義。」
子類別(Subclass) ▲ 基底類別(Base Class)
|
關聯標記法(使用)
關聯由連接兩個相關類別的實線表示。你可能會看到箭頭表示使用的方向,如果關係是雙向的,則可能沒有箭頭。
球隊類別(Team) ------------------ 球員類別(Player)
如果關係是單向的(例如 A 類別使用 B 類別,但 B 不知道 A 的存在),你會加上一個簡單的開口箭頭。
類別 A ------------------> 類別 B
快速複習:關係符號
- 繼承:空心三角形箭頭指向上方(指向父類別)。
- 關聯:簡單實線或帶有開口箭頭的線。
- 存取:
+(公開),-(私有),#(受保護)。
繼續練習識別圖表中的這些符號,並將它們與 OOP 的核心概念——專門化(繼承)與協作(關聯)聯繫起來。你一定行的!