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

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

定義

適配器模式(Adapter Pattern)又叫做變壓器模式,它的功能是將一個類的接口變成客戶端所期望的另一種接口,從而使原本因接口不匹配而導(dǎo)致無法在一起工作的兩個類能夠一起工作.

屬于結(jié)構(gòu)型設(shè)計模式.

也就是說,當(dāng)前系統(tǒng)存在兩種接口A和B,客戶只支持訪問A接口,但是當(dāng)前系統(tǒng)沒有A接口對象,但是有B接口對象,但客戶無法識別B接口,因此需要通過一個適配器C,將B接口內(nèi)容轉(zhuǎn)換成A接口,從而使得客戶能夠從A接口獲取得到B接口內(nèi)容.

在軟件開發(fā)中,基本上 任何問題都可以通過增加一個中間層進(jìn)行解決.適配器模式就是一個中間層.綜上,適配器模式其實起著轉(zhuǎn)化/委托的作用,將一種接口轉(zhuǎn)化為另一種符合需求的接口.

適配器模式一般包含3種角色:目標(biāo)角色、源角色、適配器.

1、目標(biāo)角色(Target):也就是我們期望的接口;

2、源角色(Adaptee):存在于系統(tǒng)中,內(nèi)容滿足客戶需求(需轉(zhuǎn)換),但借口不匹配的接口實例;

3、適配器(Adapter):將源角色(Adaptee)轉(zhuǎn)化為目標(biāo)角色(Target)的類實例.

適配器模式各角色之間的關(guān)系如下:

假設(shè)當(dāng)前系統(tǒng)中,客戶端需要訪問的是target接口,但target接口沒有一個實例符合需求,而Adaptee實例符合需求;但是客戶端無法直接使用Adaptee(接口不兼容);因此,我們需要一個適配器(Adapter)來進(jìn)行中轉(zhuǎn),讓Adaptee能轉(zhuǎn)化為Target接口形式.

適配器模式有3種形式:類適配器對象適配器、接口適配器.

類適配器

類適配器的原理就是通過繼承來實現(xiàn)適配器的功能.具體做法:讓Adapter實現(xiàn)Target接口,并且繼承Adaptee,這樣Adapter就具備Target和Adaptee等特性,就可以將兩者進(jìn)行轉(zhuǎn)化.

類適配器UML圖

下面我們以一個實例進(jìn)行講解,來看下該實例分別用類適配器、對象適配器和接口適配器是怎樣進(jìn)行代碼實現(xiàn).在中國民用電都是220V交流電,但我們手機(jī)使用的鋰電池使用的5V直流電.因此我們給手機(jī)充電時就需要使用電源適配器來進(jìn)行轉(zhuǎn)換.下面我們有代碼來還原這個生活場景,創(chuàng)建Adaptee角色,需要被轉(zhuǎn)換的對象AC220類,表示220V交流電:

Adaptee角色:需要被轉(zhuǎn)換的對象AC220類
Target角色:DC5接口,表示5V直流電的標(biāo)準(zhǔn)
Adapter角色:電源適配器PowerAdapter類
測試
運行結(jié)果

上面的案例中,通過增加PowerAdapter電源適配器,實現(xiàn)了兩者的兼容.

對象適配器

對象適配器的原理就是通過組合來實現(xiàn)適配器的功能.具體做法:讓Adapter實現(xiàn)Target接口,然后內(nèi)部持有Adaptee實例,然后在Target接口規(guī)定的方法那轉(zhuǎn)換Adaptee.

接口適配器:只實現(xiàn)target接口,并持有Adaptee對象.
測試方法

接口適配器

接口適配器的關(guān)注點與類適配器和對象適配器不太一樣,類適配器和對象適配器著重于系統(tǒng)存在一個角色(Adaptee)轉(zhuǎn)化成目標(biāo)接口(Target)所需內(nèi)容,而接口適配器的使用場景是解決接口方法過多,如果直接實現(xiàn)接口,那么類會多出許多空實現(xiàn)的方法,類顯得很臃腫.此時,使用接口適配器就能讓我們只實現(xiàn)我們需要的接口方法,目標(biāo)更清晰.

接口適配器的主要原理就是利用抽象類實現(xiàn)接口,并且空實現(xiàn)接口眾多方法.下面我們來接口適配器的源碼實現(xiàn),首先創(chuàng)建Target角色DC5類:

Target角色:DC5類(具有多個接口)
Adaptee角色:需要被轉(zhuǎn)換的對象AC220類
Adapter角色:PowerAdapter類.
測試代碼,運行結(jié)果同上.

重構(gòu)第三方登錄自由適配的業(yè)務(wù)場景

下面我們來一個實際的業(yè)務(wù)場景,利用適配器模式來解決實際問題.年紀(jì)稍微大一點的小伙伴一定經(jīng)歷過這樣一個過程,我們很早以前開發(fā)的老系統(tǒng)應(yīng)該都有登錄接口,但是隨著業(yè)務(wù)的發(fā)展和社會的進(jìn)步,單純的依賴用戶名密碼登錄顯然不能滿足用戶需求了.現(xiàn)在,我們大部分系統(tǒng)都支持多種登錄方式,如QQ登錄、微信登錄、手機(jī)登錄、微博登錄等等,同時保留用戶名密碼登錄方式.雖然登錄方式豐富了,但是登錄后的處理邏輯可以不必改,同樣是將登陸狀態(tài)保存到session,遵循開閉原則,我們開始創(chuàng)建統(tǒng)一的返回結(jié)果ResultMsg類:

