適配器模式將一個類別的介面轉換成客戶端期望的另一個介面,使原本介面不兼容的類別能夠合作。別名:Wrapper(包裝器)。
機制: 透過繼承源類別,實作目標介面。
結構:
Target (介面)
↑ 實作
Adapter → 繼承 → Adaptee (源類別)
機制: 透過組合持有源物件參考,實作目標介面。
結構:
Target (介面)
↑ 實作
Adapter → 組合 → Adaptee (源類別)
古代坐騎只能 run(),現代坐騎需同時支援 run() 與 fly()。
// 目標介面:現代坐騎標準
public interface IModernMount {
void run();
void fly();
}
// 源類別:古代坐騎(只能跑)
public class AncientMount {
public void run() {
System.out.println("古代坐騎:在地上奔跑...");
}
}
/**
* 類別適配器:繼承 AncientMount,實作 IModernMount
* 優點:可覆寫源類別方法;缺點:Java 單繼承限制,無法適配多個源類別
*/
public class ClassAdapter extends AncientMount implements IModernMount {
@Override
public void fly() {
System.out.println("類別適配器:獲得飛行能力,騰空而起!");
}
// run() 直接繼承自 AncientMount,無需重寫
}
/**
* 物件適配器:組合 AncientMount,實作 IModernMount
* 優點:可適配多個源物件、無繼承限制、符合組合優於繼承原則
*/
public class ObjectAdapter implements IModernMount {
private AncientMount ancientMount; // 持有源物件參考
// 甚至可持有多個源物件
// private AnotherMount anotherMount;
public ObjectAdapter(AncientMount ancientMount) {
this.ancientMount = ancientMount;
}
@Override
public void run() {
// 委派給源物件
ancientMount.run();
}
@Override
public void fly() {
System.out.println("物件適配器:施展飛行術,翱翔天際!");
}
}
public class AdapterDemo {
public static void main(String[] args) {
System.out.println("=== 類別適配器 ===");
IModernMount classAdapter = new ClassAdapter();
classAdapter.run(); // 繼承自 AncientMount
classAdapter.fly(); // 適配器新增
System.out.println("\n=== 物件適配器 ===");
AncientMount ancient = new AncientMount();
IModernMount objectAdapter = new ObjectAdapter(ancient);
objectAdapter.run(); // 委派給 ancient
objectAdapter.fly(); // 適配器新增
}
}
=== 類別適配器 ===
古代坐騎:在地上奔跑...
類別適配器:獲得飛行能力,騰空而起!
=== 物件適配器 ===
古代坐騎:在地上奔跑...
物件適配器:施展飛行術,翱翔天際!
| 維度 | 類別適配器 | 物件適配器 |
|---|---|---|
| 實作關係 | 繼承 | 組合/委派 |
| 適配多個源 | 不可(單繼承) | 可(持有多個參考) |
| 覆寫源行為 | 容易(Override) | 需重新實作或包裝 |
| 靈活度 | 低(編譯期綁定) | 高(執行期可切換源物件) |
| 符合設計原則 | 違反「組合優於繼承」 | 符合 |
| 適用場景 | 源類別固定、需大量覆寫 | 源類別多變、需執行期切換 |
同時實作源介面與目標介面,可在兩種系統中互通:
public class TwoWayAdapter extends AncientMount implements IModernMount, IAncientMount {
// 同時是古代坐騎也是現代坐騎
}
提供介面的空實作,子類別只需覆寫需要的方法:
public abstract class MountAdapter implements IModernMount {
public void run() { /* 預設實作 */ }
public void fly() { /* 預設實作 */ }
}
// 使用時只覆寫 fly()
public class FlyOnlyAdapter extends MountAdapter {
@Override public void fly() { /* 真實飛行邏輯 */ }
}
多層適配,逐步轉換介面:
// LegacySystem → Adapter1 → Adapter2 → ModernSystem
// 系統需求:ILogger
// 第三方:Log4jLogger, Slf4jLogger, JULLogger
public class Log4jAdapter implements ILogger {
private Logger log4jLogger;
public void log(String msg) { log4jLogger.info(msg); }
}
// JDBC 本身就是適配器模式
// java.sql.Connection (Target) ← 各廠商驅動實作
// OracleConnection, MySQLConnection, PostgreSQLConnection (Adaptee)
// Arrays.asList() 將陣列適配為 List
List list = Arrays.asList("a", "b", "c");
// Collections.list() 將 Enumeration 適配為 Collection
// Controller (Adaptee) → HandlerAdapter (Adapter) → DispatcherServlet (Client)
// SimpleControllerHandlerAdapter, HttpRequestHandlerAdapter, RequestMappingHandlerAdapter
XXXAdapter,明確表達意圖適配器模式是結構型模式中的實用主力,透過介面轉換解決不兼容問題。理解類別與物件適配器的差異、掌握委派與繼承的權衡、識別適用場景,能有效整合舊系統、第三方庫與新架構,實現平滑演進。