🧩 適配器(Adapter)
· 3 min read
🔹 Adapter Pattern 是什麼?
Adapter(適配器模式)屬於 結構型設計模式(Structural Pattern)。 它的目的是 將一個類的介面轉換成客戶端期望的另一個介面,讓原本不相容的類可以一起工作。
就像「轉接頭」的概念 —— 比如你的筆電只有 USB-C 插槽,但滑鼠是 USB-A 的,你就需要一個轉接器(Adapter)讓兩者可以相容。
🔹 使用情境
- 當 現有類別的介面不符合需求,但你又不能修改原有類(可能來自第三方套件或舊程式碼)。
- 當你要 整合新舊系統 時,Adapter 可以避免大規模修改。
- 適合 保持相容性,例如 API 版本轉換、跨平台封裝。
🔹 結構
Adapter 模式有三個主要角色:
-
Target(目標介面)
- 客戶端期望的介面。
-
Adaptee(被適配者)
- 已存在的類,功能完整,但介面不符合需求。
-
Adapter(適配器)
- 包裝 Adaptee,轉換成 Target 的介面。
🔹 UML 圖(簡化)
Client ---> Target <--- Adapter ---> Adaptee
🔹 範例(Swift / 物件導向語言)
情境:
你有一個舊系統類別 OldPrinter,只能用 printText(_:)。
新系統規範要使用 printMessage(_:)。
→ 這時候就可以用 Adapter。
// Target (客戶端期待的介面)
protocol Printer {
func printMessage(_ message: String)
}
// Adaptee (舊系統,不能改)
class OldPrinter {
func printText(_ text: String) {
print("Old Printer: \(text)")
}
}
// Adapter (轉換器)
class PrinterAdapter: Printer {
private let oldPrinter: OldPrinter
init(oldPrinter: OldPrinter) {
self.oldPrinter = oldPrinter
}
func printMessage(_ message: String) {
// 轉換介面
oldPrinter.printText(message)
}
}
// 使用
let oldPrinter = OldPrinter()
let adapter = PrinterAdapter(oldPrinter: oldPrinter)
// 客戶端用的還是新的介面
adapter.printMessage("Hello, Adapter Pattern!")
輸出結果:
Old Printer: Hello, Adapter Pattern!
🔹 生活中的例子
- 電源插頭轉接器(歐規 → 美規)
- Type-C 轉 Lightning 線
- 軟體 API Wrapper(舊版 API → 新版 API)
🔹 優缺點
✅ 優點
- 可以重用現有的類,無需修改原始碼。
- 提供相容性,幫助新舊程式共存。
- 符合 單一職責原則(SRP)與 開放封閉原則(OCP)。
⚠️ 缺點
- 增加了額外的層次,可能會稍微複雜。
- 如果濫用,會讓系統到處充滿「轉接器」,降低可維護性。
舉另外一個台灣和日本插座的例子:
// Target: 台灣插座需要 plugIn()
protocol TaiwanPlug {
func plugIn()
}
// Adaptee: 日本插頭,只能用 insert()
class JapanPlug {
func insert() {
print("🔌 日本插頭插入")
}
}
// Adapter: 把 insert() 轉換成 plugIn()
class PlugAdapter: TaiwanPlug {
private let japanPlug: JapanPlug
init(japanPlug: JapanPlug) {
self.japanPlug = japanPlug
}
func plugIn() {
// 轉換呼叫
japanPlug.insert()
}
}
// Client
let japanPlug = JapanPlug()
let adapter = PlugAdapter(japanPlug: japanPlug)
// 用戶只知道台灣的 plugIn()
adapter.plugIn()