Skip to main content

🧩 適配器(Adapter)

· 3 min read

🔹 Adapter Pattern 是什麼?

Adapter(適配器模式)屬於 結構型設計模式(Structural Pattern)。 它的目的是 將一個類的介面轉換成客戶端期望的另一個介面,讓原本不相容的類可以一起工作。

就像「轉接頭」的概念 —— 比如你的筆電只有 USB-C 插槽,但滑鼠是 USB-A 的,你就需要一個轉接器(Adapter)讓兩者可以相容。

🔹 使用情境

  • 現有類別的介面不符合需求,但你又不能修改原有類(可能來自第三方套件或舊程式碼)。
  • 當你要 整合新舊系統 時,Adapter 可以避免大規模修改。
  • 適合 保持相容性,例如 API 版本轉換、跨平台封裝。

🔹 結構

Adapter 模式有三個主要角色:

  1. Target(目標介面)

    • 客戶端期望的介面。
  2. Adaptee(被適配者)

    • 已存在的類,功能完整,但介面不符合需求。
  3. 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()