描述
????適配器模式把一個(gè)類的接口變換成客戶端所期待的另一種接口窃祝,從而使原本因接口不匹配而無法在一起工作的兩個(gè)類能夠在一起工作护昧。
簡介
????適配器模式有類的適配器模式和對象的適配器模式兩種不同的形式初家。
????類的適配器模式通過繼承方式把適配的類的API轉(zhuǎn)換成為目標(biāo)類的API。Adapter與Adaptee是繼承關(guān)系。
????對象的適配器模式通過組合方式把適配的類的API轉(zhuǎn)換成為目標(biāo)類的API笼恰。Adapter與Adaptee是組合關(guān)系冤荆。
角色
- Target(目標(biāo)抽象類):目標(biāo)抽象類定義客戶所需的接口朴则,可以是一個(gè)抽象類或接口,也可以是具體類钓简。
- Adapter(適配器類):它可以調(diào)用另一個(gè)接口佛掖,作為一個(gè)轉(zhuǎn)換器,對Adaptee和Target進(jìn)行適配涌庭。它是適配器模式的核心芥被。
- Adaptee(適配者類):適配者即被適配的角色,它定義了一個(gè)已經(jīng)存在的接口坐榆,這個(gè)接口需要適配拴魄,適配者類包好了客戶希望的業(yè)務(wù)方法。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 將目標(biāo)類和適配者類解耦席镀,通過引入一個(gè)適配器類來重用現(xiàn)有的適配者類匹中,無需修改原有結(jié)構(gòu)。
- 增加了類的透明性和復(fù)用性豪诲,將具體的業(yè)務(wù)實(shí)現(xiàn)過程封裝在適配者類中顶捷,對于客戶端類而言是透明的,而且提高了適配者的復(fù)用性屎篱,同一適配者類可以在多個(gè)不同的系統(tǒng)中復(fù)用服赎。
- 靈活性和擴(kuò)展性都非常好,通過使用配置文件交播,可以很方便的更換適配器重虑,也可以在不修改原有代碼的基礎(chǔ)上增加新的適配器,完全復(fù)合開閉原則秦士。
缺點(diǎn)
- 過多地使用適配器缺厉,會讓系統(tǒng)非常零亂,不易整體進(jìn)行把握。
- 由于 JAVA 至多繼承一個(gè)類提针,所以至多只能適配一個(gè)適配者類命爬,而且目標(biāo)類必須是抽象類,有一定的局限性辐脖。
使用場景
- 系統(tǒng)需要使用一些現(xiàn)有的類遇骑,而這些類的接口不符合系統(tǒng)的需要,甚至沒有這些類的源代碼揖曾。
- 創(chuàng)建一個(gè)可以重復(fù)使用的類落萎,用于和一些彼此之間沒有太大關(guān)聯(lián)的類,包括一些可能在將來引進(jìn)的類一起工作炭剪。
類適配器和對象適配器的權(quán)衡
- 類適配器使用對象繼承的方式练链,是靜態(tài)的定義方式;而對象適配器使用對象組合的方式奴拦,是動態(tài)組合的方式媒鼓。
- 對于類適配器,由于適配器直接繼承了Adaptee错妖,使得適配器不能和Adaptee的子類一起工作绿鸣,因?yàn)槔^承是靜態(tài)的關(guān)系,當(dāng)適配器繼承了Adaptee后暂氯,就不可能再去處理 Adaptee的子類了潮模。而對于對象適配器,一個(gè)適配器可以把多種不同的源適配到同一個(gè)目標(biāo)痴施。換言之擎厢,同一個(gè)適配器可以把源類和它的子類都適配到目標(biāo)接口。因?yàn)閷ο筮m配器采用的是對象組合的關(guān)系辣吃,只要對象類型正確动遭,是不是子類都無所謂。
- 對于類適配器神得,適配器可以重定義Adaptee的部分行為厘惦,相當(dāng)于子類覆蓋父類的部分實(shí)現(xiàn)方法。而對于對象適配器哩簿,要重定義Adaptee的行為比較困難宵蕉,這種情況下,需要定義Adaptee的子類來實(shí)現(xiàn)重定義卡骂,然后讓適配器組合子類国裳。雖然重定義Adaptee的行為比較困難形入,但是想要增加一些新的行為則方便的很全跨,而且新增加的行為可同時(shí)適用于所有的源。
- 對于類適配器亿遂,僅僅引入了一個(gè)對象浓若,并不需要額外的引用來間接得到Adaptee渺杉。而對于對象適配器,需要額外的引用來間接得到Adaptee挪钓。
????建議盡量使用對象適配器的實(shí)現(xiàn)方式是越,多用合成/聚合、少用繼承碌上。當(dāng)然倚评,具體問題具體分析,根據(jù)需要來選用實(shí)現(xiàn)方式馏予,最適合的才是最好的天梧。
示例
類適配器
/**
* 需要適配的類
*/
public class Adaptee {
public void specificRequest(){
System.out.println("系統(tǒng)原有的接口");
}
}
/**
* 客戶端需要的接口
*/
public interface Target {
/**
* 客戶端需要的接口
*/
void request();
}
/**
* 適配器,最終客戶需要的類
*/
public class Adapter extends Adaptee implements Target{
/**
* 客戶端需要的接口
*/
@Override
public void request() {
System.out.println("客戶端需要的接口");
}
}
對象適配器
/**
* 需要適配的類
*/
public class Adaptee {
public void specificRequest(){
System.out.println("系統(tǒng)原有的接口");
}
}
/**
* 客戶端需要的接口
*/
public interface Target {
/**
* 客戶端需要的接口
*/
void request();
}
/**
* 適配器霞丧,最終客戶需要的類
*/
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
/**
* 客戶端需要的接口
*/
@Override
public void request() {
System.out.println("客戶端需要的接口");
}
/**
* 系統(tǒng)原有的接口
*/
public void specificRequest() {
this.adaptee.specificRequest();
}
}