設(shè)計(jì)模式-適配器模式

一 概述

定義:適配器模式將某個類的接口轉(zhuǎn)換成客戶端期望的另一個接口表示,主的目的是兼容性,讓原本因接口不匹配不能一起工作的兩個類可以協(xié)同工作。其別名為包裝器(Wrapper)。

屬于結(jié)構(gòu)型模式

主要分為三類:類適配器模式、對象的適配器模式、接口的適配器模式。

本文定義:

需要被適配的類、接口、對象(我們有的),簡稱src(source)

最終需要的輸出(我們想要的),簡稱dst(destination,即Target)

適配器稱之為Adapter。

一句話描述適配器模式的感覺:src->Adapter->dst,即src以某種形式(三種形式分別對應(yīng)三種適配器模式)給到Adapter里,最終轉(zhuǎn)化成了dst。

拿我們Android開發(fā)最熟悉的展示列表數(shù)據(jù)的三大控件:ListView,GridView,RecyclerView的Adapter來說,它們?nèi)齻€控件需要的是View(dst),而我們有的一般是datas(src),所以適配器Adapter就是完成了數(shù)據(jù)源datas 轉(zhuǎn)化成 ItemView的工作。

帶入src->Adapter->dst中,即datas->Adapter->View.

使用場景:

1 系統(tǒng)需要使用現(xiàn)有的類,而這些類的接口不符合系統(tǒng)的需要。

2 想要建立一個可以重復(fù)使用的類,用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類,包括一些可能在將來引進(jìn)的類一起工作。

3 需要一個統(tǒng)一的輸出接口,而輸入端的類型不可預(yù)知。

二 類適配器模式:

一句話描述:Adapter類,通過繼承src類,實(shí)現(xiàn)dst 類接口,完成src->dst的適配。

別的文章都用生活中充電器的例子來講解適配器,的確,這是個極佳的舉例,本文也不能免俗:

充電器本身相當(dāng)于Adapter,220V交流電相當(dāng)于src,我們的目dst標(biāo)是5V直流電。

UserAdapter不僅實(shí)現(xiàn)了UserInterface接口,同時還繼承了UserInfo類。在實(shí)現(xiàn)接口的getName()和getTelNumber()方法中,分別調(diào)用了UserInfo類中的相應(yīng)方法并取得結(jié)果。由此可以滿足需求。在上述定義中,按照UserInterface、UserInfo和UserAdapter在場景中的目的不同,可以具體劃分成如下角色:

UserInterface:目標(biāo)角色——目標(biāo)接口,系統(tǒng)所期待實(shí)現(xiàn)的目標(biāo);

UserInfo:源角色——當(dāng)前已經(jīng)存在的原有的實(shí)現(xiàn)類,即將被適配的類;

UserAdapter:適配器角色——將原有實(shí)現(xiàn)裝換為目標(biāo)接口的實(shí)現(xiàn)。

簡單點(diǎn)說,適配器模式是指:定義一個類,將一個已經(jīng)存在的類,轉(zhuǎn)換成目標(biāo)接口所期望的行為形式。

在具體的實(shí)現(xiàn)過程中,又可以基于其實(shí)現(xiàn)層次是類層次還是對象層次,將其分為類適配器和對象適配器。如上所寫的是類適配器。

對象適配器使用組合代替繼承,將源角色視為適配器角色的屬性:

總體而言:適配器模式是指定義一個適配器類,將一個已經(jīng)存在的類,轉(zhuǎn)換成目標(biāo)接口所期望的行為形式。同時,一般來說,基于更多的推薦使用組合而不是繼承,因此,對象適配器可能使用更多。

類適配器和對象適配器的選擇

從實(shí)現(xiàn)上:類適配器使用對象繼承的方式,屬于靜態(tài)的定義方式。對象適配器使用對象組合的方式,屬于動態(tài)組合的方式;

從工作模式上:類適配器直接繼承了 Adaptee,使得適配器不能和 Adaptee 的子類一起工作。對象適配器允許一個 Adapter 和多個 Adaptee,包括 Adaptee 和它所有的子類一起工作;

從定義角度:類適配器可以重定義 Adaptee 的部分行為,相當(dāng)于子類覆蓋父類的部分實(shí)現(xiàn)方法。對象適配器要重定義 Adaptee 很困難;

從開發(fā)角度:類適配器僅僅引入了一個對象,并不需要額外的引用來間接得到 Adaptee。對象適配器需要額外的引用來間接得到 Adaptee。

總的來說,建議使用對象適配器方式。

適配器模式使用注意事項(xiàng)

充當(dāng)適配器角色的類就是:實(shí)現(xiàn)已有接口的抽象類;

為什么要用抽象類?此類是不要被實(shí)例化的。而只充當(dāng)適配器的角色,也就為其子類提供了一個共同的接口,但其子類又可以將精力只集中在其感興趣的地方。

