💻 綜合學習筆記:物件導向與進階程式設計 (9645)
你好,未來的電腦科學家!歡迎來到物件導向程式設計 (Object-Oriented Programming, OOP) 及其他關鍵進階程式設計技巧的章節。這些概念起初可能顯得有些抽象,但它們是現代大型軟體開發的基石。別擔心!我們會把它們拆解成簡單易懂的部分。學完這一章,你將學會如何設計出穩健、靈活且可重用的程式碼。
讓我們開始吧!
1. 物件導向程式設計 (OOP) 基礎 (3.9.1)
OOP 是一種強大的程式設計方法,它將程式碼圍繞著物件 (Objects) 來構建,而不僅僅是函式和邏輯。它透過將現實世界中的實體直接模擬到我們的程式中,幫助我們管理複雜性。
什麼是類別 (Class)? (藍圖)
類別 (Class) 本質上是一個藍圖、範本或定義,用於創建物件。它定義了該類型所有物件將擁有的通用特徵(資料)和行為(動作)。
- 類比:將類別想像成汽車工廠的藍圖。它規定了每輛車都必須有四個輪子、一個引擎,以及像 start()(啟動)和 accelerate()(加速)這樣的方法。
屬性 (Properties / Attributes)
這是定義物件狀態的資料欄位。它們捕捉了物件的特徵。
- 範例:如果類別是 Car(汽車),屬性就會是 colour(顏色)、speed(速度)和 fuelLevel(油量)。
方法 (Methods)
這些是在類別內定義的函式或程序,決定了物件可以執行的動作或行為。
- 範例:對於 Car 類別,方法將包括 startEngine()(啟動引擎)、brake()(煞車)或 refuel()(加油)。
什麼是物件 (Object)? (實際的東西)
物件 (Object) 是類別的實體化表現。一旦你建立了一個物件,它就擁有了關於其屬性的特定且獨特的值。
- 類比:汽車藍圖(類別)是抽象的。而停在外面那輛紅色的 Toyota Corolla(物件)則是具體的,並由該藍圖實體化而成。
實體化 (Instantiation)
實體化 (Instantiation) 是從類別創建物件的過程。當你實體化一個類別時,你是在要求電腦為該特定物件及其獨有的資料分配記憶體。
建構子 (Constructors)
建構子 (Constructor) 是一種特殊的方法,當物件被實體化時會自動呼叫。其主要工作是將物件初始化為特定的狀態。
- 如果你建立一個 Car 物件,建構子可能會自動將初始 speed 設為 0,並將 fuelLevel 設為 50 公升。
類別 (Class):藍圖(定義結構)
物件 (Object):實例(實際建造出來的結構)
建構子 (Constructor):初始化器(設定物件的起始資料)
2. 封裝 (Encapsulation) (隱藏細節) (3.9.2)
封裝 (Encapsulation) 是 OOP 的支柱之一。它意味著將資料(屬性/屬性)與操作這些資料的方法捆綁在一起,形成一個單元(類別),且關鍵在於隱藏類別運作的內部機制以及它如何向其他類別呈現資料。
為什麼要使用封裝?
它保護了資料的完整性。如果內部資料只能由受控的方法(而不是直接)修改,你就能確保資料始終有效。(例如:你可以確保速度永遠不會低於零。)
存取修飾詞 (Access Modifiers / Access Specifiers)
存取修飾詞是用於定義類別成員(屬性和方法)可見性和可存取性的關鍵字。
- 公有 (Public,
+):可在程式的任何地方存取,包括類別外部。(汽車喇叭 - 誰都可以按。) - 私有 (Private,
-):只能在宣告它們的類別內部存取。(引擎內部的溫度計 - 只有引擎相關的方法需要看到這個。) - 受保護 (Protected,
#):可在類別本身以及任何繼承自它的子類別 (subclasses) 中存取。(只有汽車及其特殊貨車版本才知道的維修程序。)
Getter 與 Setter 方法
由於私有資料無法被類別外的物件直接存取,我們使用稱為 Getter 和 Setter 的特殊公有方法來提供受控的存取權。
- Getter:用於獲取(get)私有屬性值的方法。
- Setter:用於修改(set)私有屬性值的方法。Setter 通常包含驗證邏輯,以確保新數值是合理的。
類比:想想銀行帳戶。帳戶餘額(資料)是私有的。你不能直接伸手去更改那個數字。你必須使用像 deposit()(存款,一個 setter)或 checkBalance()(查詢餘額,一個 getter)這樣的公有方法。這些方法保護了資料。
3. 類別之間的關係 (3.9.3)
現實世界系統涉及許多交互的組件。在 OOP 中,類別必須建立關係來模擬這種交互。
繼承 (Inheritance) (「是一種」(Is-a) 關係)
繼承 (Inheritance) 是一種關係,其中一個類別(子類別 (subclass) 或衍生類別 (derived class))是現有類別(基底類別 (base class) 或父類別 (parent class))的更專業版本。
- 它促進了程式碼重用 (code re-use),因為子類別會自動獲得基底類別的所有屬性和方法。
- 範例:Truck(貨車)類別(子類別)繼承自 Vehicle(車輛)類別(基底類別)。貨車 *是一種* 車輛。
覆寫 (Overriding)
覆寫 (Overriding) 是指子類別重新定義了從基底類別繼承而來的方法。這允許子類別在保持相同方法名稱的情況下,針對該特定方法表現出不同的行為。
- 範例:Car(汽車)和 Motorcycle(機車)(皆為 Vehicle 的子類別)都有 drive()(駕駛)方法。機車的 drive() 方法會被覆寫,以包含特定於兩個輪子而非四個輪子的行為。
關聯 (Association) (「使用一個」(Uses-a) 關係)
關聯 (Association) 是兩個物件之間的一般關係,其中一個物件可以使用另一個物件。
- 這是一種比繼承更弱的關係。
- 範例:在足球模擬遊戲中,Team(球隊)物件與多個 Player(球員)物件相關聯。球隊 *使用* 球員。
類別圖符號 (Class Diagrams Notation)
你必須熟悉基本的 UML(統一塑模語言)符號來呈現這些關係:
- 繼承:以實線表示,箭頭為空心三角形,指向從子類別到基底類別。
- 關聯:以兩類別之間的實線表示,通常會加上標籤以描述關係。
- 類別圖中的存取修飾詞:
- + (Public / 公有)
- - (Private / 私有)
- # (Protected / 受保護)
4. 進階程式設計技巧 (3.9.4)
4.1 檔案處理 (文字檔) (3.9.4.1)
在「進階程式設計」部分,你需要知道如何透過讀取和寫入文字檔 (text files) 來與電腦的永久儲存設備進行互動。
- 寫入 (Writing):開啟檔案,逐行將資料(字串)傳送給它,並關閉檔案以永久儲存變更。
- 讀取 (Reading):開啟檔案,順序地從中檢索資料(字串),並關閉檔案。
文字檔至關重要,因為它們允許程式儲存配置設定、使用者輸入或結果,這些資料在程式停止執行後仍需保留。
4.2 遞迴 (呼叫自身的副程式) (3.9.4.2)
遞迴副程式 (recursive subroutine) 是指為了解決問題而呼叫自身的函式或程序。它是一種強大的工具,常用於可以分解為相同、較小版本的問題,例如計算階乘 (factorial) 或走訪樹狀結構。
為了防止遞迴副程式永遠執行下去(無限迴圈,導致堆疊溢位錯誤),每個遞迴函式都必須具備兩個關鍵組件:
1. 基礎案例 (Base Case)
基礎案例 (Base Case) 是停止條件。它是副程式不再呼叫自身的條件。當達到此情況時,函式會回傳一個結果,遞迴過程便會開始展開。
- 如果你忘記了基礎案例,你的程式就會崩潰!
2. 遞迴案例 (Recursive Case)
遞迴案例 (Recursive Case) 是副程式呼叫自身的部分,通常使用較小的輸入,使問題更接近基礎案例。
逐步範例:計算階乘 (n!)
階乘定義為 \(n! = n \times (n-1) \times (n-2) \times \dots \times 1\)。
讓我們定義一個遞迴函式 Factorial(n):
- 基礎案例: 若 \(n = 0\),回傳 1。(0! 定義為 1。)
- 遞迴案例: 若 \(n > 0\),回傳 \(n \times \text{Factorial}(n-1)\)。
追蹤 Factorial(4):
Factorial(4) 呼叫 4 * Factorial(3)
↳ Factorial(3) 呼叫 3 * Factorial(2)
↳ ↳ Factorial(2) 呼叫 2 * Factorial(1)
↳ ↳ ↳ Factorial(1) 呼叫 1 * Factorial(0)
↳ ↳ ↳ ↳ Factorial(0) 觸及 基礎案例,回傳 1。
↳ ↳ ↳ 回傳 1 * 1 = 1
↳ ↳ 回傳 2 * 1 = 2
↳ 回傳 3 * 2 = 6
↳ 回傳 4 * 6 = 24
最終結果為 24。
追蹤遞迴時,請記住流程:
1. Start(開始):呼叫函式。
2. Unwind(展開):持續呼叫(堆疊呼叫)直到達到基礎案例。
3. Return(回傳):一旦觸及基礎案例,將值層層回傳至堆疊頂端以獲得最終答案。
進階程式設計的重點總結
OOP 的概念——類別、物件、繼承與封裝——能幫助你寫出模組化、更容易除錯且可重用的程式碼。理解檔案處理能確保你的資料持久保存,而掌握遞迴則提供了一種優雅的方式來高效解決複雜且自我相似的問題。
繼續練習你的追蹤技巧,特別是遞迴和像實體化這種基本的 OOP 概念,你很快就能精通這一部分!