適配器模式
說到適配器壳坪,小秋第一想到的是我們電腦的電源適配器舶得,它能夠?qū)?20v,110v等不同電壓轉(zhuǎn)換為我們電腦需要的電壓值供電腦使用,那么你知道適配器模式是怎樣實現(xiàn)的嗎爽蝴,下面就和小秋一起探索一下適配器的工作模式吧
定義
將一個類的接口轉(zhuǎn)換成客戶希望的另一個接口
動機
通常情況下沐批,客戶端可以通過目標(biāo)類的接口訪問它所提供的服務(wù)。有時蝎亚,現(xiàn)有的類可以滿足客戶類的功能需要九孩,但是它所提供的接口不一定是客戶類所期望的,這可能是因為現(xiàn)有類中方法名與目標(biāo)類中定義的方法名不一致等原因所導(dǎo)致的颖对。
組件
目標(biāo)(Target)角色:客戶端所期待得到的接口捻撑,
適配器(Adaper)角色:適配器類是本模式的核心。適配器把源接口轉(zhuǎn)換成目標(biāo)接口缤底。顯然顾患,這一角色不可以是接口,而必須是具體類个唧。
源(Adapee)角色被適配者:現(xiàn)在需要被適配的接口
分類
類適配器模式
定義
通過多重繼承將apdatee2接口與target接口進行匹配江解,將適配的類apdatee2的API轉(zhuǎn)換成為目標(biāo)類的API
結(jié)構(gòu)
優(yōu)點
適配器可以重定義Adaptee的部分行為,相當(dāng)于子類覆蓋父類的部分實現(xiàn)方法徙歼。
僅僅引入了一個對象犁河,并不需要額外的引用來間接得到Adaptee
缺點
由于適配器直接繼承了Adaptee鳖枕,使得適配器不能和Adaptee的子類一起工作,因為繼承是靜態(tài)的關(guān)系桨螺,當(dāng)適配器繼承了Adaptee后宾符,就不可能再去處理 Adaptee的子類了
對象的適配器模式
定義
被適配的類的API轉(zhuǎn)換成為目標(biāo)類的API,與類的適配器模式不同的是灭翔,對象的適配器模式不是使用繼承關(guān)系連接到Adaptee類而是使用委派關(guān)系連接到Adaptee類
結(jié)構(gòu)
優(yōu)點
一個適配器可以把多種不同的源適配到同一個目標(biāo)魏烫。換言之,同一個適配器可以把源類和它的子類都適配到目標(biāo)接口肝箱。因為對象適配器采用的是對象組合的關(guān)系哄褒,只要對象類型正確,是不是子類都無所謂煌张。
符合設(shè)計原則:多用合成/聚合呐赡、少用繼承,從而減少類之間的耦合
缺點
要重定義Adaptee的行為比較困難骏融,這種情況下链嘀,需要定義Adaptee的子類來實現(xiàn)重定義,然后讓適配器組合子類绎谦。雖然重定義Adaptee的行為比較困難管闷,但是想要增加一些新的行為則方便的很,而且新增加的行為可同時適用于所有的源
需要額外的引用來間接得到Adaptee窃肠。
目標(biāo)接口(客戶端調(diào)用的接口)
package adapter;
//目標(biāo)接口(客戶端需要使用的接口)
public interface Target {
//客戶端需要請求處理的方法
public void request();
}
源接口(需要被適配的接口)
package adapter;
//源接口(已經(jīng)存在的接口)
//需要被轉(zhuǎn)換的對象
//這個接口需要重新配置以適應(yīng)目標(biāo)接口
public class Adaptee {
public void specifiRequest() {
System.out.println("源接口對象調(diào)用源接口中的方法");
}
}
適配器
package adapter;
public class Adapter implements Target {
//持有源接口對象
private Adaptee adaptee;
/**
* 構(gòu)造方法,傳入需要被適配的對象
* @param adaptee
*/
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
/**
* 重寫目標(biāo)接口的方法刷允,以適應(yīng)客戶端的需求
*/
@Override
public void request() {
//調(diào)用源接口的方法
System.out.println("適配器包裝源接口對象冤留,調(diào)用源接口的方法");
adaptee.specifiRequest();
}
}
客戶端
package adapter;
public class Client {
public static void main(String[] args){
//創(chuàng)建源對象(被適配的對象)
Adaptee adaptee = new Adaptee();
//利用源對象對象一個適配器對象,提供客戶端調(diào)用的方法
Adapter adapter = new Adapter(adaptee);
System.out.println("客戶端調(diào)用適配器中的方法");
adapter.request();
}
}
//客戶端調(diào)用適配器中的方法
//適配器包裝源接口對象树灶,調(diào)用源接口的方法
//源接口對象調(diào)用源接口中的方法
優(yōu)點
目標(biāo)類和適配者類解耦纤怒,增加了類的透明性和復(fù)用性,同時系統(tǒng)的靈活性和擴展性都非常好天通,更換適配器或者增加新的適配器都非常方便泊窘,符合“開閉原則”
缺點
過多的使用適配器,會讓系統(tǒng)非常零亂像寒,不易整體進行把握烘豹。比如,明明看到調(diào)用的是A接口诺祸,其實內(nèi)部被適配成了B接口的實現(xiàn)
應(yīng)用案例
Java語言的數(shù)據(jù)庫連接工具JDBC携悯,JDBC給出一個客戶端通用的抽象接口,每一個具體數(shù)據(jù)庫引擎(如SQL Server筷笨、Oracle憔鬼、MySQL等)的JDBC驅(qū)動軟件都是一個介于JDBC接口和數(shù)據(jù)庫引擎接口之間的適配器軟件
應(yīng)用場景
后期維護龟劲,由于不同的廠家不同的產(chǎn)品以及不同的開發(fā)人員
調(diào)用第三方組件
雙方都不太容易修改的時候
用途
想要復(fù)用一些現(xiàn)有的類,但是接口與復(fù)用環(huán)境要求不一致
適配器模式與裝飾模式的對比
UML圖
-
適配器模式
-
裝飾器模式
內(nèi)容
-
適配器模式
持有的是待適配的對象轴或,實現(xiàn)的是目標(biāo)接口昌跌,兩個不一樣
擴展了待適配類新的功能
適配器模式拓展了新的功能
-
裝飾器模式
持有對象和繼承的對象一般是同一個類或接口
裝飾模式中裝飾過的類力求與原來對外接口一致,這使得在調(diào)用方看來照雁,裝飾過后的類與之前沒有什么區(qū)別蚕愤,只是某一方面功能增強了
裝飾模式增強了原有功能
總結(jié)
'裝飾模式與適配器模式是不沖突的,可以既增強原有功能囊榜,又添加全新的功能审胸。
最后附上一張適配器的概覽圖