一、模式動機
- 在軟件開發中采用類似于電源適配器的設計和編碼技巧被稱為適配器模式。
- 通常情況下,客戶端可以通過目標類的接口訪問它所提供的服務。有時,現有的類可以滿足客戶類的功能需要,但是它所提供的接口不一定是客戶類所期望的,這可能是因為現有類中方法名與目標類中定義的方法名不一致等原因所導致的。
- 在這種情況下,現有的接口需要轉化為客戶類期望的接口,這樣保證了對現有類的重用。如果不進行這樣的轉化,客戶類就不能利用現有類所提供的功能,適配器模式可以完成這樣的轉化。
- 在適配器模式中可以定義一個包裝類,包裝不兼容接口的對象,這個包裝類指的就是適配器(Adapter),它所包裝的對象就是適配者(Adaptee),即被適配的類。
- 適配器提供客戶類需要的接口,適配器的實現就是把客戶類的請求轉化為對適配者的相應接口的調用。也就是說:當客戶類調用適配器的方法時,在適配器類的內部將調用適配者類的方法,而這個過程對客戶類是透明的,客戶類并不直接訪問適配者類。因此,適配器可以使由于接口不兼容而不能交互的類可以一起工作。這就是適配器模式的模式動機。
二、模式定義
適配器模式(Adapter Pattern) :將一個接口轉換成客戶希望的另一個接口,適配器模式使接口不兼容的那些類可以一起工作,其別名為包裝器(Wrapper)。適配器模式既可以作為類結構型模式,也可以作為對象結構型模式。
三、模式結構
適配器模式包含如下角色:
- Target:目標抽象類
- Adapter:適配器類
- Adaptee:適配者類
- Client:客戶類
適配器模式有對象適配器和類適配器兩種實現:
3.1、對象適配器:
3.2、類適配器:
四、代碼分析
4.1、對象適配器代碼實現
public interface Target {
void sampleOperation1();
void sampleOperation2();
}
public class Adaptee {
public void sampleOperation1() {
System.out.println("sampleOperation1");
}
}
public class Adapter implements Target {
private Adaptee mAdaptee;
public Adapter(Adaptee adaptee) {
mAdaptee = adaptee;
}
@Override
public void sampleOperation1() {
mAdaptee.sampleOperation1();
}
@Override
public void sampleOperation2() {
System.out.println("sampleOperation2");
}
}
public class MyClass {
public static void main(String[] args) {
Adapter adapter =new Adapter(new Adaptee());
adapter.sampleOperation1();
adapter.sampleOperation2();
}
}
輸出內容為:
sampleOperation1
sampleOperation2
4.2、類適配器代碼實現
public interface Target {
void sampleOperation1();
void sampleOperation2();
}
public class Adaptee {
public void sampleOperation1() {
System.out.println("sampleOperation1");
}
}
public class Adapter extends Adaptee implements Target {
@Override
public void sampleOperation2() {
System.out.println("sampleOperation2");
}
}
public class MyClass {
public static void main(String[] args) {
Target adapter = new Adapter();
adapter.sampleOperation1();
adapter.sampleOperation2();
}
}
輸出內容為:
sampleOperation1
sampleOperation2
五、優點
- 將目標類和適配者類解耦,通過引入一個適配器類來重用現有的適配者類,而無須修改原有代碼。
- 增加了類的透明性和復用性,將具體的實現封裝在適配者類中,對于客戶端類來說是透明的,而且提高了適配者的復用性。
- 靈活性和擴展性都非常好,通過使用配置文件,可以很方便地更換適配器,也可以在不修改原有代碼的基礎上增加新的適配器類,完全符合“開閉原則”。
類適配器模式還具有如下優點:
由于適配器類是適配者類的子類,因此可以在適配器類中置換一些適配者的方法,使得適配器的靈活性更強。
對象適配器模式還具有如下優點:
一個對象適配器可以把多個不同的適配者適配到同一個目標,也就是說,同一個適配器可以把適配者類和它的子類都適配到目標接口。
六、缺點
類適配器模式的缺點如下:
對于Java、C#等不支持多重繼承的語言,一次最多只能適配一個適配者類,而且目標抽象類只能為抽象類,不能為具體類,其使用有一定的局限性,不能將一個適配者類和它的子類都適配到目標接口。
對象適配器模式的缺點如下:
與類適配器模式相比,要想置換適配者類的方法就不容易。如果一定要置換掉適配者類的一個或多個方法,就只好先做一個適配者類的子類,將適配者類的方法置換掉,然后再把適配者類的子類當做真正的適配者進行適配,實現過程較為復雜。
七、適用環境
在以下情況下可以使用適配器模式:
- 系統需要使用現有的類,而這些類的接口不符合系統的需要。
- 想要建立一個可以重復使用的類,用于與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。
八、模式應用
Sun公司在1996年公開了Java語言的數據庫連接工具JDBC,JDBC使得Java語言程序能夠與數據庫連接,并使用SQL語言來查詢和操作數據。JDBC給出一個客戶端通用的抽象接口,每一個具體數據庫引擎(如SQL Server、Oracle、MySQL等)的JDBC驅動軟件都是一個介于JDBC接口和數據庫引擎接口之間的適配器軟件。抽象的JDBC接口和各個數據庫引擎API之間都需要相應的適配器軟件,這就是為各個不同數據庫引擎準備的驅動程序。
九、模式擴展
認適配器模式(Default Adapter Pattern)或缺省適配器模式
當不需要全部實現接口提供的方法時,可先設計一個抽象類實現接口,并為該接口中每個方法提供一個默認實現(空方法),那么該抽象類的子類可有選擇地覆蓋父類的某些方法來實現需求,它適用于一個接口不想使用其所有的方法的情況。因此也稱為單接口適配器模式。
十、總結
- 結構型模式描述如何將類或者對象結合在一起形成更大的結構。
- 適配器模式用于將一個接口轉換成客戶希望的另一個接口,適配器模式使接口不兼容的那些類可以一起工作,其別名為包裝器。適配器模式既可以作為類結構型模式,也可以作為對象結構型模式。
- 適配器模式包含四個角色:目標抽象類定義客戶要用的特定領域的接口;適配器類可以調用另一個接口,作為一個轉換器,對適配者和抽象目標類進行適配,它是適配器模式的核心;適配者類是被適配的角色,它定義了一個已經存在的接口,這個接口需要適配;在客戶類中針對目標抽象類進行編程,調用在目標抽象類中定義的業務方法。
- 在類適配器模式中,適配器類實現了目標抽象類接口并繼承了適配者類,并在目標抽象類的實現方法中調用所繼承的適配者類的方法;在對象適配器模式中,適配器類繼承了目標抽象類并定義了一個適配者類的對象實例,在所繼承的目標抽象類方法中調用適配者類的相應業務方法。
- 適配器模式的主要優點是將目標類和適配者類解耦,增加了類的透明性和復用性,同時系統的靈活性和擴展性都非常好,更換適配器或者增加新的適配器都非常方便,符合“開閉原則”;類適配器模式的缺點是適配器類在很多編程語言中不能同時適配多個適配者類,對象適配器模式的缺點是很難置換適配者類的方法。
- 適配器模式適用情況包括:系統需要使用現有的類,而這些類的接口不符合系統的需要;想要建立一個可以重復使用的類,用于與一些彼此之間沒有太大關聯的一些類一起工作。
本文參考:http://www.lxweimin.com/p/b770626554fc
http://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/adapter.html#id12