描述
????適配器模式把一個(gè)類(lèi)的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無(wú)法在一起工作的兩個(gè)類(lèi)能夠在一起工作。
簡(jiǎn)介
????適配器模式有類(lèi)的適配器模式和對(duì)象的適配器模式兩種不同的形式。

類(lèi)適配器模式
????類(lèi)的適配器模式通過(guò)繼承方式把適配的類(lèi)的API轉(zhuǎn)換成為目標(biāo)類(lèi)的API。Adapter與Adaptee是繼承關(guān)系。

對(duì)象適配器模式
????對(duì)象的適配器模式通過(guò)組合方式把適配的類(lèi)的API轉(zhuǎn)換成為目標(biāo)類(lèi)的API。Adapter與Adaptee是組合關(guān)系。
角色
- Target(目標(biāo)抽象類(lèi)):目標(biāo)抽象類(lèi)定義客戶所需的接口,可以是一個(gè)抽象類(lèi)或接口,也可以是具體類(lèi)。
- Adapter(適配器類(lèi)):它可以調(diào)用另一個(gè)接口,作為一個(gè)轉(zhuǎn)換器,對(duì)Adaptee和Target進(jìn)行適配。它是適配器模式的核心。
- Adaptee(適配者類(lèi)):適配者即被適配的角色,它定義了一個(gè)已經(jīng)存在的接口,這個(gè)接口需要適配,適配者類(lèi)包好了客戶希望的業(yè)務(wù)方法。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 將目標(biāo)類(lèi)和適配者類(lèi)解耦,通過(guò)引入一個(gè)適配器類(lèi)來(lái)重用現(xiàn)有的適配者類(lèi),無(wú)需修改原有結(jié)構(gòu)。
- 增加了類(lèi)的透明性和復(fù)用性,將具體的業(yè)務(wù)實(shí)現(xiàn)過(guò)程封裝在適配者類(lèi)中,對(duì)于客戶端類(lèi)而言是透明的,而且提高了適配者的復(fù)用性,同一適配者類(lèi)可以在多個(gè)不同的系統(tǒng)中復(fù)用。
- 靈活性和擴(kuò)展性都非常好,通過(guò)使用配置文件,可以很方便的更換適配器,也可以在不修改原有代碼的基礎(chǔ)上增加新的適配器,完全復(fù)合開(kāi)閉原則。
缺點(diǎn)
- 過(guò)多地使用適配器,會(huì)讓系統(tǒng)非常零亂,不易整體進(jìn)行把握。
- 由于 JAVA 至多繼承一個(gè)類(lèi),所以至多只能適配一個(gè)適配者類(lèi),而且目標(biāo)類(lèi)必須是抽象類(lèi),有一定的局限性。
使用場(chǎng)景
- 系統(tǒng)需要使用一些現(xiàn)有的類(lèi),而這些類(lèi)的接口不符合系統(tǒng)的需要,甚至沒(méi)有這些類(lèi)的源代碼。
- 創(chuàng)建一個(gè)可以重復(fù)使用的類(lèi),用于和一些彼此之間沒(méi)有太大關(guān)聯(lián)的類(lèi),包括一些可能在將來(lái)引進(jìn)的類(lèi)一起工作。
類(lèi)適配器和對(duì)象適配器的權(quán)衡
- 類(lèi)適配器使用對(duì)象繼承的方式,是靜態(tài)的定義方式;而對(duì)象適配器使用對(duì)象組合的方式,是動(dòng)態(tài)組合的方式。
- 對(duì)于類(lèi)適配器,由于適配器直接繼承了Adaptee,使得適配器不能和Adaptee的子類(lèi)一起工作,因?yàn)槔^承是靜態(tài)的關(guān)系,當(dāng)適配器繼承了Adaptee后,就不可能再去處理 Adaptee的子類(lèi)了。而對(duì)于對(duì)象適配器,一個(gè)適配器可以把多種不同的源適配到同一個(gè)目標(biāo)。換言之,同一個(gè)適配器可以把源類(lèi)和它的子類(lèi)都適配到目標(biāo)接口。因?yàn)閷?duì)象適配器采用的是對(duì)象組合的關(guān)系,只要對(duì)象類(lèi)型正確,是不是子類(lèi)都無(wú)所謂。
- 對(duì)于類(lèi)適配器,適配器可以重定義Adaptee的部分行為,相當(dāng)于子類(lèi)覆蓋父類(lèi)的部分實(shí)現(xiàn)方法。而對(duì)于對(duì)象適配器,要重定義Adaptee的行為比較困難,這種情況下,需要定義Adaptee的子類(lèi)來(lái)實(shí)現(xiàn)重定義,然后讓適配器組合子類(lèi)。雖然重定義Adaptee的行為比較困難,但是想要增加一些新的行為則方便的很,而且新增加的行為可同時(shí)適用于所有的源。
- 對(duì)于類(lèi)適配器,僅僅引入了一個(gè)對(duì)象,并不需要額外的引用來(lái)間接得到Adaptee。而對(duì)于對(duì)象適配器,需要額外的引用來(lái)間接得到Adaptee。
????建議盡量使用對(duì)象適配器的實(shí)現(xiàn)方式,多用合成/聚合、少用繼承。當(dāng)然,具體問(wèn)題具體分析,根據(jù)需要來(lái)選用實(shí)現(xiàn)方式,最適合的才是最好的。
示例
類(lèi)適配器
/**
* 需要適配的類(lèi)
*/
public class Adaptee {
public void specificRequest(){
System.out.println("系統(tǒng)原有的接口");
}
}
/**
* 客戶端需要的接口
*/
public interface Target {
/**
* 客戶端需要的接口
*/
void request();
}
/**
* 適配器,最終客戶需要的類(lèi)
*/
public class Adapter extends Adaptee implements Target{
/**
* 客戶端需要的接口
*/
@Override
public void request() {
System.out.println("客戶端需要的接口");
}
}
對(duì)象適配器
/**
* 需要適配的類(lèi)
*/
public class Adaptee {
public void specificRequest(){
System.out.println("系統(tǒng)原有的接口");
}
}
/**
* 客戶端需要的接口
*/
public interface Target {
/**
* 客戶端需要的接口
*/
void request();
}
/**
* 適配器,最終客戶需要的類(lèi)
*/
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();
}
}