設計模式之介面卡模式(Adapter)
阿新 • • 發佈:2021-07-31
一、介面卡模式的定義
介面卡模式(Adapter)的定義如下:將一個類的介面轉換成客戶希望的另外一個介面,使得原本由於介面不相容而不能一起工作的那些類能一起工作。
介面卡模式分為類結構型模式和物件結構型模式兩種:在類介面卡模式中,介面卡與適配者之間是繼承(或實現)關係;在物件介面卡模式中,介面卡與適配者之間是關聯關係。前者類之間的耦合度比後者高,且要求程式設計師瞭解現有元件庫中的相關元件的內部結構,所以應用相對較少些。
二、介面卡模式優缺點
主要優點:
- 將目標類和適配者類解耦,通過引入一個介面卡類來重用現有的適配者類,無須修改原有結構。
- 增加了類的透明性和複用性,將具體的業務實現過程封裝在適配者類中,對於客戶端類而言是透明的,而且提高了適配者的複用性,同一個適配者類可以在多個不同的系統中複用。
- 靈活性和擴充套件性都非常好,通過使用配置檔案,可以很方便地更換介面卡,也可以在不修改原有程式碼的基礎上增加新的介面卡類,完全符合“開閉原則”。
具體來說,類介面卡模式還有如下優點:
- 由於介面卡類是適配者類的子類,因此可以在介面卡類中置換一些適配者的方法,使得介面卡的靈活性更強。
物件介面卡模式還有如下優點:
- 一個物件介面卡可以把多個不同的適配者適配到同一個目標;
- 可以適配一個適配者的子類,由於介面卡和適配者之間是關聯關係,根據“里氏代換原則”,適配者的子類也可通過該介面卡進行適配。
類介面卡模式的缺點如下:
- 對於Java、C#等不支援多重類繼承的語言,一次最多隻能適配一個適配者類,不能同時適配多個適配者;
- 適配者類不能為最終類,如在Java中不能為final類,C#中不能為sealed類;
- 在Java、C#等語言中,類介面卡模式中的目標抽象類只能為介面,不能為類,其使用有一定的侷限性。
物件介面卡模式的缺點如下:
- 與類介面卡模式相比,要在介面卡中置換適配者類的某些方法比較麻煩。如果一定要置換掉適配者類的一個或多個方法,可以先做一個適配者類的子類,將適配者類的方法置換掉,然後再把適配者類的子類當做真正的適配者進行適配,實現過程較為複雜。
三、介面卡模式實現
- 類介面卡模式可採用定義一個介面卡類來實現當前系統的業務介面,同時又繼承現有元件庫中已經存在的元件。
- 物件介面卡模式可釆用將現有元件庫中已經實現的元件引入介面卡類中,該類同時實現當前系統的業務介面。現在來介紹它們的基本結構。
介面卡模式(Adapter)包含以下主要角色。
- 目標(Target)介面:當前系統業務所期待的介面,它可以是抽象類或介面。
- 適配者(Adaptee)類:它是被訪問和適配的現存元件庫中的元件介面。
- 介面卡(Adapter)類:它是一個轉換器,通過繼承或引用適配者的物件,把適配者介面轉換成目標介面,讓客戶按目標介面的格式訪問適配者。
類介面卡模式的結構圖如圖所示(繼承或實現關係):
物件介面卡模式的結構圖如圖所示(關聯關係):
程式碼實現(類介面卡模式程式碼):
//目標介面 interface Target { public void request(); }
//適配者介面 class Adaptee { public void specificRequest() { System.out.println("適配者中的業務程式碼被呼叫!"); } }
//類介面卡類 class ClassAdapter extends Adaptee implements Target { public void request() { specificRequest(); } }
//客戶端程式碼 public class ClassAdapterTest { public static void main(String[] args) { System.out.println("類介面卡模式測試:"); Target target = new ClassAdapter(); target.request(); } }
測試結果如下:
類介面卡模式測試: 適配者中的業務程式碼被呼叫!
程式碼實現(物件介面卡模式程式碼):
//目標介面 interface Target { public void request(); } //適配者介面 class Adaptee { public void specificRequest() { System.out.println("適配者中的業務程式碼被呼叫!"); } } //物件介面卡類 class ObjectAdapter implements Target { private Adaptee adaptee; public ObjectAdapter(Adaptee adaptee) { this.adaptee=adaptee; } public void request() { adaptee.specificRequest(); } } //客戶端程式碼 public class ObjectAdapterTest { public static void main(String[] args) { System.out.println("物件介面卡模式測試:"); Adaptee adaptee = new Adaptee(); Target target = new ObjectAdapter(adaptee); target.request(); } }
四、介面卡模式擴充套件(雙向介面卡模式)
介面卡模式(Adapter)可擴充套件為雙向介面卡模式,雙向介面卡類既可以把適配者介面轉換成目標介面,也可以把目標介面轉換成適配者介面,其結構圖如圖所示:
實現程式碼如下:
//目標介面 interface TwoWayTarget { public void request(); } //適配者介面 interface TwoWayAdaptee { public void specificRequest(); } //目標實現 class TargetRealize implements TwoWayTarget { public void request() { System.out.println("目的碼被呼叫!"); } } //適配者實現 class AdapteeRealize implements TwoWayAdaptee { public void specificRequest() { System.out.println("適配者程式碼被呼叫!"); } } //雙向介面卡 class TwoWayAdapter implements TwoWayTarget, TwoWayAdaptee { private TwoWayTarget target; private TwoWayAdaptee adaptee; public TwoWayAdapter(TwoWayTarget target) { this.target=target; } public TwoWayAdapter(TwoWayAdaptee adaptee) { this.adaptee=adaptee; } public void request() { adaptee.specificRequest(); } public void specificRequest() { target.request(); } } //客戶端程式碼 public class TwoWayAdapterTest { public static void main(String[] args) { System.out.println("目標通過雙向介面卡訪問適配者:"); TwoWayAdaptee adaptee=new AdapteeRealize(); TwoWayTarget target=new TwoWayAdapter(adaptee); target.request(); System.out.println("-------------------"); System.out.println("適配者通過雙向介面卡訪問目標:"); target=new TargetRealize(); adaptee=new TwoWayAdapter(target); adaptee.specificRequest(); } }
執行結果如下:
目標通過雙向介面卡訪問適配者: 適配者程式碼被呼叫! ------------------- 適配者通過雙向介面卡訪問目標: 目的碼被呼叫!
五、介面卡模式適用場景
常見介面卡模式使用場景如下:
- 系統需要使用一些現有的類,而這些類的介面(如方法名)不符合系統的需要,甚至沒有這些類的原始碼。
- 想建立一個可以重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。
在開源框架中有很多地方使用到了介面卡模式,比如Spring AOP中,使用的 Advice(通知) 來增強被代理類的功能;SpringMVC中介面卡模式主要用於執行目標Controller
中的請求處理方法;Spring中關於資料庫型別的適配;Netty中關於InboundHandler和OutboundHandler的適配。