適配器模式中被適配的接口 Adaptee 和適配成為的接口 Target 是沒有關(guān)聯(lián)的,Adaptee 和 Target 中的方法既可以是相同的,也可以是不同的。

適配器在適配的時候,可以適配多個 Apaptee,也就是說實(shí)現(xiàn)某個新的 Target 的功能的時候,需要調(diào)用多個模塊的功能,適配多個模塊的功能才能滿足新接口的要求。

適配器有一個潛在的問題,就是被適配的對象不再兼容 Adaptee 的接口,因?yàn)檫m配器只是實(shí)現(xiàn)了 Target 的接口。這導(dǎo)致并不是所有 Adaptee 對象可以被使用的地方都能是使用適配器,雙向適配器解決了這個問題。

優(yōu)點(diǎn)

適配器模式也是一種包裝模式,它與裝飾模式同樣具有包裝的功能,此外,對象適配器模式還具有委托的意思??偟膩碚f,適配器模式屬于補(bǔ)償模式,專用來在系統(tǒng)后期擴(kuò)展、修改時使用。

缺點(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)。

適配器模式應(yīng)用場景

在軟件開發(fā)中,也就是系統(tǒng)的數(shù)據(jù)和行為都正確,但接口不相符時,我們應(yīng)該考慮用適配器,目的是使控制范圍之外的一個原有對象與某個接口匹配。適配器模式主要應(yīng)用于希望復(fù)用一些現(xiàn)存的類,但是接口又與復(fù)用環(huán)境要求不一致的情況。比如在需要對早期代碼復(fù)用一些功能等應(yīng)用上很有實(shí)際價值。適用場景大致包含三類:

1、已經(jīng)存在的類的接口不符合我們的需求;

2、創(chuàng)建一個可以復(fù)用的類,使得該類可以與其他不相關(guān)的類或不可預(yù)見的類(即那些接口可能不一定兼容的類)協(xié)同工作;

3、在不對每一個都進(jìn)行子類化以匹配它們的接口的情況下,使用一些已經(jīng)存在的子類。

Java I/O 庫大量使用了適配器模式,例如 ByteArrayInputStream 是一個適配器類,它繼承了 InputStream 的接口,并且封裝了一個 byte 數(shù)組。換言之,它將一個 byte 數(shù)組的接口適配成 InputStream 流處理器的接口。

我們知道 Java 語言支持四種類型:Java 接口,Java 類,Java 數(shù)組,原始類型(即 int,float 等)。前三種是引用類型,類和數(shù)組的實(shí)例是對象,原始類型的值不是對象。也即,Java 語言的數(shù)組是像所有的其他對象一樣的對象,而不管數(shù)組中所存儲的元素類型是什么。這樣一來的話,ByteArrayInputStream 就符合適配器模式的描述,是一個對象形式的適配器類。FileInputStream 是一個適配器類。在 FileInputStream 繼承了 InputStrem 類型,同時持有一個對 FileDiscriptor 的引用。這是將一個 FileDiscriptor 對象適配成 InputStrem 類型的對象形式的適配器模式。

同樣地,在 OutputStream 類型中,所有的原始流處理器都是適配器類。ByteArrayOutputStream 繼承了 OutputStream 類型,同時持有一個對 byte 數(shù)組的引用。它一個 byte 數(shù)組的接口適配成 OutputString 類型的接口,因此也是一個對象形式的適配器模式的應(yīng)用。

FileOutputStream 繼承了 OutputStream 類型,同時持有一個對 FileDiscriptor 對象的引用。這是一個將 FileDiscriptor 接口適配成 OutputStream 接口形式的對象型適配器模式。

Reader 類型的原始流處理器都是適配器模式的應(yīng)用。StringReader 是一個適配器類,StringReader 類繼承了 Reader 類型,持有一個對 String 對象的引用。它將 String 的接口適配成 Reader 類型的接口。


Spring 中使用適配器模式的典型應(yīng)用

在 Spring 的 AOP 里通過使用的 Advice(通知)來增強(qiáng)被代理類的功能。Spring 實(shí)現(xiàn)這一 AOP 功能的原理就使用代理模式(1、JDK 動態(tài)代理。2、CGLib 字節(jié)碼生成技術(shù)代理。)對類進(jìn)行方法級別的切面增強(qiáng),即,生成被代理類的代理類,并在代理類的方法前,設(shè)置攔截器,通過執(zhí)行攔截器中的內(nèi)容增強(qiáng)了代理方法的功能,實(shí)現(xiàn)的面向切面編程。

Advice(通知)的類型有:BeforeAdvice、AfterReturningAdvice、ThrowSadvice 等。每個類型 Advice(通知)都有對應(yīng)的攔截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。Spring 需要將每個 Advice(通知)都封裝成對應(yīng)的攔截器類型,返回給容器,所以需要使用適配器模式對 Advice 進(jìn)行轉(zhuǎn)換。


http://www.ibm.com/developerworks/cn/java/j-lo-adapter-pattern/index.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容