1、概要
適配:即在不改變原有實現的基礎上,將原先不適合的接口轉換成適合的接口.
what is Apater?適配,這個概念在生活中無處不在,比如你的iphone 4手機充電器壞了,這是時候只有一個iphone 8的充電器,兩個充電器的頭並不匹配,這個時候,你就需要一個充電器適配器.這個適配器將8的充電器轉換成能支持4充電的充電器接口.這個例子在不改變8的充電器原有功能的情況下,將8不適合4的接口通過適配器轉變成合適的接口.等等例子還有很多.
2、動機
在軟件開發的過程中,常常需要將一些"現存的對象"放到新的環境中去,但是新的環境接口,這些對象並不滿足.如何解決這種"遷移的變化",就是適配器模式要解決的問題.
3、意圖
將已經穩定的一個類的接口轉換成客戶需要的接口,Apater模式使用原本由於接口不兼容的而不能一起工作的接口能一起工作.
4、代碼實例-對象適配器
現在客戶系統在實現一個功能的時候只需要ArrayList的部分功能,需要的功能通過ICustomerReqiured接口定義.這個時候.用適配器模式能很好的解決這個問題!
/// <summary> /// 客戶要求的接口 /// </summary> public interface ICustomerRequired { void Push(object item); object Pop(); object Peek(); } /// <summary> /// 對象適配器 /// 對象適配器,Apater創建了一個ArrayList的包裝器,縮小了ArrayList的接口範圍,如果有特殊的業務需要使用ArrayList的部分方法,可以使用該模式 /// </summary> public class Apater : ICustomerRequired { private ArrayList _apatee;//需要被適配的對象,也是存在的穩定的對象 public Apater(ArrayList arrayList) { _apatee = arrayList; } /// <summary> /// 返回最後一項 /// </summary> /// <returns></returns> public object Peek() { if (_apatee.Count >= 1) return _apatee[_apatee.Count - 1]; return null; } /// <summary> /// 移除最後一項,返回最後一項 /// </summary> /// <returns></returns> public object Pop() { _apatee.RemoveAt(_apatee.Count - 1); return Peek(); } /// <summary> /// 添加一項 /// </summary> /// <param name="item"></param> public void Push(object item) { _apatee.Add(item); } }
當然,失配器遠比上面代碼所展示的功能要強,不僅僅支持縮小限制ArrayList的功能,也能擴展、修改組合ArrayList的功能.
5、代碼實例-類適配器
/// <summary> /// 類適配器 /// 類適配器,Apater繼承了ArrayList,擁有了ArrayList類所有方法的同時,有實現客戶要求的接口,但是違反了類職責單一的oop原則 /// </summary> public class Apater :ArrayList,ICustomerRequired { public Apater(ICollection collection) : base(collection) { } /// <summary> /// 返回最後一項 /// </summary> /// <returns></returns> public object Peek() { if (Count >= 1) return this[this.Count - 1]; return null; } /// <summary> /// 移除最後一項,返回最後一項 /// </summary> /// <returns></returns> public object Pop() { this.RemoveAt(this.Count - 1); return Peek(); } /// <summary> /// 添加一項 /// </summary> /// <param name="item"></param> public void Push(object item) { this.Add(item); } }
分析上面的代碼發現,雖然Apater很好的完成了需求,但是存在以下兩個缺點:
1、違背了OOP原則一類的單一職責,Apater即有ArrayList的職責,又包含了ICustomerRequired接口的職責.這種方式的適配器不建議使用,更建議使用對象適配器!
2、類只能單繼承,當適配器需要適配多個類時,類適配器就無法完成這個任務.
3、類之間的強耦合關係(在OOP中,繼承會自帶耦合效果),當被適配的類發生改變時,當前適配器會被強加這種改變.
所以,使用類適配器需要慎重.相比類適配器更推薦第一種對象適配器.
6、關於適配器模式的設計建議
客戶端調用,優先使用客戶要求的接口類,如下代碼:
/// <summary> /// 第三方調用系統 /// </summary> public class ThirdSystem { /// <summary> /// 建議這種調用方式,更符合OOP的思想 /// </summary> /// <param name="customerRequired"></param> public void Process(ICustomerRequired customerRequired) { } /// <summary> /// 不建議這種方法 /// </summary> /// <param name="apater"></param> public void ProcssError(Apater apater) { } }
上面的代碼更加符合面向接口的編程思想.
7、.Net Framework中使用適配器模式的案例
public class User { public string Name { get; set; } public int Age { get; set; } } /// <summary> /// IComparer<User> 爲客戶程序要求適配器實現的接口,必須實現該接口,完成對兩個User實例的年齡比較 /// </summary> public class UserCompareApater : IComparer<User> { /// <summary> /// User類作爲被適配對象 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public int Compare(User x, User y) { if (x.Age > y.Age) return 1; else if (x.Age < y.Age) return -1; return 0; }
通過適配器,繼承了FCL中提供的兩個類型比較的接口,實現了對兩個User實例的排序。
其它的例子還有很多.如.Net數據庫訪問類(Apater變體),主流的數據庫都沒有提供DataSet接口,但是使用DbDataApater可以訪問各種數據庫,並且將讀取過來的數據填充到DataSet實例中.