基礎介紹:
想象這樣一個場景,原專案中介面返回的資料是XML格式的資料,但現在來了一個新客戶,它期望介面返回的資料型別為json格式的。
想要實現要麼就是改原有介面,但這樣就違反了開閉原則,容易出現未知bug,影響到老客戶的正常使用。
而如果寫一個介面卡類也就是轉換類(第三方類),將原本返回的XML格式資料轉換成json格式資料,而具體資料是怎麼來的則直接用原有介面方法就可以。
新客戶只需要呼叫介面卡類就可以了,而老客戶這邊也不會進行任何修改處理。
如果再有新的客戶要求其他型別的返回,只需要在介面卡類中增加相應的轉換處理就可以了。
再思考一個問題,現實生活中空調插頭一般都是三頭的,但如果家裡只有兩孔插座,那必然是插不進去的。
以前老的辦法那就是把三頭插座掰掉一個,另外兩個也掰直,這樣做存在很大的安全隱患,而且有時並不能工作。
而如果提供一個擁有三孔插座和兩頭插頭的轉換器的話,那空調可以先插在這個轉換器上,然後這個轉換器再插在插座上就可以了。
本質並沒有變,只是將二孔插座包裝了一下,向外界提供了一個三孔插座的外觀以供客戶使用。
適配的本質就是轉換,將不滿足使用條件的東西透過第三方類進行加工處理成可使用的東西。
介面卡模式(Apapter Pattern)是一種結構型設計模式,將一個類的介面轉換成客戶希望的另一個介面。介面卡模式使得原本由於介面相容而不能一起工作的那些類可以一起工作。
介面卡模式用來解決現有物件與客戶端期待介面不一致的問題。
- 目標角色(Target):描述了其他類與客戶端程式碼合作時必須遵循的協議。
- 客戶角色(Client):與符合Target介面的物件協同。
- 被適配(服務類,功能類)(Adaptee):定義一個已經存在並已經使用的介面,這個介面需要適配。 客戶端與其介面不相容, 因此無法直接呼叫其功能。
- 介面卡(Adapter) :介面卡模式的核心。介面卡接受客戶端透過介面卡介面發起的呼叫,同時根據其內在邏輯呼叫對應服務類。客戶端程式碼只需透過介面與介面卡互動即可, 無需與具體的服務類耦合。
優缺點:
- 單一職責原則:可以將介面或資料轉換程式碼從主要業務邏輯中分離。
- 開閉原則: 客戶端介面只需介面卡進行互動, 能在不修改現有程式碼的情況下在程式中新增新型別的介面卡。
- 透過介面卡模式,可以使兩個不相容的介面協同工作,避免了修改現有程式碼的需要。
- 提高了程式碼的複用性和靈活性,因為介面卡可以重複使用,並且可以在不同的場景中使用。
- 降低了系統的耦合度,介面卡模式允許系統中的各個元件相互獨立地演化。
- 程式碼整體複雜度增加 :因為需要新增一系列介面和類。 有時直接更改服務類使其與其他程式碼相容會更簡單。
應用場景:
系統需要複用現有類,但是介面又與複用環境要求不一致的情況。
- 舊系統與新系統的相容:可以使新系統能夠無縫地與老舊系統進行通訊。
- 第三方元件的整合:介面卡可以將第三方元件的介面轉換為符合我們系統需求的介面形式,從而能夠順利地整合到我們的系統中。
- 多個類庫之間的互操作:介面卡模式可以起到橋樑的作用。
建立方式:
介面卡模式有兩種實現結構,物件介面卡和類介面卡。
試想一下,目前有一個三頭插頭的空調,需要一個三孔插座,但目前只有一個兩孔插座。
編寫一個介面卡來包裝一下這個兩孔插座,讓使用者可以使用這個空調。
-
類介面卡
1 /// <summary> 2 /// 兩孔插座---被適配者 3 /// </summary> 4 public class TwoHoleSocket 5 { 6 public void SpecificRequest() 7 { 8 Console.WriteLine("兩孔插座"); 9 } 10 } 11 12 /// <summary> 13 /// 三孔插座---目標角色 14 /// </summary> 15 public interface IThreeHoleSocket 16 { 17 void Request(); 18 } 19 20 /// <summary> 21 /// 介面卡類提供了三孔插座的外觀,但其本質是兩孔插座 22 /// </summary> 23 public class PowerAdapter : TwoHoleSocket, IThreeHoleSocket 24 { 25 public void Request() 26 { 27 Console.WriteLine("提供三孔插座的外觀"); 28 //執行兩孔插座的功能 29 this.SpecificRequest(); 30 } 31 } 32 33 /// <summary> 34 /// 客戶端 35 /// </summary> 36 class Client 37 { 38 static void Main(string[] args) 39 { 40 //客戶端可以透過介面卡來使用這個兩孔插座了(因為外觀已經是三孔的了) 41 IThreeHoleSocket threeHoleSocket = new PowerAdapter(); 42 threeHoleSocket.Request(); 43 Console.ReadKey(); 44 } 45 }
TwoHoleSocket類代表原有的兩孔插座,IThreeHoleSocket介面來規範三孔插座的外觀。
PowerAdapter類代表介面卡,將兩孔插座賦予三孔插座的外觀。
這樣使用者就可以使用這個介面卡來使用這個三頭插頭的空調了。
從例項中可以看出,類介面卡只要是用繼承來實現的,但如果有很多個類進行適配,這個方式就不支援了。
-
物件介面卡
1 /// <summary> 2 /// 兩孔插座---被適配者 3 /// </summary> 4 public class TwoHoleSocket 5 { 6 public void SpecificRequest() 7 { 8 Console.WriteLine("兩孔插座"); 9 } 10 } 11 12 /// <summary> 13 /// 三孔插座---目標角色 14 /// </summary> 15 public class ThreeHoleSocket 16 { 17 // 客戶端需要的方法 18 public virtual void Request() 19 { 20 //具體實現 21 } 22 } 23 24 /// <summary> 25 /// 介面卡類提供了三孔插座的外觀,但其本質是兩孔插座 26 /// </summary> 27 public class PowerAdapter : ThreeHoleSocket 28 { 29 //引用兩孔插座的例項,從而將客戶端與TwoHoleSocket聯絡起來 30 public TwoHoleSocket twoHoleSocket = new TwoHoleSocket(); 31 public override void Request() 32 { 33 Console.WriteLine("提供三孔插座的外觀"); 34 this.Request(); 35 //執行兩孔插座的功能 36 twoHoleSocket.SpecificRequest(); 37 } 38 } 39 40 /// <summary> 41 /// 客戶端 42 /// </summary> 43 class Client 44 { 45 static void Main(string[] args) 46 { 47 //客戶端可以透過介面卡來使用這個兩孔插座了(因為外觀已經是三孔的了) 48 ThreeHoleSocket threeHoleSocket = new PowerAdapter(); 49 threeHoleSocket.Request(); 50 Console.ReadKey(); 51 } 52 }
從例項中可以看出,物件介面卡其實就是在介面卡類中建立了一個被適配者的例項,從而將兩者聯絡在一起。
這種方式採用 “物件組合”的方式,更符合松耦合。
總結:
總而言之,介面卡就是一個第三方類,將不合時宜的東西轉換成符合心意的工具類。
本質就是轉換。