概述
適配器模式把一個類的接口變換成客戶端所期待的另一種接口辆苔,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作挤巡。
適配器模式的用途
用電器做例子,筆記本電腦的插頭一般都是三相的,即除了陽極绵患、陰極外,還有一個地極悟耘。而有些地方的電源插座卻只有兩極落蝙,沒有地極。電源插座與筆記本電腦的電源插頭不匹配使得筆記本電腦無法使用。這時(shí)候一個三相到兩相的轉(zhuǎn)換器(適配器)就能解決此問題筏勒,而這正像是本模式所做的事情移迫。
適配器模式的結(jié)構(gòu)
適配器模式有類的適配器模式和對象的適配器模式兩種不同的形式。
類適配器模式
類的適配器模式把適配的類的API轉(zhuǎn)換成為目標(biāo)類的API管行。
在上圖中可以看出厨埋,Adaptee類并沒有sampleOperation2()方法,而客戶端則期待這個方法病瞳。為使客戶端能夠使用Adaptee類揽咕,提供一個中間環(huán)節(jié),即類Adapter套菜,把Adaptee的API與Target類的API銜接起來亲善。Adapter與Adaptee是繼承關(guān)系,這決定了這個適配器模式是類的
模式所涉及的角色有:
1.目標(biāo)(Target)角色:這就是所期待得到的接口逗柴。注意:由于這里討論的是類適配器模式蛹头,因此目標(biāo)不可以是類。
2.源(Adapee)角色:現(xiàn)在需要適配的接口戏溺。
3.適配器(Adaper)角色:適配器類是本模式的核心渣蜗。適配器把源接口轉(zhuǎn)換成目標(biāo)接口。顯然旷祸,這一角色不可以是接口耕拷,而必須是具體類。
源代碼
/**
* 目標(biāo)接口托享,或稱為標(biāo)準(zhǔn)接口
*/
public interface Target {
public void request();
}
/**
* 標(biāo)準(zhǔn)實(shí)現(xiàn)
*/
public class ConcreteTarget implements Target {
@Override
public void request() {
System.out.println("標(biāo)準(zhǔn)實(shí)現(xiàn)");
}
}
/**
* 已存在的骚烧、具有特殊功能、但不符合我們既有的標(biāo)準(zhǔn)接口的類
*/
public class Adaptee {
public void specificRequest() {
System.out.println("不標(biāo)準(zhǔn)實(shí)現(xiàn)闰围,特殊實(shí)現(xiàn)");
}
}
/**
* 適配器
*/
public class Adapter extends Adaptee implements Target {
/**
* 適配器繼承了被適配對象赃绊,同時(shí)實(shí)現(xiàn)了標(biāo)準(zhǔn)接口,可以重寫的方法中調(diào)用父類(Adaptee)的方法羡榴,完成適配
*/
@Override
public void request() {
super.specificRequest();
}
}
/**
* 客戶端
*/
public class Client {
public static void main(String[] args) {
//標(biāo)準(zhǔn)接口實(shí)現(xiàn)
Target target1 = new ConcreteTarget();
target1.request();
//通過適配器實(shí)現(xiàn)標(biāo)準(zhǔn)接口
Target target2 = new Adapter();
target2.request();
}
}
上面這種實(shí)現(xiàn)的適配器稱為類適配器碧查,因?yàn)?Adapter 類既繼承了 Adaptee (被適配類),也實(shí)現(xiàn)了 Target 接口(因?yàn)?Java不支持多繼承校仑,所以這樣來實(shí)現(xiàn))忠售,在 Client 類中我們可以根據(jù)需要選擇并創(chuàng)建任一種符合需求的子類,來實(shí)現(xiàn)具體功能
對象適配器模式
與類的適配器模式一樣迄沫,對象的適配器模式把被適配的類的API轉(zhuǎn)換成為目標(biāo)類的API稻扬,與類的適配器模式不同的是,對象的適配器模式不是使用繼承關(guān)系連接到Adaptee類邢滑,而是使用委派關(guān)系連接到Adaptee類腐螟。
從上圖可以看出,Adaptee類并沒有sampleOperation2()方法困后,而客戶端則期待這個方法乐纸。為使客戶端能夠使用Adaptee類,需要提供一個包裝(Wrapper)類Adapter摇予。這個包裝類包裝了一個Adaptee的實(shí)例汽绢,從而此包裝類能夠把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是委派關(guān)系侧戴,這決定了適配器模式是對象的宁昭。
源代碼
/**
* 適配器
*/
public class Adapter implements Target {
// 直接關(guān)聯(lián)被適配類
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
/**
* 使用委托的方式完成特殊功能
*/
@Override
public void request() {
adaptee.specificRequest();
}
}
public class Client {
public static void main(String[] args) {
//通過構(gòu)造方法傳入適配對象
Adapter adapter = new Adapter(new Adaptee());
adapter.request();
}
}
適配器模式的優(yōu)點(diǎn)
1.更好的復(fù)用性
系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要酗宋。那么通過適配器模式就可以讓這些功能得到更好的復(fù)用积仗。
2.更好的擴(kuò)展性
在實(shí)現(xiàn)適配器功能的時(shí)候,可以調(diào)用自己開發(fā)的功能蜕猫,從而自然地?cái)U(kuò)展系統(tǒng)的功能寂曹。
適配器模式的缺點(diǎn)
過多的使用適配器,會讓系統(tǒng)非常零亂回右,不易整體進(jìn)行把握隆圆。比如,明明看到調(diào)用的是A接口翔烁,其實(shí)內(nèi)部被適配成了B接口的實(shí)現(xiàn)渺氧,一個系統(tǒng)如果太多出現(xiàn)這種情況,無異于一場災(zāi)難蹬屹。因此如果不是很有必要侣背,可以不使用適配器,而是直接對系統(tǒng)進(jìn)行重構(gòu)哩治。
缺省適配模式
缺省適配(Default Adapter)模式為一個接口提供缺省實(shí)現(xiàn)秃踩,這樣子類型可以從這個缺省實(shí)現(xiàn)進(jìn)行擴(kuò)展,而不必從原有接口進(jìn)行擴(kuò)展业筏。作為適配器模式的一個特例憔杨,缺省是適配模式在JAVA語言中有著特殊的應(yīng)用。
在很多情況下蒜胖,必須讓一個具體類實(shí)現(xiàn)某一個接口消别,但是這個類又用不到接口所規(guī)定的所有的方法。通常的處理方法是台谢,這個具體類要實(shí)現(xiàn)所有的方法寻狂,那些有用的方法要有實(shí)現(xiàn),那些沒有用的方法也要有空的朋沮、平庸的實(shí)現(xiàn)蛇券。
這些空的方法是一種浪費(fèi),有時(shí)也是一種混亂。除非看過這些空方法的代碼纠亚,程序員可能會以為這些方法不是空的塘慕。即便他知道其中有一些方法是空的,也不一定知道哪些方法是空的蒂胞,哪些方法不是空的图呢,除非看過這些方法的源代碼或是文檔。
缺省適配模式可以很好的處理這一情況骗随「蛑可以設(shè)計(jì)一個抽象的適配器類實(shí)現(xiàn)接口,此抽象類要給接口所要求的每一種方法都提供一個空的方法鸿染。此抽象類可以使它的具體子類免于被迫實(shí)現(xiàn)空的方法指蚜。
缺省適配模式的結(jié)構(gòu)
缺省適配模式是一種“平庸”化的適配器模式。
源代碼
public interface AbstractService {
public void serviceOperation1();
public int serviceOperation2();
public String serviceOperation3();
}
public abstract class ServiceAdapter implements AbstractService{
@Override
public void serviceOperation1() {
}
@Override
public int serviceOperation2() {
return 0;
}
@Override
public String serviceOperation3() {
return null;
}
}
可以看到涨椒,接口AbstractService要求定義三個方法姚炕,分別是serviceOperation1()、serviceOperation2()丢烘、serviceOperation3()柱宦;而抽象適配器類ServiceAdapter則為這三種方法都提供了平庸的實(shí)現(xiàn)。因此播瞳,任何繼承自抽象類ServiceAdapter的具體類都可以選擇它所需要的方法實(shí)現(xiàn)掸刊,而不必理會其他的不需要的方法。
適配器模式的用意是要改變源的接口赢乓,以便于目標(biāo)接口相容忧侧。缺省適配的用意稍有不同,它是為了方便建立一個不平庸的適配器類而提供的一種平庸實(shí)現(xiàn)牌芋。
在任何時(shí)候蚓炬,如果不準(zhǔn)備實(shí)現(xiàn)一個接口的所有方法時(shí),就可以使用“缺省適配模式”制造一個抽象類躺屁,給出所有方法的平庸的具體實(shí)現(xiàn)肯夏。這樣,從這個抽象類再繼承下去的子類就不必實(shí)現(xiàn)所有的方法了犀暑。