Java設計模式之適配器模式詳解
一、定義
適配器模式(Adapter Pattern):結構型模式之一,將一個類的接口轉換成客戶希望的另一個接口。
Adapter模式使得原本由于接口不兼容而不能一起工作的哪些類可以一起工作。
二、UML類圖

三、角色職責
- 目標角色(Target):該角色定義把其他類轉換為何種接口,也就是我們的期望接口。
- 源角色(Adaptee):你想把誰轉換成目標角色,這個“誰”就是源角色,它是已經存在的、運行良好的類或對象。
- 適配器角色(Adapter):適配器模式的核心角色,其他兩個角色都是已經存在的角色,而適配器角色是需要新建立的,它的職責非常簡單:通過繼承或是類關聯(lián)的方式把源角色轉換為目標角色。
四、代碼實現(xiàn)
前言:舉個栗子,我今天買了機票,飛到香港迪士尼去游玩,晚上回到了酒店,想給我的筆記本電腦充電,但這時我發(fā)現(xiàn),香港的插座是英式三角插座,我的充電器插不進去。這時我們就可以使用適配器模式,進行適配。
- 類適配器:適配器通過類來實現(xiàn),以類來繼承和實現(xiàn)接口的方式,來獲取被適配類的信息并轉換輸出重寫到適配接口。
中式插座(源角色 Adaptee)
@AllArgsConstructor
@Data
public class ChineseStandard {
public String getChineseStandard() {
return "中式插座";
}
}英式插座(目標角色 Target)
public interface BritishStandard {
String getBritishStandard();
}插座適配器(適配器角色 Adapter)
public class StandardAdapter extends ChineseStandard implements BritishStandard {
@Override
public 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("充電失??!");
}
}
}測試類
public class AdapterTest {
public static void main(String[] args) {
// 充電成功!
new Notebook().charge(new StandardAdapter());
}
}- 對象適配器:通過實例對象(構造器傳遞)來實現(xiàn)適配器,而不是再用繼承,其余基本同類適配器。
我么們將插座適配器就行修改即可
@AllArgsConstructor
public class StandardAdapter implements BritishStandard {
private ChineseStandard chineseStandard;
@Override
public String getBritishStandard() {
return chineseStandard.getChineseStandard();
}
}測試類
public class AdapterTest {
public static void main(String[] args) {
// 充電成功!
new Notebook().charge(new StandardAdapter(new ChineseStandard()));
}
}如果我們的源目標接口中還有一些其他我們不需要的方法,我們并不想去實現(xiàn)它,我們就可以將適配器作為一個抽象類,當我們實現(xiàn)適配器抽象類的時候只要重寫我們需要的方法即可。這時候我們就用到了接口適配器。
- 接口適配器:當不需要全部實現(xiàn)接口提供的方法時,可先設計一個抽象類實現(xiàn)接口,并為該接口中每個方法提供一個默認實現(xiàn)(空方法),那么該抽象類的子類可有選擇地覆蓋父類的某些方法來實現(xiàn)需求。
英式插座(目標角色 Target)
public interface BritishStandard {
String getBritishStandard();
String getTypeC();
String getUSB();
}插座適配器(適配器角色 Adapter)
@AllArgsConstructor
public abstract class StandardAdapter extends ChineseStandard implements BritishStandard {
@Override
public String getBritishStandard() {
return null;
}
@Override
public String getTypeC() {
return null;
}
@Override
public String getUSB() {
return null;
}
}測試類
public class AdapterTest {
public static void main(String[] args) {
StandardAdapter standardAdapter= new StandardAdapter() {
@Override
public String getBritishStandard() {
return new ChineseStandard().getChineseStandard();
}
};
// 充電成功!
new Notebook().charge(standardAdapter);
}
}五、源碼分析
我們先來看一下Spring MVC的工作原理

