封裝(Encapsulation)是物件導向程式設計(OOP)的核心原則之一,將類別內部的資料(屬性)與操作方法綁定在一起,並透過存取控制隱藏實作細節,只暴露必要介面給外部使用。它就像膠囊藥丸,外層保護內部成分,防止外部直接干涉,同時確保資料安全與程式模組化,提高程式碼的可維護性與可靠性。
封裝的基本概念與目的
封裝透過「資料隱藏」實現,將類別內部狀態限制為私有,外部只能透過公開方法(如 Getter/Setter)存取。這避免無效輸入、意外修改,並將實作細節抽象化,讓使用者無需了解內部邏輯即可操作物件。主要目的包括保護資料完整性、促進鬆散耦合,以及簡化介面設計。
例如,銀行帳戶類別不允許直接修改餘額(防止負值),而須透過 deposit()、withdraw() 方法驗證後操作。
存取修飾符與實現機制
封裝依賴語言提供的存取控制:
-
公開(Public):外部可存取,如
public int balance;。 -
私有(Private):僅類別內部存取,如
private int _balance;。 -
受保護(Protected):子類別可存取,用於繼承。
-
預設(Default/Package):同包內存取。
Getter/Setter 範例(Java):
public class BankAccount {
private double balance; // 私有屬性
public double getBalance() { // Getter
return balance;
}
public void deposit(double amount) { // Setter with validation
if (amount > 0) balance += amount;
}
}
外部呼叫:account.deposit(100);,無法直接 account.balance = -50;。
封裝在不同語言的語法
| 語言 | 私有語法 | Getter/Setter 範例 |
|---|---|---|
| Java | private |
getX() / setX() |
| Python | _x 或 __x |
@property 裝飾器 |
| C# | private |
自動屬性 {get; set;} |
| JS | 慣例 _x |
#privateField (Private Fields) |
Python 使用 @property 模擬:
class Circle:
def __init__(self, radius):
self._radius = radius # 私有慣例
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value >= 0:
self._radius = value
封裝與 OOP 其他特性的結合
-
與繼承:子類可存取 protected 成員,但無法碰私有部分,維持父類穩定。
-
與多型:公開介面一致,內部實作可變。
-
抽象:進一步隱藏細節,僅定義合約。
實際應用如框架設計:使用者呼叫 user.save(),無需知曉是否存 SQL 或 NoSQL。
封裝的優點與實際範例
優點:
-
資料保護:驗證輸入,防止無效狀態。
-
易維護:內部變更不影響外部(如改用快取)。
-
模組化:類別自給自足,降低耦合。
範例:購物車類別
class ShoppingCart:
def __init__(self):
self._items = {} # 隱藏內部結構
def add_item(self, name, price):
self._items[name] = price # 內部邏輯
def total(self):
return sum(self._items.values())
外部僅用 cart.add_item("蘋果", 50),不知內部用 dict 實作。
常見誤區與最佳實務
誤區:過度封裝(如全私有無介面)或無驗證 Setter。實務:
-
只暴露必要方法。
-
遵循最小驚喜原則(Least Surprise)。
-
使用不變性(Immutable)物件如 String。
-
避免大 Getter(洩漏內部狀態)。
封裝是 OOP 入門基石,讓程式如黑盒子般可靠。結合繼承與多型,形成強健架構,從簡單類別到企業系統皆適用。