适配器模式(Adapter Pattern)
一、定義
適配器模式(Adapter Pattern):結(jié)構(gòu)型模式之一,將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另一個(gè)接口。Adapter模式使得原本由于接口不兼容而不能一起工作的哪些類可以一起工作。
二、UML類圖
三、角色職責(zé)
- 目標(biāo)角色(Target):該角色定義把其他類轉(zhuǎn)換為何種接口,也就是我們的期望接口。
- 源角色(Adaptee):你想把誰轉(zhuǎn)換成目標(biāo)角色,這個(gè)“誰”就是源角色,它是已經(jīng)存在的、運(yùn)行良好的類或?qū)ο蟆?/li>
- 適配器角色(Adapter):適配器模式的核心角色,其他兩個(gè)角色都是已經(jīng)存在的角色,而適配器角色是需要新建立的,它的職責(zé)非常簡(jiǎn)單:通過繼承或是類關(guān)聯(lián)的方式把源角色轉(zhuǎn)換為目標(biāo)角色。
四、代碼實(shí)現(xiàn)
前言:舉個(gè)栗子,我今天買了機(jī)票,飛到香港迪士尼去游玩,晚上回到了酒店,想給我的筆記本電腦充電,但這時(shí)我發(fā)現(xiàn),香港的插座是英式三角插座,我的充電器插不進(jìn)去。這時(shí)我們就可以使用適配器模式,進(jìn)行適配。
-
類適配器:適配器通過類來實(shí)現(xiàn),以類來繼承和實(shí)現(xiàn)接口的方式,來獲取被適配類的信息并轉(zhuǎn)換輸出重寫到適配接口。
中式插座(目標(biāo)角色 Target)
@AllArgsConstructor @Data public class ChineseStandard {public String getChineseStandard() {return "中式插座";} }英式插座(源角色 Adaptee)
public interface BritishStandard {String getBritishStandard(); }插座適配器(適配器角色 Adapter)
public class StandardAdapter extends ChineseStandard implements BritishStandard {@Overridepublic String getBritishStandard() {return this.getChineseStandard();} }筆記本電腦(客戶端 Client)
public class Notebook {public void charge(BritishStandard britishStandard) {if ("中式插座".equals(britishStandard.getBritishStandard())) {System.out.println("充電成功!");} else {System.out.println("充電失敗!");}} }測(cè)試類
public class AdapterTest {public static void main(String[] args) {// 充電成功!new Notebook().charge(new StandardAdapter());} } -
對(duì)象適配器:通過實(shí)例對(duì)象(構(gòu)造器傳遞)來實(shí)現(xiàn)適配器,而不是再用繼承,其余基本同類適配器。
我么們將插座適配器就行修改即可
@AllArgsConstructor public class StandardAdapter implements BritishStandard {private ChineseStandard chineseStandard;@Overridepublic String getBritishStandard() {return chineseStandard.getChineseStandard();} }測(cè)試類
public class AdapterTest {public static void main(String[] args) {// 充電成功!new Notebook().charge(new StandardAdapter(new ChineseStandard()));} }如果我們的源目標(biāo)接口中還有一些其他我們不需要的方法,我們并不想去實(shí)現(xiàn)它,我們就可以將適配器作為一個(gè)抽象類,當(dāng)我們實(shí)現(xiàn)適配器抽象類的時(shí)候只要重寫我們需要的方法即可。這時(shí)候我們就用到了接口適配器。
-
接口適配器:當(dāng)不需要全部實(shí)現(xiàn)接口提供的方法時(shí),可先設(shè)計(jì)一個(gè)抽象類實(shí)現(xiàn)接口,并為該接口中每個(gè)方法提供一個(gè)默認(rèn)實(shí)現(xiàn)(空方法),那么該抽象類的子類可有選擇地覆蓋父類的某些方法來實(shí)現(xiàn)需求。
英式插座(源角色 Adaptee)
public interface BritishStandard {String getBritishStandard();String getTypeC();String getUSB(); }插座適配器(適配器角色 Adapter)
@AllArgsConstructor public abstract class StandardAdapter extends ChineseStandard implements BritishStandard {@Overridepublic String getBritishStandard() {return null;}@Overridepublic String getTypeC() {return null;}@Overridepublic String getUSB() {return null;} }測(cè)試類
public class AdapterTest {public static void main(String[] args) {StandardAdapter standardAdapter= new StandardAdapter() {@Overridepublic String getBritishStandard() {return new ChineseStandard().getChineseStandard();}};// 充電成功!new Notebook().charge(standardAdapter);} }
五、源碼分析
我們先來看一下Spring MVC的工作原理
可以看出Spring MVC中的適配主要執(zhí)行Controller的請(qǐng)求處理方法。在Spring MVC中,DispatcherServlet作為用戶,HandlerAdapter作為期望接口(目標(biāo)角色 Target),Controller則為源角色(Adaptee)。Spring MVC中的Controller種類眾多,不同類型的Controller通過不同的方法來對(duì)請(qǐng)求進(jìn)行處理。
我們首先看一下HandlerAdapter接口
Spring MVC提供的Controler如下。
Spring MVC提供的Adapter如下。
該接口的每一個(gè)Controller都有一個(gè)適配器與之對(duì)應(yīng),這樣的話,每自定義一個(gè)Controller需要定義一個(gè)實(shí)現(xiàn)HandlerAdapter的適配器。
我們進(jìn)入DispatcherServlet類,查看是如何獲得適配器的。
當(dāng)Spring容器啟動(dòng)后,會(huì)將所有定義好的適配器對(duì)象存放在一個(gè)List集合中,當(dāng)一個(gè)請(qǐng)求來臨時(shí),DispatcherServlet會(huì)通過 handler的類型找到對(duì)應(yīng)適配器,并將該適配器對(duì)象返回給用戶,然后就可以統(tǒng)一通過適配器的handle()方法來調(diào)用Controller中的用于處理請(qǐng)求的方法。通過適配器模式我們將所有的Controller統(tǒng)一交給 HandlerAdapter 處理,免去了寫大量的 if-else 語句對(duì) Controller進(jìn)行判斷,也更利于擴(kuò)展新的Controller類型。
六、優(yōu)缺點(diǎn)分析
類適配器
優(yōu)點(diǎn):可以根據(jù)需求重寫Adaptee類的方法,使得Adapter的靈活性增強(qiáng)了。
缺點(diǎn):有一定局限性。因?yàn)轭愡m配器需要繼承Target類,而Java是單繼承機(jī)制,所以要求Adaptee類必須是接口。
對(duì)象適配器
優(yōu)點(diǎn):同一個(gè)Adapter可以把Adaptee類和他的子類都適配到目標(biāo)接口。
缺點(diǎn):需要重新定義Adaptee行為時(shí),需要重新定義Adaptee的子類,并將適配器組合適配。
接口適配器
優(yōu)點(diǎn):可以靈活方便的選擇性重寫接口方法。
缺點(diǎn):由于是匿名內(nèi)部類的形式,所以不利于代碼復(fù)用。
七、適用場(chǎng)景
- 系統(tǒng)需要復(fù)用現(xiàn)有類,而該類的接口不符合系統(tǒng)的需求,可以使用適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
- 多個(gè)組件功能類似,但接口不統(tǒng)一且可能會(huì)經(jīng)常切換時(shí),可使用適配器模式,使得客戶端可以以統(tǒng)一的接口使用它們。
八、總結(jié)
適配器模式將現(xiàn)有接口轉(zhuǎn)化為客戶類所期望的接口,實(shí)現(xiàn)了對(duì)現(xiàn)有類的復(fù)用,它是一種使用頻率非常高的設(shè)計(jì)模式,在軟件開發(fā)中得以廣泛應(yīng)用,Spring等開源框架、驅(qū)動(dòng)程序設(shè)計(jì)(如JDBC中的數(shù)據(jù)庫驅(qū)動(dòng)程序)中也都使用了適配器模式。
總結(jié)
以上是生活随笔為你收集整理的适配器模式(Adapter Pattern)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: aes解密流程图_aes流程图(apqp
- 下一篇: Qt视频直播软件--项目实战(Day6)