把一個既有類別「不相容的介面」包成 client 期望的介面,讓兩邊在不改原始碼的前提下接得起來。重點是轉換介面,不是加強行為。
🧠 When to Use
TIP
訊號:你手上有個好用的類別(常是第三方或 legacy),但它的方法名 / 簽章跟你的程式期望的介面對不上。
- 想重用既有類別,但它的介面跟你的 client 不相容。
- 要整合無法修改的第三方 / legacy 程式碼。
- 想為多個來源(不同 SDK)提供一致的對外介面。
⚖️ Structure & Variants
Object Adapter — 用組合包裝(首選)
// client 期望的目標介面
interface PaymentGateway { fun pay(cents: Int): Boolean }
// 第三方類別,介面不相容、無法修改
class StripeSdk { fun charge(dollars: Double, currency: String): Stripe.Result { /* ... */ } }
// Adapter 持有 adaptee,做介面與單位的轉換
class StripeAdapter(private val stripe: StripeSdk) : PaymentGateway {
override fun pay(cents: Int): Boolean =
stripe.charge(cents / 100.0, "USD").isSuccess
}
val gateway: PaymentGateway = StripeAdapter(StripeSdk())- 用組合持有 adaptee,彈性高、能同時轉接多個物件。
Class Adapter — 用繼承
- 直接繼承 adaptee(多重繼承的語言)或實作其介面,覆寫成目標介面。
- Kotlin / Java 單繼承下較受限;綁死特定 adaptee 類別,無法在執行期替換。
- 一般偏好 object adapter,因為它符合組合優於繼承。
和 Decorator / Facade 的差別
- Adapter:改變介面,把 A 轉成 B,目的是相容,通常一對一。
- Decorator:介面不變,加強行為,可疊加。
- Facade:對一整組子系統提供新的簡化入口,不是一對一轉接。
⚠️ Misuse & Anti-patterns
- 在 Adapter 裡塞商業邏輯:它應只做介面 / 格式轉換;摻入邏輯會讓它變成難測的灰色地帶。
- 明明能改原類別卻硬包一層:若 adaptee 是自家可改的程式,直接讓它實作目標介面更乾淨。
- 誤當 Facade 用:要簡化的是「一堆子系統」而非「轉一個介面」時,你要的是 Facade。
🔑 Takeaways
- 解決的是「介面不相容」:讓既有 / 第三方類別接上 client 期望的介面。
- Object adapter(組合)優先於 class adapter(繼承),彈性與可替換性都更好。
- 和 Decorator、Facade 都是「包一層」,Adapter 的關鍵意圖是轉介面。
No notes yet — jot your takeaways or Q&A here.