當需要使用現有類別,但其介面不符合當前系統需求時,適配器模式提供標準解決方案:將一個類別的介面轉換成客戶端期望的另一個介面。適配器模式分為「類別適配器」(多重繼承/介面實作)與「物件適配器」(組合/委派)兩種形式。本文以訊息系統為例,展示如何將 SqlMessage(Get/Insert)適配為 IMessage(Select/Add),並完整對比兩種適配器實作優劣。
IMessage,客戶端期望介面(Select()、Add())。SqlMessage,現有類別(Get()、Insert())。Message : SqlMessage, IMessage,繼承 Adaptee + 實作 Target。Message2 : IMessage,組合 Adaptee 實例 + 實作 Target。IMessage 介面使用。
public interface IMessage
{
List<MessageModel> Select();
bool Add(MessageModel mm);
}
public class SqlMessage
{
public List<MessageModel> Get()
{
var l = new List<MessageModel>();
l.Add(new MessageModel("SQL方式獲取Message", DateTime.Now));
return l;
}
public bool Insert(MessageModel mm) { return true; }
}
public class Message : SqlMessage, IMessage
{
public List<MessageModel> Select() => base.Get(); // 轉發給繼承的 Get()
public bool Add(MessageModel mm) => base.Insert(mm); // 轉發給繼承的 Insert()
}
特點:
public class Message2 : IMessage
{
private SqlMessage _sqlMessage = new SqlMessage(); // 組合
public List<MessageModel> Select() => _sqlMessage.Get();
public bool Add(MessageModel mm) => _sqlMessage.Insert(mm);
}
特點:
IMessage m;
m = new Message(); // 類別適配器
Response.Write("類適配器方式");
Response.Write(m.Add(new MessageModel("插入", Now)));
Response.Write(m.Select()[0].Message);
m = new Message2(); // 物件適配器
Response.Write("對象適配器方式");
Response.Write(m.Add(new MessageModel("插入", Now)));
Response.Write(m.Select()[0].Message);
類適配器方式
True
SQL方式獲取Message 2007-4-8 20:59:29
對象適配器方式
True
SQL方式獲取Message 2007-4-8 20:59:29
兩種適配器對客戶端行為完全一致,驗證介面轉換正確。
| 維度 | 類別適配器 | 物件適配器 |
|---|---|---|
| 實現方式 | 繼承 Adaptee + 實作 Target | 組合 Adaptee + 實作 Target |
| 與 Adaptee 關係 | Is-A (繼承) | Has-A (組合) |
| 覆寫 Adaptee 行為 | 容易 (override virtual) | 困難 (需替換組合物件) |
| 適配 Adaptee 子類別 | 不可 (繼承固定) | 可 (多型注入) |
| 耦合度 | 較高 (繼承耦合) | 較低 (介面耦合) |
| 適用場景 | Adaptee 穩定、需擴展行為 | Adaptee 多變、需多型、現代首選 |
適配器同時實作 Target 與 Adaptee 介面,可在兩種系統中互相流通。
實作:class TwoWayAdapter : ITarget, IAdaptee { ... }
為介面提供空實作預設類別,子類別只需覆寫關心方法。
應用:MouseAdapter (滑鼠事件)、WindowAdapter (視窗事件) — Java Swing/AWT 經典。
SqlDataAdapter 適配 IDbDataAdapter,填充 DataSet。List<T> 實作 IList<T>、IReadOnlyList<T>,陣列適配 IList<T>。StreamReader 適配 TextReader 讀取 Stream。RCW (Runtime Callable Wrapper) 適配 COM 介面為 .NET 介面。UseMiddleware<T>() 適配自定義類別為 RequestDelegate。Adapter 結尾,職責單一(只做介面轉換,不加業務邏輯)。適配器模式以「介面轉換」消除「介面不兼容」障礙,讓既有資產在新架構中無縫復用。本範例完整展示了類別適配器(繼承)與物件適配器(組合)雙重實作,驗證了兩者對客戶端行為一致性,並深度對比了繼承與組合在適配場景下的優劣。實務中,從資料庫驅動、集合介面、流包裝到微服務網關轉換、第三方 SDK 整合、舊系統遷移包裝,適配器模式是系統整合、架構遷移、庫封裝的核心工具。掌握其兩種形式優劣、進階變體(雙向/預設)與現代最佳實務(組合優先、單一職責、文件化),能讓你在面對「介面不匹配、舊新共存、多庫整合」的系統挑戰時,從容設計出清晰邊界、低耦合、易演進的適配層架構。