一:適配器模式的定義算法
適配器模式:將一個類的接口轉換成客戶但願的另外一個接口。適配器模式讓那些接口不兼容的類能夠一塊兒工做編程
Adapter Pattern:Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interface.app
適配器模式的別名爲包裝器(Wrapper)模式,它既能夠做爲類結構型模式,也能夠做爲對象結構型模式。在適配器模式定義中所說起的接口是指廣義的接口,它能夠表示一個方法或者方法的集合。測試
二:適配器模式的結構ui
類適配器模式結構圖:this
對象適配器結構圖:spa
由圖可知適配器模式包含一下三個角色:設計
1:Target(目標抽象類):目標抽象類定義客戶所需的接口,能夠是一個抽象類或接口,也能夠是具體類。在類適配器中,因爲C#語言不支持多重繼承,因此它只能是接口。code
2:Adapter(適配器類):它能夠調用另外一個接口,做爲一個轉換器,對Adaptee和Target進行適配。它是適配器模式的核心。xml
3:Adaptee(適配者類):適配者即被適配的角色,它定義了一個已經存在的接口,這個接口須要適配,適配者類包好了客戶但願的業務方法。
三:適配器模式的實現
1:類適配器
class Adapter : Adaptee, Target { public void Request() { base.SpecificRequest(); } }
2:對象適配器
class Adapter : Target { private Adaptee adaptee; //維持一個對適配者對象的引用 public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } public void Request() { adaptee.SpecificRequest();//轉發調用 } }
注意:在實際開發中對象適配器的使用頻率更高。
四:適配器模式的應用
在爲某學校開發教務管理系統時,開發人員發現須要對學生成績進行排序和查找,該系統的設計人員已經開發了一個成績操做接口ScoreOperation,在該接口中聲明瞭排序方法Sort(int[]) 和查找方法Search(int[], int),爲了提升排序和查找的效率,開發人員決定重用現有算法庫中的快速排序算法類QuickSortClass和二分查找算法類BinarySearchClass,其中QuickSortClass的QuickSort(int[])方法實現了快速排序,BinarySearchClass的BinarySearch (int[], int)方法實現了二分查找。
因爲某些緣由,開發人員已經找不到該算法庫的源代碼,沒法直接經過複製和粘貼操做來重用其中的代碼;並且部分開發人員已經針對ScoreOperation接口編程,若是再要求對該接口進行修改或要求你們直接使用QuickSortClass類和BinarySearchClass類將致使大量代碼須要修改。
現使用適配器模式設計一個系統,在不修改已有代碼的前提下將類QuickSortClass和類BinarySearchClass的相關方法適配到ScoreOperation接口中。
結構以下圖所示:
ScoreOperation接口充當抽象目標,QuickScortClass和BinarySearchClass充當適配者,OperationAdapter充當適配器。
(1)ScoreOperation:抽象成績操做類,充當目標接口
public interface ScoreOperation { int[] Sort(int[] array); //成績排序 int Search(int[] array, int key); //成績查找 }
(2)QuickSortClass:快速排序類,充當適配者
public class QuickSortClass { public int[] QuickSort(int[] array) { Sort(array, 0, array.Length - 1); return array; } public void Sort(int[] array, int p, int r) { int q = 0; if(p < r) { q = Partition(array, p, r); Sort(array, p, q - 1); Sort(array, q + 1, r); } } public int Partition(int[] array, int p, int r) { int x = array[r]; int j = p - 1; for (int i = p; i <= r - 1; i++) { if(array[i] <= x) { j++; Swap(array, j, i); } } Swap(array, j + 1, r); return j + 1; } public void Swap(int[] array, int i, int j) { int t = array[i]; array[i] = array[j]; array[j] = t; } }
(3)BinarySearchClass:二分查找類,充當適配者
public class BinarySearchClass { public int BinarySearch(int[] array, int key) { int low = 0; int high = array.Length - 1; while (low <= high) { int mid = (low + high) / 2; int midVal = array[mid]; if (midVal < key) low = mid + 1; else if (midVal > key) high = mid - 1; else return 1; //找到元素返回1 } return -1; //未找到元素返回-1 } }
(4)OperationAdapter:操做適配器,充當適配器
public class OperationAdapter : ScoreOperation { //定義適配者QuickSortClass對象 private QuickSortClass sortObj; //定義適配者BinarySearchClass對象 private BinarySearchClass searchObj; public OperationAdapter() { sortObj = new QuickSortClass(); searchObj = new BinarySearchClass(); } public int Search(int[] array, int key) { return searchObj.BinarySearch(array, key); } public int[] Sort(int[] array) { return sortObj.QuickSort(array); } }
(5)配置文件App.config:在配置文件中存儲了適配器類的類名
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> </startup> <appSettings> <add key="adapter" value="Model.AdapterSample.OperationAdapter"/> </appSettings> </configuration>
(6)Program:客戶端測試類
static void Main(string[] args) { ScoreOperation operation; //讀取配置文件 string adapterType = ConfigurationManager.AppSettings["adapter"]; //經過反射生成對象 operation = (ScoreOperation)Assembly.Load("Model.AdapterSample").CreateInstance(adapterType); int[] socres = { 84,76, 50, 69, 90, 92, 88, 86 }; int[] result; int score; Console.WriteLine("程序的排序結果是:"); result = operation.Sort(socres); //遍歷輸出成績 foreach (var item in result) Console.Write(item+","); Console.WriteLine(); Console.WriteLine("查找成績90:"); score = operation.Search(result, 90); if(score!=-1) Console.WriteLine("找到成績90."); else Console.WriteLine("沒有找到成績90。"); Console.WriteLine("查找成績92:"); score = operation.Search(result, 920); if(score!=-1) Console.WriteLine("找到成績92."); else Console.WriteLine("沒有找到成績92。"); Console.ReadKey(); }
五:適配器模式的優缺點
優勢:
1:將目標類和適配者類解耦,經過引入一個適配器類來重用現有的適配者類,無需修改原有結構。
2:增長了類的透明性和複用性,將具體的業務實現過程封裝在適配者類中,對於客戶端類而言是透明的,並且提升了適配者的複用性,同一適配者類能夠在多個不一樣的系統中複用。
3:靈活性和擴展性都很是好,經過使用配置文件,能夠很方便的更換適配器,也能夠在不修改原有代碼的基礎上 增長新的適配器,徹底複合開閉原則。
缺點:
1:一次最多隻能適配一個適配者類,不能同時適配多個適配者。
2:適配者類不能爲最終類,在C#中不能爲sealed類
3:目標抽象類只能爲接口,不能爲類,其使用有必定的侷限性。
六:適配器模式的適用環境
系統須要使用一些現有的類,而這些類的接口不符合系統的須要,甚至沒有這些類的源代碼
建立一個能夠重複使用的類,用於和一些彼此之間沒有太大關聯的類,包括一些可能在未來引進的類一塊兒工做
七:缺醒適配器模式
缺醒適配器模式(Default Adapter Pattern):當不須要實現一個接口所提供的全部方法時,可先設計一個抽象類實現該接口,併爲接口中的每一個方法提供一個默認實現(空方法),那麼該抽象類能夠有選擇性的覆蓋父類的某些方法來實現需求,它適用於不想使用一個接口中的全部方法的狀況,又稱爲單接口適配器模式。
由圖可知,在缺醒適配器模式中,包含如下三個角色:
1:ServiceInsterface(適配者接口):它是一個接口,一般在該接口中聲明瞭大量的方法
2:AbstractServiceClass(缺醒適配器類):它是缺醒適配器模式的核心類,使用空方法的形式實現了ServiceInterface接口中聲明的方法。一般將它定義爲抽象類,由於對它進行實例化也沒有任何意義。
3:ConcreteServiceClass(具體業務類):它是缺醒適配器的子類,在沒有引入適配器以前,它須要實現適配者接口,所以須要實如今適配者接口中生命的全部方法,而對於一些無需使用的方法不得不提供空實現。有了缺醒適配器以後,能夠直接繼承該適配器類,根據須要有選擇性的覆蓋配置器類中定義的方法。
八:雙向適配器
在對象適配器中若是同時包含目標類和適配者類的引用,適配者能夠經過它調用目標類中的方法,目標類也能夠經過它調用適配者類中的方法,那麼該適配器就是一個雙向適配器。
雙向適配器結構示意圖:
示意代碼:
public class Adapter:Target,Adaptee { //同時維持對抽象目標類和適配者類的引用 private Target target; private Adaptee adaptee; public Adapter(Target target) { this.target = target; } public Adapter(Adaptee adatee) { this.adaptee = adatee; } public void Reqeust() { this.adaptee.SpecificRequest(); } public void SpecificRequest() { this.target.Request(); } }