創(chuàng)建統(tǒng)一的返回結(jié)果ResultMsg類
老系統(tǒng)的登錄邏輯PassportService

為了遵循開閉原則,老系統(tǒng)的代碼我們不會去修改.那么下面開啟代碼重構(gòu)之路,先創(chuàng)建Member類:

用戶信息類

運行非常穩(wěn)定的代碼我們不去改動,首先創(chuàng)建Target角色I(xiàn)PassportForThird接口:

Target角色I(xiàn)PassportForThird接口:支持了多種登錄方式

然后創(chuàng)建適配器Adapter角色實現(xiàn)兼容,創(chuàng)建一個新的類PassportForThirdAdapter繼承原來的邏輯:

Adapter角色:類PassportForThirdAdapter繼承原來的邏輯和新登錄方式
測試代碼

通過這么一個簡單的適配,完成了代碼兼容.當(dāng)然,我們代碼還可以更加優(yōu)雅,根據(jù)不同的登錄方式,創(chuàng)建不同的Adapter.首先,創(chuàng)建ILoginAdapter接口:

LoginAdapter接口

然后,創(chuàng)建一個抽象類AbstractAdapter繼承PassportService原有的功能,同時實現(xiàn)ILoginAdapter接口,然后分別實現(xiàn)不同的登錄適配.

抽象類
QQ登錄LoginForQQAdapter
手機(jī)登錄:LoginForTelAdapter
Token自動登錄:LoginForTokenAdapter
微信登錄:LoginForWechatAdapter

然后,創(chuàng)建適配器PassportForThirdAdapter類,實現(xiàn)目標(biāo)接口IPassportForThird完成兼容,

適配器PassportForThirdAdapter類
測試代碼

最后我們看一下類圖:


UML圖(PS:mac本對uml工具支持真的有限啊,哪個大佬給推薦個好用的建模工具,謝過啦~)

至此,我們在遵循開閉原則的前提下,完整地實現(xiàn)了一個兼容多平臺登錄的業(yè)務(wù)場景.當(dāng)然,我們目前的這個設(shè)計也并不完美,僅供參考,感興趣的小伙伴們可以繼續(xù)完善這段代碼.例如適配器中的參數(shù)目前是寫死成String的,改為Object[]會更合理.

學(xué)習(xí)到這里,相信小伙伴們會有一個疑問:適配器模式跟策略模式好像區(qū)別不大?在這里我要強(qiáng)調(diào)一下,適配器模式主要解決的是功能兼容問題,單場景適配大家肯定不會和策略模式有對比.但多場景適配大家容易產(chǎn)生聯(lián)想和混淆.其實,大家有沒有發(fā)現(xiàn)一個細(xì)節(jié),我給每個適配器都加上了一個support()方法用來判斷是否兼容,support()方法的參數(shù)也是Object的,而support來自于接口.適配器內(nèi)的邏輯并不依賴于接口,我們完全可以講ILoginAdapter接口去掉.而加上接口,只是為了代碼規(guī)范.上面的代碼可以說是策略模式、簡單工廠和適配器模式的綜合運用.

適配器模式在源碼中的體現(xiàn)

Spring中適配器模式也應(yīng)用的非常廣泛,例如:SpringAOP中的AdvisorAdapter類,它有三個實現(xiàn)類MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter和ThrowsAdviceAdapter,先來看頂層接口AdvisorAdapter的源代碼:

AdvisorAdapter接口

再看MethodBeforeAdviceAdapter類:

MethodBeforeAdviceAdapter類
AfterReturningAdviceAdapter類

剩余的那個類就不貼了,Spring會根據(jù)不同的AOP配置來確定使用對應(yīng)的Advice,跟策略模式不同的是:策略模式一個方法可以同時擁有多個Advice.

擴(kuò)展:SpringMVC中的HandlerAdapter類也是一個適配器模式的應(yīng)用實例.

適用場景

1、已經(jīng)存在的類,它的方法和需求不匹配(方法結(jié)果相同或相似)的情況.

2、適配器模式不是軟件設(shè)計階段考慮的設(shè)計模式,是隨著軟件維護(hù),由于不同產(chǎn)品、不同廠家造成功能類似而接口不相同情況下的解決方案.

生活中也存在非常多的應(yīng)用場景,例如電源轉(zhuǎn)換插頭、手機(jī)充電轉(zhuǎn)換頭,顯示器轉(zhuǎn)接頭等.

優(yōu)點

1、能提高類的透明性和復(fù)用性,現(xiàn)有的類復(fù)用但不需要改變;

2、目標(biāo)類和適配器類解耦,提高程序的擴(kuò)展性;

3、在很多業(yè)務(wù)場景中符合開閉原則.

缺點

1、適配器編寫過程需要全面考慮,可能會增加系統(tǒng)的復(fù)雜度;

2、增加代碼閱讀難度,降低代碼可讀性,過多使用適配器會使系統(tǒng)代碼變得凌亂.

適配器模式和裝飾器模式對比

裝飾器是一種非常特別的適配器
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容