在軟體開發中,我們經常會遇到這樣的情況:我們需要使用一個現有的類或者介面,但它與我們系統的目標介面不相容,而我們又不能修改它。這時候,我們該怎麼辦呢?大多數情況下我們都可以使用適配器模式來解決這個問題,**本文將從以下四個方面講解適配器模式**。 - 簡介 - 優缺點 - 應用場景 - Java 代 ...
在軟體開發中,我們經常會遇到這樣的情況:我們需要使用一個現有的類或者介面,但它與我們系統的目標介面不相容,而我們又不能修改它。這時候,我們該怎麼辦呢?大多數情況下我們都可以使用適配器模式來解決這個問題,本文將從以下四個方面講解適配器模式。
- 簡介
- 優缺點
- 應用場景
- Java 代碼示例
簡介
適配器模式(Adapter Pattern)是一種結構型設計模式,它可以將一個介面轉換成客戶端所期待的另一個介面,從而使原本由於介面不相容而不能一起工作的類可以一起工作。適配器模式也稱為包裝器模式(Wrapper Pattern),因為它通過一個包裝類(即適配器)來包裝不相容的介面,並提供統一的目標介面。適配器模式可以在運行時根據需要選擇不同的適配器來適配不同的被適配者。
對象適配器模式的各角色定義如下。
- Target(目標介面):客戶端要使用的目標介面標準,對應下文中的三相插孔介面 TriplePin。
- Adapter(適配器):實現了目標介面,負責適配(轉換)被適配者的介面 specificRequest()為目標介面 request(),對應本章下文中的電視機專屬適配器類 TriplePinAdapter。
- Adaptee(被適配者):被適配者的介面標準,目前不能相容目標介面的問題介面,可以有多種實現類,對應下文中的兩相插孔介面 DualPin。
- Client(客戶端):目標介面的使用者。
推薦博主開源的 H5 商城項目waynboot-mall,這是一套全部開源的微商城項目,包含三個項目:運營後臺、H5 商城前臺和服務端介面。實現了商城所需的首頁展示、商品分類、商品詳情、商品 sku、分詞搜索、購物車、結算下單、支付寶/微信支付、收單評論以及完善的後臺管理等一系列功能。 技術上基於最新得 Springboot3.0、jdk17,整合了 MySql、Redis、RabbitMQ、ElasticSearch 等常用中間件。分模塊設計、簡潔易維護,歡迎大家點個 star、關註博主。
github 地址:https://github.com/wayn111/waynboot-mall
優缺點
適配器模式的優點有:
- 適配器模式可以增強程式的可擴展性,通過使用適配器,可以在不修改原有代碼的基礎上引入新的功能或者介面。
- 適配器模式可以提高類的復用性,通過使用適配器,可以將已有的類或者介面重新組合和封裝,使其符合新的需求。
- 適配器模式可以增加類的透明度,通過使用適配器,客戶端只需要關註目標介面,而無需瞭解被適配者的具體實現。
- 適配器模式可以靈活地切換不同的被適配者,通過使用不同的適配器,可以動態地選擇不同的被適配者來滿足不同的場景。
適配器模式的缺點有:
- 適配器模式會增加系統的複雜性,過多地使用適配器會使系統變得零亂和難以理解。
- 適配器模式可能會降低系統的性能,因為每次調用目標介面時都需要經過適配器的轉換。
- 適配器模式可能會違反開閉原則,如果目標介面發生變化,則需要修改所有的適配器類。
應用場景
適配器模式適用於以下場景:
- 當需要在一個已有系統中引入新的功能或者介面時,它與系統的目標介面不相容,但又不能修改原有代碼時,可以使用適配器模式。例如在一個資料庫操作系統中,如果想要支持多種類型的資料庫源,但系統只提供了一個固定類型資料庫源的操作介面時,可以使用一個資料庫源操作適配器來將不同類型資料庫源轉換成統一類型資料庫源。
- 當需要在多個獨立開發的系統或者組件之間進行協作時,但由於各自採用了不同的介面或者協議時,可以使用適配器模式。例如在一個分散式服務系統中,如果想要讓不同語言編寫的服務之間進行通信和調用,但各自採用了不同的通信協議和數據格式時,可以使用一個服務通信適配器來將不同協議和數據格式轉換成統一協議和數據格式。
Java 代碼示例
舉一個生活中常見的實例,我們新買了一臺電視機,其電源插頭是兩相的,不巧的是牆上的插孔卻是三相的,這時電視機便無法通電使用,我們以代碼來重現這個場景。
- 定義目標介面:三相插口 TriplePin,其中 3 個參數 l、n、e 分別對應火線(live)、零線(null)和地線(earth)。
public interface TriplePin {
public void electrify(int l, int n, int e);
}
- 定義被適配者介面:兩項插口 DualPin,可以看到參數中缺少了地線 e 參數。
public interface DualPin {
public void electrify(int l, int n);
}
- 添加被適配者介面具體實現類:TV,可以看到 TV 實現的是兩相介面,所在無法直接在三項介面中使用。
public class TV implements DualPin {
@Override
public void electrify(int l, int n) {
System.out.println("火線通電:" + l + ",零線通電:" + n);
System.out.println("電視開機");
}
}
- 定義適配器類:三項介面適配器 TriplePinAdapter,實現了三項介面並且包含兩項介面屬性,在 electrify 方法中調用被適配設備的兩插通電方法,忽略地線參數 e,以此來完成三項介面對兩項介面的相容。
這也就意味著 TriplePinAdapter 類能幫助我們將 TV 類與三項介面相容。
public class TriplePinAdapter implements TriplePin {
private DualPin dualPin;
public TriplePinAdapter(DualPin dualPin) {
this.dualPin = dualPin;
}
@Override
public void electrify(int l, int n, int e) {
// 調用被適配設備的兩插通電方法,忽略地線參數e
dualPin.electrify(l, n);
}
}
- 定義客戶端類
public class Client {
public static void main(String[] args) {
DualPin dualPinDevice = new TV();
TriplePin triplePinDevice = new TriplePinAdapter(dualPinDevice);
triplePinDevice.electrify(1, 0, -1);
}
}
輸出結果如下:
火線通電:1,零線通電:0
電視開機
總結
通過利用適配器模式對系統進行擴展後,我們就不必再為解決相容性問題去暴力修改類介面了,轉而通過適配器,以更為優雅、巧妙的方式將兩側“對立”的介面“整合”在一起,順利化解雙方難以調和的矛盾,最終使它們順利接通。
關註公眾號【waynblog】每周分享技術乾貨、開源項目、實戰經驗、國外優質文章翻譯等,您的關註將是我的更新動力!