適配器模式
- 類型: 結(jié)構(gòu)型
- 難度:入門級
更多設(shè)計(jì)模式小故事案例代碼詳解 >>點(diǎn)我!點(diǎn)我!點(diǎn)我!<< 設(shè)計(jì)模式忙芒,如此簡單~
別名
Wrapper (包裝)(適配器模式(Adapter Pattern)和裝飾器模式(Decorator Pattern)的統(tǒng)稱)
設(shè)計(jì)目的
將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口示弓。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
釋義
生活中的例子
你有一個(gè)張內(nèi)存卡呵萨,有一臺(tái)電腦奏属,你現(xiàn)在想要看內(nèi)存卡上的照片,想聽內(nèi)存卡上的歌潮峦,想看內(nèi)存卡上的電影囱皿,但是你直接插電腦上又插不上去,所以你需要一個(gè)適配器忱嘹,那就是讀卡器嘱腥。這樣你的內(nèi)存卡就可以在電腦上運(yùn)行了。
你的iphone x的手機(jī)拘悦,想要聽歌齿兔,但是耳機(jī)忘記帶了,所以和我來借,可是我是國產(chǎn)的OPPO分苇,所以你從包里拿出來一個(gè)轉(zhuǎn)換插頭添诉,讓耳機(jī)插到轉(zhuǎn)換插頭上,再插到手機(jī)上医寿,這個(gè)轉(zhuǎn)換插頭就是適配器栏赴。
侵華的日本鬼子當(dāng)年侵華無法和我們溝通,結(jié)果你猜怎么著靖秩,那個(gè)漢奸就是適配器须眷,他把日語轉(zhuǎn)成了中文,把中文轉(zhuǎn)成了日語盆偿。勿忘國恥柒爸!
簡單來講
適配器模式可以讓你在適配器中包裝一個(gè)與另一個(gè)對象不兼容的對象,使其兼容事扭。
將一個(gè)類的接口轉(zhuǎn)接成用戶所期待的捎稚。一個(gè)適配使得因接口不兼容而不能在一起工作的類能在一起工作,做法是將類自己的接口包裹在一個(gè)已存在的類中求橄。
代碼實(shí)例講解
有一個(gè)船長今野,只會(huì)使用劃艇,不會(huì)使用漁船罐农。
首先条霜,我們有接口RowingBoat
和FishingBoat
public interface RowingBoat {
void row();
}
public class FishingBoat {
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class);
public void sail() {
LOGGER.info("The fishing boat is sailing");
}
}
并且船長本身是會(huì)劃艇的,所以船長已經(jīng)實(shí)現(xiàn)了這個(gè)接口涵亏。
public class Captain implements RowingBoat {
private RowingBoat rowingBoat;
public Captain(RowingBoat rowingBoat) {
this.rowingBoat = rowingBoat;
}
@Override
public void row() {
rowingBoat.row();
}
}
現(xiàn)在來了一個(gè)海盜宰睡,并且只有漁船可以使用,我們的船長想要逃避海盜气筋,就只能使用漁船拆内。所以我們需要一個(gè)適配器來幫助船長來用他操作劃艇的技術(shù)來操作漁船。
public class FishingBoatAdapter implements RowingBoat {
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class);
private FishingBoat boat;
public FishingBoatAdapter() {
boat = new FishingBoat();
}
@Override
public void row() {
boat.sail();
}
}
現(xiàn)在宠默,船長既可以開著漁船逃避海盜了麸恍。
Captain captain = new Captain(new FishingBoatAdapter());
captain.row();
完整代碼傳送 >>>
使用契機(jī)
什么時(shí)候使用適配器模式?
- 你想使用現(xiàn)有的類搀矫,但是這個(gè)類的接口不符合你所需要的抹沪。
- 你現(xiàn)在想要?jiǎng)?chuàng)建一個(gè)類,用在一些彼此之間沒有太大關(guān)聯(lián)的類瓤球,包括一些以后將來引進(jìn)的類一起工作融欧。這些類不一定有一致的接口。
- 通過接口轉(zhuǎn)換卦羡,將一個(gè)類插入另一個(gè)類系中蹬癌。(比如老虎和飛禽权她,現(xiàn)在多了一個(gè)飛虎,在不增加實(shí)體的需求下逝薪,增加一個(gè)適配器隅要,在里面包容一個(gè)虎對象,實(shí)現(xiàn)飛的接口董济。)
- 大多數(shù)使用第三方庫的應(yīng)用程序使用適配器作為應(yīng)用程序和第三方庫之間的中間層挫鸽,以將應(yīng)用程序與庫解耦梭冠。如果必須使用另一個(gè)庫,則只需要為新庫添加適配器,而不必更改應(yīng)用程序代碼避消。
結(jié)論:
類適配器和對象適配器的區(qū)別
類適配器
- 通過提交到具體的需要適配的類來使適配器來適應(yīng)目標(biāo)類缕碎。 因此佛点,當(dāng)我們想要調(diào)整類及其所有子類時(shí)朽寞,類適配器將不起作用。
- 讓適配器覆蓋一些適配者的行為吹埠, 因?yàn)檫m配器是適配者的子類第步。
- 只需要引入一個(gè)對象,不需要其他的指針來間接的指向適配器缘琅。
- 適配器Adapter繼承我們的被適配者Adaptee粘都,并實(shí)現(xiàn)目標(biāo)接口。由于Java中是單繼承刷袍,所以這個(gè)適配器僅僅只能服務(wù)于所繼承的被適配者Adaptee
對象適配器
- 適配器實(shí)現(xiàn)我們的目標(biāo)接口翩隧,但是并不繼承需要被適配的類。而是通過在適配器的構(gòu)造函數(shù)中將需要被適配的類傳遞進(jìn)來從而進(jìn)行適配
- 讓一個(gè)適配器與許多適配者一起工作 - 即適配者本身及其所有子類(如果有的話)呻纹。 適配器還可以立即向所有適配者添加功能堆生。
- 覆蓋適配者Adaptee的方法復(fù)雜困難,需要適配器使用一個(gè)適配者的子類雷酪,不能直接引用適配者淑仆。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 可以讓任何兩個(gè)沒有關(guān)聯(lián)的類一起運(yùn)行。
- 提高了類的復(fù)用太闺。
- 增加了類的透明度。
- 靈活性好嘁圈。
缺點(diǎn):
- 過多地使用適配器省骂,會(huì)讓系統(tǒng)非常零亂,不易整體進(jìn)行把握最住。比如钞澳,明明看到調(diào)用的是 A 接口,其實(shí)內(nèi)部被適配成了 B 接口的實(shí)現(xiàn)涨缚,一個(gè)系統(tǒng)如果太多出現(xiàn)這種情況轧粟,無異于一場災(zāi)難。因此如果不是很有必要,可以不使用適配器兰吟,而是直接對系統(tǒng)進(jìn)行重構(gòu)通惫。
- 由于 JAVA 至多繼承一個(gè)類,所以至多只能適配一個(gè)適配者類混蔼,而且目標(biāo)類必須是抽象類履腋。
jdk中使用到此模式的地方
- java.util.Arrays#asList()
- java.util.Collections#list()
- java.util.Collections#enumeration()
- javax.xml.bind.annotation.adapters.XMLAdapter