1. 介紹
1.1 模式說明
定義一個(gè)包裝類藐俺,用于包裝不兼容接口的對(duì)象。
- 包裝類 = 適配器Adapter;
- 被包裝對(duì)象 = 適配者Adaptee = 被適配的類小压。
1.2 定義
將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口壤靶。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作缚俏。
適配器模式的兩種形式:類的適配器模式 & 對(duì)象的適配器模式
2. 類的適配器模式
2.1 UML類圖 & 組成講解
類的適配器模式UML.jpg
- Target:期待得到的接口(目標(biāo)角色)
- ConcreteTarget:具體目標(biāo)類,具有目標(biāo)的普通功能
- Adaptee:需要適配的接口(源角色)
- Adapter:把源接口轉(zhuǎn)換成目標(biāo)接口(適配器角色)
2.2 解釋說明
在類的UML類圖可以看出:
- 沖突:Target期待調(diào)用Request方法贮乳,而Adaptee并沒有(這就是所謂的不兼容了)忧换。
- 解決方案:為使Target能夠使用Adaptee類里的SpecificRequest方法,故提供一個(gè)中間環(huán)節(jié)Adapter類(繼承Adaptee & 實(shí)現(xiàn)Target接口)向拆,把Adaptee的API與Target的API銜接起來(適配)亚茬。
Adapter與Adaptee是繼承關(guān)系,這決定了這個(gè)適配器模式是類的適配器模式浓恳。
2.3 使用步驟(代碼解析)
步驟1: 創(chuàng)建Target接口
public interface Target {
//這是源類Adapteee沒有的方法
void Request();
}
步驟2: 創(chuàng)建源類(Adaptee)
public class Adaptee {
public void SpecificRequest(){
System.out.println("源類方法");
}
}
步驟3: 創(chuàng)建適配器類(Adapter)
//適配器Adapter繼承自Adaptee刹缝,同時(shí)又實(shí)現(xiàn)了目標(biāo)(Target)接口
public class Adapter extends Adaptee implements Target {
//目標(biāo)接口要求調(diào)用Request()這個(gè)方法名,但源類Adaptee沒有方法Request()
//因此適配器補(bǔ)充上這個(gè)方法
//但實(shí)際上Request()還是調(diào)用的源類Adaptee的SpecificRequest()的方法
//所以適配器只是將SpecificRequest()方法作了一層包裝處理颈将,兼容成了可以調(diào)用的Request()的Target而已
@Override
public void Request() {
this.SpecificRequest();
}
}
步驟4:定義具體使用目標(biāo)類梢夯,并通過Adapter類調(diào)用所需要的方法從而實(shí)現(xiàn)目標(biāo)
public class AdapterPattern {
public static void main(String[] args){
Target mAdapter = new Adapter();
mAdapter.Request();//會(huì)打印輸出:源類方法
}
}
2.4 實(shí)例講解
接下來我用一個(gè)實(shí)例來對(duì)類的適配器模式進(jìn)行更深一步的介紹。
a. 實(shí)例概況
- 背景:小成買了一個(gè)進(jìn)口的電視機(jī)晴圾。
- 沖突:進(jìn)口電視機(jī)要求電壓(110V)與國(guó)內(nèi)插頭標(biāo)準(zhǔn)輸出電壓(220V)不兼容颂砸。
- 解決方案:通過適配器將插頭輸出的220V轉(zhuǎn)變成110V。
b. 使用步驟
步驟1: 創(chuàng)建Target接口(期待得到的插頭):能輸出110V電壓
public interface Target {
//將220V轉(zhuǎn)換輸出110V方法
void Convert_110v();
}
步驟2: 創(chuàng)建源類(國(guó)內(nèi)輸出220V電壓的插頭)
public class PowerPort220V {
//國(guó)內(nèi)輸出220V電壓的插頭
public void Output_220v(){}
}
步驟3: 創(chuàng)建適配器類(Adapter)
public class Adapter220V extends PowerPort220V implements Target {
@Override
public void Convert_110v() {
this.Output_220v();
}
}
步驟4: 進(jìn)口電視機(jī)類
public class ImportedTv {
//進(jìn)口電視機(jī)需要傳入目標(biāo)110V電壓進(jìn)行供電才能正常運(yùn)行
public void Work(Target target) {
System.out.println("進(jìn)口電視正常運(yùn)行");
}
}
步驟5: 使用
public class AdapterPattern {
public static void main(String[] args){
Target mAdapter220V = new Adapter220V();
ImportedTv mImportedTv = new ImportedTv();
//用戶拿著進(jìn)口機(jī)器插上適配器(調(diào)用Convert_110v()方法)
//再將適配器插上原有插頭(Convert_110v()方法內(nèi)部調(diào)用Output_220v()方法)
//適配器只是對(duì)國(guó)內(nèi)220V電壓進(jìn)行轉(zhuǎn)換疑务,轉(zhuǎn)換成進(jìn)口電視機(jī)能正常使用的110V電壓沾凄,但本質(zhì)還是使用國(guó)內(nèi)220V進(jìn)行供電
mAdapter220V.Convert_110v();
mImportedTv.Work(mAdapter220V);//會(huì)打印輸出:進(jìn)口電視正常運(yùn)行
}
}
3. 對(duì)象的適配器模式
與類的適配器模式不同的是,對(duì)象的適配器模式不是使用繼承關(guān)系連接到Adaptee類知允,而是使用委派關(guān)系連接到Adaptee類撒蟀。
3.1 UML類圖
對(duì)象的適配器模式UML.jpg
Adapter與Adaptee是委派關(guān)系,即通過在Adapter的構(gòu)造方法中傳入具體需要適配的對(duì)象Adaptee温鸽,這決定了適配器模式是對(duì)象的適配器模式保屯。
3.2 使用步驟(代碼解析)
步驟1: 創(chuàng)建Target接口
public interface Target {
//這是源類Adapteee沒有的方法
void Request();
}
步驟2: 創(chuàng)建源類(Adaptee)
public class Adaptee {
public void SpecificRequest(){
System.out.println("源類方法");
}
}
步驟3: 創(chuàng)建適配器類(Adapter)(不再用繼承而是委派)
public class Adapter implements Target {
// 直接關(guān)聯(lián)被適配類
private Adaptee adaptee;
//通過構(gòu)造函數(shù)傳入具體需要適配的對(duì)象
public Adapter (Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void Request() {
// 這里是使用委派的方式完成特殊功能
this.adaptee.SpecificRequest();
}
}
步驟4:定義具體使用目標(biāo)類手负,并通過Adapter類調(diào)用所需要的方法從而實(shí)現(xiàn)目標(biāo)
public class AdapterPattern {
public static void main(String[] args){
Target mAdapter = new Adapter(new Adaptee());
mAdapter.Request();//會(huì)打印輸出:源類方法
}
}
4. 優(yōu)缺點(diǎn)和兩種方式的適配器比較
4.1 優(yōu)點(diǎn)
- 更好的復(fù)用性:系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要姑尺。那么通過適配器模式就可以讓這些功能得到更好的復(fù)用竟终。
- 透明、簡(jiǎn)單:客戶端可以調(diào)用同一接口切蟋,因而對(duì)客戶端來說是透明的统捶。這樣做更簡(jiǎn)單 & 更直接
- 更好的擴(kuò)展性:在實(shí)現(xiàn)適配器功能的時(shí)候,可以調(diào)用自己開發(fā)的功能柄粹,從而自然地?cái)U(kuò)展系統(tǒng)的功能喘鸟。
- 解耦性:將目標(biāo)類和適配者類解耦,通過引入一個(gè)適配器類重用現(xiàn)有的適配者類驻右,而無需修改原有代碼
- 符合開放-關(guān)閉原則:同一個(gè)適配器可以把適配者類和它的子類都適配到目標(biāo)接口什黑;可以為不同的目標(biāo)接口實(shí)現(xiàn)不同的適配器,而不需要修改待適配類
4.2 缺點(diǎn)
- 過多的使用適配器堪夭,會(huì)讓系統(tǒng)非常零亂愕把,不易整體進(jìn)行把握。
4.3 比較
- 類的適配器模式使用方便森爽,代碼簡(jiǎn)化恨豁;而對(duì)象的適配器模式使用復(fù)雜,需要引入對(duì)象實(shí)例爬迟。
- 類的適配器模式高耦合圣絮,靈活性低,使用對(duì)象繼承的方式雕旨,是靜態(tài)的定義方式;而對(duì)象的適配器模式靈活性高捧请、低耦合凡涩,采用 “對(duì)象組合”的方式,是動(dòng)態(tài)組合方式疹蛉。
5. 使用建議
建議盡量使用對(duì)象的適配器模式活箕,多用合成/聚合、少用繼承可款。