借用terrylee的原話:
Adapter模式主要應用于“希望複用一些現存的類,但是接口又與複用環境要求不一緻的情況”,在遺留代碼複用、類庫遷移等方面非常有用。
擴充卡模式再次展現了“面向接口程式設計,而非面向實作程式設計”這一精神。
場景:
有一個基于資料庫的系統,裡面的資料庫操作就拿最常用的查詢來說,主要是用SqlHelper類裡的QueryData(string sql)這個方法來處理的,後來意外發現該方法實作上性能并不是最好(或者不能滿足新的需要),而這時正好有一個第三方的DbHelper程式集,寫得很成熟性能也不錯,但唯一不足的是裡面的查詢方法簽名是SelectData(string sql),怎麼辦?所有引用SqlHelper的地方全部修改,重頭編譯麼?No,沒人會想這樣
先看下原來的代碼:
using System;
using System.Data;
namespace Adapter
{
class Program
{
static void Main(string[] args)
{
IDBHelper dbhelper = new SqlHelper();
dbhelper.QueryData("Select * from TableA");
Console.ReadKey();
}
}
public interface IDBHelper
DataSet QueryData(string sql);
public class SqlHelper : IDBHelper
public DataSet QueryData(string sql)
Console.WriteLine("QueryData is Called,the sql is :\"{0}\"",sql);
return new DataSet();//這裡示範起見,就直接傳回一個DataSet執行個體完事 :)
}
如何在盡量不影響原有用戶端代碼的情況下,用新的DbHelper來取代舊的SqlHelper呢?
假如第三方的DBHelper結構如下:
/// <summary>
/// 第三方的新dbHelper,實際場景中,這個類通常都是封裝在程式集中以dll提供,用戶端程式無法修改
/// </summary>
public class DbHelper
public DataSet SelectData(string sql)
Console.WriteLine("SelectData is Called,the sql is :\"{0}\"", sql);
可以新增一個擴充卡:
/// <summary>
/// 新增的擴充卡
public class DBHelperAdapter : IDBHelper
private DbHelper _dbHelper;
public DBHelperAdapter(DbHelper dbHelper)
this._dbHelper = dbHelper;
public DataSet QueryData(string sql)
return _dbHelper.SelectData(sql);
這樣原有的用戶端程式,隻需要把
IDBHelper dbhelper = new SqlHelper();
改成:
IDBHelper dbhelper = new DBHelperAdapter(new DbHelper()); 就萬事大吉了,當然你可以用配置檔案+反射,完全解耦,此處略過
反思:
本例中之是以能輕易将新的類替換舊的類,主要得益于舊的代碼僅依賴于抽象(即接口IDBHelper),而非具體的實作(即類SqlHelper),否則也不可能達到最終效果。
OO原則中的"面對接口編碼","依賴倒置"的妙處也就在于此。
最後給出類圖: