---
# System prepended metadata

title: '[Video Note] [OOP] freeCodeCamp.org - Intro to Object Oriented Programming - Crash Course'
tags: [OOP, Video Note]

---

# Introduction
## 物件導向程式設計簡介
![CleanShot 2024-09-19 at 14.41.40](https://hackmd.io/_uploads/rJb3DHFpC.png)


- 物件導向程式設計（OOP）是一種將資料和功能組合在一起的編程方法。
- OOP的四個主要原則是：封裝、抽象、繼承和多型。

## 基礎前提與對象
- OOP假設學習者已有基本的程式設計知識。
- 本課程將使用範例來解釋，但不要求特定程式語言的背景知識。

## 基本概念：物件與原始資料型別
![CleanShot 2024-09-19 at 14.42.08](https://hackmd.io/_uploads/S1A6PHYTA.png)
![CleanShot 2024-09-19 at 14.42.19](https://hackmd.io/_uploads/HJdRDSKpA.png)
![CleanShot 2024-09-19 at 14.42.46](https://hackmd.io/_uploads/rJQgdSY6C.png)

- 原始資料型別：儲存單一、簡單值的變數，如 `byte`、`int`、`float`、`boolean` 等。
- 隨著程式變得複雜，單純使用原始資料型別變得不夠用。

## 為何需要物件？
![CleanShot 2024-09-19 at 14.43.24](https://hackmd.io/_uploads/rkPMOHY6C.png)

- 複雜程式需要將相關變數進行分組。例如程式設計一個西洋棋遊戲時，騎士需要有位置、是否被捕獲、顏色等變數。
- 分組變數可讓開發者更容易處理像棋盤上的騎士等複雜的資料結構。

## 結構體的出現
![CleanShot 2024-09-19 at 14.44.05](https://hackmd.io/_uploads/HySr_rFaA.png)
![CleanShot 2024-09-19 at 14.44.16](https://hackmd.io/_uploads/BJQIuHKTC.png)
![CleanShot 2024-09-19 at 14.44.39](https://hackmd.io/_uploads/rkBuuHtTC.png)
![CleanShot 2024-09-19 at 14.45.19](https://hackmd.io/_uploads/SkTKuHYp0.png)
![CleanShot 2024-09-19 at 14.46.19](https://hackmd.io/_uploads/Hyy0urtpR.png)

- C 語言中的 `struct` 提供了將不同型別資料分組的方式，這比只能儲存同類型資料的陣列更靈活。
- 結構體允許將不同資料型別（例如 `int` 和 `string`）儲存在一起，甚至可以儲存其他結構體。

## 結構體的限制與物件的誕生
![CleanShot 2024-09-19 at 14.46.36](https://hackmd.io/_uploads/r1uR_rtpA.png)


- 結構體無法定義函數，這是物件導向程式設計解決的問題之一。
- 物件不僅能儲存資料，還能定義和儲存函數。

## 什麼是物件與類別？
![CleanShot 2024-09-19 at 14.46.50](https://hackmd.io/_uploads/SyvyFSKpC.png)
![CleanShot 2024-09-19 at 14.48.48](https://hackmd.io/_uploads/SysLtHYTC.png)
![CleanShot 2024-09-19 at 14.48.54](https://hackmd.io/_uploads/SkGDYSKTR.png)

- 物件是類別的實例。
- 類別是物件的模板，定義了物件應具有的屬性（變數）和行為（方法）。

## 類別與物件的區別
![CleanShot 2024-09-19 at 14.47.24](https://hackmd.io/_uploads/Bk5ZFBY60.png)

- 類別定義通用的資料和方法，例如西洋棋的騎士類別定義了所有騎士的移動方式。
- 物件則是具體的實例，例如每個棋盤上的騎士，它們有不同的具體屬性（位置、顏色等）。
![CleanShot 2024-09-19 at 14.47.33](https://hackmd.io/_uploads/S1eGFBF6A.png)

## 四大原則介紹
![CleanShot 2024-09-19 at 14.49.17](https://hackmd.io/_uploads/ry3utrYaR.png)

- 封裝：將資料和行為封裝在一起，限制外部直接訪問。
- 抽象：隱藏複雜的細節，只對外公開必要的資訊。
- 繼承：子類別可以繼承父類別的屬性和方法，減少重複代碼。
- 多型：允許同一方法在不同物件上有不同的實現方式。
# Encapsulation


## 封裝的基本概念
![CleanShot 2024-09-19 at 14.50.08](https://hackmd.io/_uploads/H1XhKHFTC.png)

- 封裝是將資料和操作該資料的方法打包在同一類別中。
- 核心理念是隱藏資料，外部無法直接訪問，只能通過類別的方法來互動。
![CleanShot 2024-09-19 at 14.50.33](https://hackmd.io/_uploads/B18pKSY6A.png)
![CleanShot 2024-09-19 at 14.50.40](https://hackmd.io/_uploads/SykRtBta0.png)

## Getter 與 Setter 方法
![CleanShot 2024-09-19 at 14.50.47](https://hackmd.io/_uploads/B1VCtBK6A.png)

- `Getter` 方法：用來從物件中取得資訊，如 `piece.getColor()` 返回棋子的顏色。
![CleanShot 2024-09-19 at 14.50.58](https://hackmd.io/_uploads/BybJ5SYa0.png)
- `Setter` 方法：用來修改物件屬性，通常會進行資料驗證，例如設置血量時，確保 `currentHealth` 不超過 `maxHealth`。
![CleanShot 2024-09-19 at 14.51.10](https://hackmd.io/_uploads/B15JcSFaA.png)
![CleanShot 2024-09-19 at 14.52.10](https://hackmd.io/_uploads/H1L7cBKaR.png)
![CleanShot 2024-09-19 at 14.52.15](https://hackmd.io/_uploads/HJcQ5BY6A.png)
![CleanShot 2024-09-19 at 14.52.23](https://hackmd.io/_uploads/ByjN9rFp0.png)


## 只讀屬性
- 一些屬性可以僅用 `Getter` 方法，避免外部類別直接修改。
![CleanShot 2024-09-19 at 14.53.08](https://hackmd.io/_uploads/rkMvcrF6A.png)

- 例如棋子的位置信息，應通過 `move()` 方法來變更，而不是直接修改 `rank` 和 `file`。
![CleanShot 2024-09-19 at 14.53.20](https://hackmd.io/_uploads/B1J_cBK6A.png)
![CleanShot 2024-09-19 at 14.53.43](https://hackmd.io/_uploads/ByQFcHYaR.png)

## 驗證與狀態控制
- 在 `move()` 方法中，可進行移動合法性檢查，如目標位置是否超出棋盤，或是否會讓國王被將軍。
- 封裝允許方法內部調用其他方法，如捕獲敵棋或將敵方國王置於將軍狀態。

## 避免非法操作
- 防止外部直接修改屬性，可以避免違規的操作發生，如兩個棋子佔據同一格。
- 封裝確保程式在合法狀態下運行，防止出現無法預期的錯誤情況。

## 控制程式複雜度
![CleanShot 2024-09-19 at 14.54.23](https://hackmd.io/_uploads/r1k39rtaR.png)
![CleanShot 2024-09-19 at 14.54.37](https://hackmd.io/_uploads/B1q3cHK60.png)
![CleanShot 2024-09-19 at 14.54.50](https://hackmd.io/_uploads/ByBTqrFaR.png)

- 在大型程式中，封裝有助於避免不同程式片段之間相互依賴，減少代碼相互糾纏。
- 封裝通過資訊隱藏來維護程式的可控性，降低整體複雜度。
# Abstraction
## 抽象化的基本概念
![CleanShot 2024-09-19 at 14.55.00](https://hackmd.io/_uploads/SyZ0cHYa0.png)
![CleanShot 2024-09-19 at 14.55.12](https://hackmd.io/_uploads/HJgkirYa0.png)

- 抽象化是指只顯示必要的細節，隱藏其他不重要的內部細節。
- 在日常生活中，例如開車時，只需了解如何操作方向盤和油門/煞車即可，不需了解車輛內部如何工作。

## 抽象化在程式設計中的應用
![CleanShot 2024-09-19 at 14.55.25](https://hackmd.io/_uploads/ryO1sBF6A.png)

- 類別應像汽車一樣，提供操作的方法，隱藏內部的具體實現。
- 使用者只需關心如何使用類別提供的接口，而不必了解其內部細節。
![CleanShot 2024-09-19 at 14.55.32](https://hackmd.io/_uploads/SkMejSFaR.png)
## 類別接口與實現

- **接口（Interface）**：類別與類別之間如何溝通，通常透過公開的方法來實現。
- **實現（Implementation）**：方法的具體實現細節，應隱藏在類別內部。

## 增量開發與團隊協作
- 抽象化有助於分段處理大型程式，集中於每個類別的功能而非整體系統。
- 在團隊合作中，協作程式員應依據預先定義的接口來工作，而無需了解其他成員的實現細節。

## 舉例：西洋棋中的抽象化
- 當你在處理騎士類別時，應使用國王類別提供的接口來檢查國王是否被將軍，而不是了解國王如何實現這一功能。
![CleanShot 2024-09-19 at 15.05.17](https://hackmd.io/_uploads/S1pV6BYpA.png)
![CleanShot 2024-09-19 at 15.05.28](https://hackmd.io/_uploads/SyrHpHYT0.png)

- 這樣的抽象化防止了不同類別之間的緊耦合，使得修改一個類別時，不會影響其他依賴於該類別的部分。
![CleanShot 2024-09-19 at 15.05.36](https://hackmd.io/_uploads/Sk-86StpC.png)

## 抽象化的優點
![CleanShot 2024-09-19 at 15.05.45](https://hackmd.io/_uploads/SJLUarY6A.png)

- 減少類別間的依賴，防止程序變得複雜且難以維護。
- 使得各部分可以獨立開發和測試，便於增量式開發和維護。
# Inheritance
## 繼承的基本概念
- 繼承是物件導向程式設計的原則之一，允許從其他類別派生新的類別。
- 派生的類別（子類別）可以繼承基類（父類別）的屬性和方法。

## 繼承的範例
- **武器類別（Weapon）**：包含所有武器共有的屬性和方法，例如傷害值和處理傷害的方法。
- **劍類別（Sword）** 和 **棍棒類別（Club）**：繼承自武器類別，具有各自獨特的屬性和行為，如劍適合切割，棍棒則為鈍器。
- 在這個例子中，武器類別是超類別（Superclass），而劍類別和棍棒類別是子類別（Subclasses）。

## 類別層次結構
- 類別層次結構可能有多層，並不僅限於一個超類別和幾個子類別。
- 武器類別可能是更廣泛的物品類別（Items）的子類別，物品類別下還可能有其他子類別。

## 訪問修飾符
- **公共（Public）**：
  - 公共成員可以從任何地方訪問，包括超類別、子類別和程序中的其他地方。
  - 用於需要被廣泛訪問的情況。
- **私有（Private）**：
  - 私有成員僅能在定義該成員的類別內部訪問。
  - 用於不希望外部訪問的資料，可以在不同類別中使用相同名稱的私有成員而不會發生衝突。
- **保護（Protected）**：
  - 保護成員可以在定義該成員的類別及其子類別中訪問。
  - 用於需要在類別層次結構內部使用的情況，避免外部類別直接訪問。

## 繼承與訪問修飾符的應用
- 在設計類別時，根據需求選擇合適的訪問修飾符以控制成員的可見性。
- 繼承允許子類別重用和擴展父類別的功能，並且訪問修飾符確保資料的封裝和安全性。
# Polymorphism
## 動態多型 (Dynamic Polymorphism)
- 動態多型發生在程式執行時 (run time)。
- 方法在子類別與父類別中有相同的方法名稱與參數，但具不同的實作。
- 子類別的實作會覆蓋父類別的實作。
- 以「車輛」為例，`Car` 類別與其子類別 `SportsCar` 都有 `drive` 方法：
  - `Car` 的 `drive` 方法每英里消耗 0.04 加侖油。
  - `SportsCar` 的 `drive` 方法每英里消耗 0.02 加侖油。
- 當呼叫子類別 `SportsCar` 的 `drive` 方法時，會執行子類別的實作，而非父類別的實作。
- 動態多型允許撰寫通用的父類別方法，而不需要使用條件判斷來處理不同的子類別。

## 靜態多型 (Static Polymorphism)
- 靜態多型發生在編譯時 (compile time)。
- 方法名稱相同，但參數數量、類型或順序不同，這稱為方法多載 (method overloading)。
- 例如在 `Car` 類別中，有三個 `drive` 方法：
  - 方法一：接受一個整數與一個字串參數（如速度與目的地）。
  - 方法二：接受兩個整數參數（如距離與速度）。
  - 方法三：接受一個字串與一個整數參數（如目的地與速度，順序不同於方法一）。
- 根據傳入的參數類型或順序，編譯器會決定要執行哪一個方法。
- 方法多載的好處是可以使用相同名稱來實現不同的功能，但必須小心參數的順序與類型，以避免呼叫錯誤的實作。

## 多型的注意事項
- 多型允許方法在不同的類別中以相同名稱但不同形式存在。
- 動態多型使得程式在執行時可以根據物件的實際類型來決定要呼叫的實作。
- 靜態多型使得方法可以根據不同的參數形式在編譯時進行區分。
- 使用多型時需小心參數的正確性，以確保程式執行符合預期。
# Terminology
- **物件導向程式設計 (OOP)**：一種程式設計範式，將資料和行為封裝在物件中，使程式更具結構性和模組化。
- **物件 (Object)**：一個類別的實例，包含變數（屬性）與函式（方法）。
- **類別 (Class)**：物件的模板，定義物件的屬性和行為，但不初始化具體數值。
- **原始資料型別 (Primitive Data Types)**：儲存單一簡單數值的變數，如 byte、int、float、double、boolean 和 char。
- **結構 (Struct)**：允許儲存不同型別的資料，早期程式設計中類似陣列但可包含多種型別。
- **陣列 (Array)**：一個儲存同一型別資料的集合，所有元素的型別相同。
- **函式 (Function)**：執行特定任務的程式碼區塊，可在類別中定義和儲存。
- **變數 (Variable)**：儲存資料的容器，在程式中會隨需求而變。
- **屬性 (Attribute)**：物件或類別中儲存資料的變數。
- **方法 (Method)**：物件中用來處理屬性或執行行為的函式。
- **位置變數 (Position Variable)**：儲存物件在某一空間中的位置，常見於遊戲程式中。
- **布林值 (Boolean)**：只有兩個值的資料型別：true 或 false。
- **初始值 (Initialization)**：物件或變數的初始狀態或數值設定。
- **模版 (Template)**：提供基本結構的程式碼範本，用以建立具體的物件。
- **物件初始化 (Object Initialization)**：創建物件時為其屬性設置具體的數值。
- **封裝 (Encapsulation)**：將資料與其相關的行為封裝成一個單一的實體，使其在外部無法直接存取。
- **抽象 (Abstraction)**：隱藏內部細節，只呈現必須的功能，讓使用者能專注於高層次的操作。
- **繼承 (Inheritance)**：允許類別從現有的類別中繼承屬性和方法，減少重複程式碼。
- **多型 (Polymorphism)**：同一個函式或方法可以根據不同的物件型別表現出不同的行為。
- **封裝 (Encapsulation)**：將資料與操作該資料的方法封裝在類別內，避免外部直接修改資料。
- **資料隱藏 (Data Hiding)**：隱藏類別內部的資料，使外部無法直接存取，僅透過方法來操作資料。
- **存取方法 (Getter Method)**：允許外部讀取物件屬性的方法，提供資料但不允許修改。
- **設置方法 (Setter Method)**：允許外部修改物件屬性的方法，通常附帶邏輯驗證以確保資料有效性。
- **顏色檢查 (Color Check)**：在程式中檢查棋子的顏色，以確定是否能進行捕捉等操作。
- **驗證 (Validation)**：設置方法時，加入邏輯檢查以確保屬性的變更不會導致錯誤或非法狀態。
- **讀取專屬屬性 (Read-only Attribute)**：僅允許讀取而不允許修改的屬性，通常只定義存取方法，不定義設置方法。
- **位置檢查 (Position Check)**：在移動棋子時檢查其新位置是否合法，防止非法移動。
- **方法鏈結 (Method Chaining)**：在一個方法內調用其他方法，以完成多步操作。
- **最大生命值 (Max Health)**：遊戲角色中用來儲存角色最大生命值的屬性，隨角色升級而增加。
- **當前生命值 (Current Health)**：角色的當前生命值，可能隨戰鬥或治療變動。
- **非法狀態 (Invalid State)**：程式執行時出現不符合邏輯的狀態，例如兩個棋子占同一個位置。
- **狀態控制 (State Control)**：使用封裝來限制物件屬性的變更，以避免程式進入非法狀態。
- **複雜度管理 (Complexity Management)**：透過封裝降低程式的相互依賴，減少程式的複雜度。
- **信息隱藏 (Information Hiding)**：防止外部類別直接存取內部資料，從而保持程式的模組化。
- **類別相互依賴 (Class Dependency)**：一個類別過度依賴於其他類別，導致程式耦合度高，難以維護。
- **非直接存取 (Indirect Access)**：透過方法來操作物件屬性，而不是直接修改其值。
- **狀態驗證 (State Validation)**：在變更屬性之前檢查其新值是否有效，以防程式進入無效狀態。
- **方法控制 (Method Control)**：通過方法來控制物件的行為，防止不合理的操作
- **抽象化**：只顯示必要的細節，隱藏不必要的實作細節。
- **物件導向**：程式設計中的主要概念之一，將程式分割為多個物件。
- **封裝**：將資料和方法包裝在同一個類別內，並透過介面進行互動。
- **介面**：類別之間溝通的方式，通常透過公開的方法來實現。
- **實作（Implementation）**：類別內部的運作邏輯，外部無法直接存取。
- **getter方法**：用來取得類別內部變數值的方法。
- **方法**：類別中的函式，用來執行特定操作。
- **類別**：物件導向中的基本單位，包含資料和方法。
- **資料封裝**：保護資料不被外部直接存取，需透過方法來操作。
- **依賴性（Coupling）**：當類別之間彼此依賴過多，會造成維護困難。
- **變數命名**：程式中的資料識別符號，應遵循一致的命名規則。
- **重構（Refactoring）**：改變程式結構而不影響其行為的過程。
- **方法調用**：使用某個類別的方法來執行操作。
- **程式模組化**：將程式分割成較小的、可獨立工作的單位。
- **增量開發**：分步驟逐步開發與測試程式的策略。
- **可測性**：確保程式中的各個部分能獨立測試。
- **系統複雜性**：程式隨著功能增加，會變得更難理解和維護。
- **責任分離**：每個類別應該只負責處理特定任務。
- **程式維護**：保持程式可讀性和可修改性的過程。
- **方法覆寫**：子類別重新定義父類別的方法以實現不同行為。
- **界面與實作分離**：將外部與內部的功能區分，僅暴露必要的功能。
- **繼承**：允許從其他類別派生出新類別，新類別可繼承舊類別的屬性和方法。
- **超類別（Superclass）**：被繼承的類別，也稱為基底類別。
- **子類別（Subclass）**：從超類別派生出的類別，也稱為衍生類別。
- **類別層級結構**：顯示類別之間的繼承關係，形成一個層級網絡。
- **屬性**：類別中的變數，用來儲存對象的狀態。
- **方法**：類別中的函數，用來執行特定操作。
- **武器類（Weapon Class）**：包含所有武器共有的屬性和方法，例如傷害值。
- **劍類（Sword Class）**：繼承自武器類，擁有劍特有的屬性和方法。
- **棍棒類（Club Class）**：繼承自武器類，擁有棍棒特有的屬性和方法。
- **類別層級**：超類別與其子類別之間的繼承關係層級。
- **類別繼承**：使得子類別可以使用超類別的屬性和方法。
- **多層繼承**：類別層級結構中的多個超類別和子類別。
- **訪問修飾符（Access Modifiers）**：控制哪些類別可以訪問屬性和方法。
- **公開修飾符（Public Modifier）**：可從任何地方訪問，包括超類別、子類別及其他地方。
- **私有修飾符（Private Modifier）**：僅能在定義該成員的類別內部訪問。
- **保護修飾符（Protected Modifier）**：可以在定義該成員的類別及其子類別中訪問。
- **私有成員**：僅在定義它的類別內部可見和可用。
- **保護成員**：在類別及其子類別中可見和可用，但在外部不可見。
- **方法覆寫**：子類別重新定義超類別的方法以實現不同的行為。
- **屬性重用**：子類別可以重用超類別的屬性和方法。
- **層級關係圖**：視覺化展示類別間的繼承關係。
- **多型（Polymorphism）**：允許方法具有多種形式，根據上下文使用不同的實現。
- **動態多型（Dynamic Polymorphism）**：運行時發生，子類覆寫父類的相同方法簽名。
- **靜態多型（Static Polymorphism）**：編譯時發生，通過參數類型或數量區分相同方法名的方法（方法重載）。
- **子類（Subclass）**：繼承父類並擁有自己的實現。
- **父類（Superclass）**：子類繼承的類別，通常包含基本功能。
- **方法簽名（Method Signature）**：方法的名稱及其參數組合，區分不同的方法。
- **覆寫（Override）**：子類重新實現父類中已有的方法。
- **方法重載（Method Overloading）**：在同一類別中定義多個同名但參數不同的方法。
- **運行時（Runtime）**：程式執行的階段，動態多型在此發生。
- **編譯時（Compile Time）**：程式編譯的階段，靜態多型在此發生。
- **參數（Parameter）**：傳遞給方法的變量，決定方法的輸入。
- **繼承（Inheritance）**：子類繼承父類的屬性和方法。
- **類層次結構（Class Hierarchy）**：類別之間的繼承關係。
- **實例（Instance）**：類別的具體對象。
- **.drive方法（.drive Method）**：範例中的方法，用來模擬車輛駕駛行為。
- **加侖（Gallon）**：範例中車輛消耗的燃油單位。
- **數字參數（Numeric Parameter）**：方法中接受的數值型參數，如速度或距離。
- **字串參數（String Parameter）**：方法中接受的字串型參數，如目的地。
- **不同類型的參數（Different Parameter Types）**：用來區分方法重載的依據，如整數和字串。
- **參數順序（Parameter Order）**：同名方法的參數順序不同，屬於方法重載的一部分。