- 瀏覽器發(fā)送請求到 控制器(DispatcherServlet)
- 控制器 根據請求地址, 到 HandlerMapping(處理器映射) 尋找對應的 Handler(處理器)
- HanldlerMapping 返回 找到的Handler
- DispatcherServlet 根據找到的Handler 找對應的HandlerAdaptor
- 執(zhí)行對應的Handler方法
- Handler 將執(zhí)行結果 和 要響應的視圖名 封裝成 ModelAndView 對象
- 控制器根據返回的 ViewName 找對應的ViewResolver (視圖解析ViewResolver 將 Model 渲染到 View 中
- 將渲染結果 返回給控制器
- 最終將結果響應給客戶端瀏覽器
可以看出Spring MVC中的適配主要執(zhí)行Controller的請求處理方法。在Spring MVC中,DispatcherServlet作為用戶,HandlerAdapter作為期望接口(目標角色 Target),Controller則為源角色(Adaptee)。Spring MVC中的Controller種類眾多,不同類型的Controller通過不同的方法來對請求進行處理。 我們首先看一下HandlerAdapter接口

Spring MVC提供的Controler如下。

Spring MVC提供的Adapter如下。

該接口的每一個Controller都有一個適配器與之對應,這樣的話,每自定義一個Controller需要定義一個實現(xiàn)HandlerAdapter的適配器。 我們進入DispatcherServlet類,查看是如何獲得適配器的。


當Spring容器啟動后,會將所有定義好的適配器對象存放在一個List集合中,當一個請求來臨時,DispatcherServlet會通過 handler的類型找到對應適配器,并將該適配器對象返回給用戶,然后就可以統(tǒng)一通過適配器的handle()方法來調用Controller中的用于處理請求的方法。通過適配器模式我們將所有的Controller統(tǒng)一交給 HandlerAdapter 處理,免去了寫大量的 if-else 語句對 Controller進行判斷,也更利于擴展新的Controller類型。
六、優(yōu)缺點分析
類適配器 優(yōu)點:可以根據需求重寫Adaptee類的方法,使得Adapter的靈活性增強了。 缺點:有一定局限性。因為類適配器需要繼承Target類,而Java是單繼承機制,所以要求Adaptee類必須是接口。
對象適配器 優(yōu)點:同一個Adapter可以把Adaptee類和他的子類都適配到目標接口。 缺點:需要重新定義Adaptee行為時,需要重新定義Adaptee的子類,并將適配器組合適配。
接口適配器 優(yōu)點:可以靈活方便的選擇性重寫接口方法。 缺點:由于是匿名內部類的形式,所以不利于代碼復用。
七、適用場景
- 系統(tǒng)需要復用現(xiàn)有類,而該類的接口不符合系統(tǒng)的需求,可以使用適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
- 多個組件功能類似,但接口不統(tǒng)一且可能會經常切換時,可使用適配器模式,使得客戶端可以以統(tǒng)一的接口使用它們。
八、總結
適配器模式將現(xiàn)有接口轉化為客戶類所期望的接口,實現(xiàn)了對現(xiàn)有類的復用,它是一種使用頻率非常高的設計模式,在軟件開發(fā)中得以廣泛應用,Spring等開源框架、驅動程序設計(如JDBC中的數據庫驅動程序)中也都使用了適配器模式。
到此這篇關于Java設計模式之適配器模式詳解的文章就介紹到這了,更多相關Java適配器模式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
idea使用war以及war exploded的區(qū)別說明
本文詳細解析了war與warexploded兩種部署方式的差異及步驟,war方式是先打包成war包,再部署到服務器上;warexploded方式是直接把文件夾、class文件等移到Tomcat上部署,支持熱部署,開發(fā)時常用,文章分別列出了warexploded模式和war包形式的具體操作步驟2024-10-10
java代碼實現(xiàn)mysql分表操作(用戶行為記錄)
這篇文章主要介紹了java代碼實現(xiàn)mysql分表操作(用戶行為記錄),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Spring Boot中Elasticsearch的連接配置原理與使用詳解
在Spring Boot中,我們可以通過Elasticsearch實現(xiàn)對數據的搜索和分析,本文將介紹Spring Boot中Elasticsearch的連接配置、原理和使用方法,感興趣的可以了解一下2023-09-09
Springboot如何實現(xiàn)Web系統(tǒng)License授權認證
這篇文章主要介紹了Springboot如何實現(xiàn)Web系統(tǒng)License授權認證,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-05-05
SpringMVC 使用JSR-303進行校驗 @Valid示例
本篇文章主要介紹了SpringMVC 使用JSR-303進行校驗 @Valid示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02
Java實現(xiàn)創(chuàng)建運行時類的對象操作示例
這篇文章主要介紹了Java實現(xiàn)創(chuàng)建運行時類的對象操作,結合實例形式分析了Java動態(tài)創(chuàng)建對象的原理與相關實現(xiàn)技巧,需要的朋友可以參考下2018-08-08

