适配器模式(为被封装对象提供不同的接口)
一、適配器講解
說到適配器,我們最熟悉的莫過于電源適配器了,也就是手機的充電頭。它就是適配器模式的一個應用。試想一下,你有一條連接電腦和手機的 USB 數據線,連接電腦的一端從電腦接口處接收 5V 的電壓,連接手機的一端向手機輸出 5V 的電壓,并且他們工作良好。中國的家用電壓都是 220V,所以 USB 數據線不能直接拿來給手機充電,這時候我們有兩種方案:
如果你使用過早期的手機,就會知道以前的手機廠商采用的就是第一種方案:早期的手機充電器都是單獨制作的,充電頭和充電線是連在一起的。現在的手機都采用了電源適配器加數據線的方案。這是生活中應用適配器模式的一個進步。
適配器模式:將一個類的接口轉換成客戶希望的另外一個接口,使得原本由于接口不兼容而不能一起工作的那些類能一起工作。適配的意思是適應、匹配。通俗地講,適配器模式適用于 有相關性但不兼容的結構,源接口通過一個中間件轉換后才可以適用于目標接口,這個轉換過程就是適配,這個中間件就稱之為適配器。家用電源和 USB 數據線有相關性:家用電源輸出電壓,USB 數據線輸入電壓。但兩個接口無法兼容,因為一個輸出 220V,一個輸入 5V,通過適配器將輸出 220V 轉換成輸出 5V 之后才可以一起工作。
二、代碼
讓我們用程序來模擬一下這個過程。首先,家庭電源提供 220V 的電壓: Java 實現
class HomeBattery { int supply() { // 家用電源提供一個 220V 的輸出電壓 return 220; } }USB 數據線只接收 5V 的充電電壓:
class USBLine { void charge(int volt) { // 如果電壓不是 5V,拋出異常 if (volt != 5) throw new IllegalArgumentException("只能接收 5V 電壓"); // 如果電壓是 5V,正常充電 System.out.println("正常充電"); } }先來看看適配之前,用戶如果直接用家庭電源給手機充電:
public class User { @Test public void chargeForPhone() { HomeBattery homeBattery = new HomeBattery(); int homeVolt = homeBattery.supply(); System.out.println("家庭電源提供的電壓是 " + homeVolt + "V");USBLine usbLine = new USBLine(); usbLine.charge(homeVolt); } }運行程序,輸出如下:
家庭電源提供的電壓是 220V java.lang.IllegalArgumentException: 只能接收 5V 電壓這時,我們加入電源適配器:
//可以理解為把A接口轉換為B接口class Adapter { int convert(int homeVolt) { // 適配過程:使用電阻、電容等器件將其降低為輸出 5V int chargeVolt = homeVolt - 215; return chargeVolt; } }然后,用戶再使用適配器將家庭電源提供的電壓轉換為充電電壓:
public class User { @Test public void chargeForPhone() { HomeBattery homeBattery = new HomeBattery(); int homeVolt = homeBattery.supply(); System.out.println("家庭電源提供的電壓是 " + homeVolt + "V"); Adapter adapter = new Adapter(); int chargeVolt = adapter.convert(homeVolt); System.out.println("使用適配器將家庭電壓轉換成了 " + chargeVolt + "V"); USBLine usbLine = new USBLine(); usbLine.charge(chargeVolt); } }運行程序,輸出如下:
家庭電源提供的電壓是 220V 使用適配器將家庭電壓轉換成了 5V 正常充電這就是適配器模式。在我們日常的開發中經常會使用到各種各樣Adapter,都屬于適配器模式的應用。但適配器模式并不推薦多用。因為未雨綢繆好過亡羊補牢,如果事先能預防接口不同的問題,不匹配問題就不會發生,只有遇到源接口無法改變時,才應該考慮使用適配器。比如現代的電源插口中很多已經增加了專門的充電接口,讓我們不需要再使用適配器轉換接口,這又是社會的一個進步。
三、適配器模式適合應用場景
- 當你希望使用某個類, 但是其接口與其他代碼不兼容時, 可以使用適配器類。
- 適配器模式允許你創建一個中間層類, 其可作為代碼與遺留類、第三方類或提供怪異接口的類之間的轉換器。
- 如果您需要復用這樣一些類, 他們處于同一個繼承體系, 并且他們又有了額外的一些共同的方法,但是這些共同的方法不是所有在這一繼承體系中的子類所具有的共性。
- 你可以擴展每個子類, 將缺少的功能添加到新的子類中。 但是, 你必須在所有新子類中重復添加這些代碼, 這樣會使得代碼有壞味道。
將缺失功能添加到一個適配器類中是一種優雅得多的解決方案。 然后你可以將缺少功能的對象封裝在適配器中, 從而動態地獲取所需功能。如要這一點正常運作, 目標類必須要有通用接口, 適配器的成員變量應當遵循該通用接口。 這種方式同裝飾模式非常相似。
四、實現方式
- 一個無法修改 (通常是第三方、 遺留系統或者存在眾多已有依賴的類) 的功能性服務類。
- 一個或多個將受益于使用服務類的客戶端類。
聲明客戶端接口, 描述客戶端如何與服務交互。
創建遵循客戶端接口的適配器類。 所有方法暫時都為空。
在適配器類中添加一個成員變量用于保存對于服務對象的引用。 通常情況下會通過構造函數對該成員變量進行初始化,
但有時在調用其方法時將該變量傳遞給適配器會更方便。
依次實現適配器類客戶端接口的所有方法。 適配器會將實際工作委派給服務對象, 自身只負責接口或數據格式的轉換。
客戶端必須通過客戶端接口使用適配器。 這樣一來, 你就可以在不影響客戶端代碼的情況下修改或擴展適配器
五、與其他模式的關系
橋接模式通常會于開發前期進行設計, 使你能夠將程序的各個部分獨立開來以便開發。 另一方面, 適配器模式通常在已有程序中使用,讓相互不兼容的類能很好地合作。
適配器可以對已有對象的接口進行修改, 裝飾模式則能在不改變對象接口的前提下強化對象功能。 此外, 裝飾還支持遞歸組合, 適配器則無法實現。
適配器能為被封裝對象提供不同的接口, 代理模式能為對象提供相同的接口, 裝飾則能為對象提供加強的接口。
外觀模式為現有對象定義了一個新接口, 適配器則會試圖運用已有的接口。 適配器通常只封裝一個對象, 外觀通常會作用于整個對象子系統上。
橋接、 狀態模式和策略模式 (在某種程度上包括適配器) 模式的接口非常相似。 實際上, 它們都基于組合模式——即將工作委派給其他對象,不過也各自解決了不同的問題。 模式并不只是以特定方式組織代碼的配方, 你還可以使用它們來和其他開發者討論模式所解決的問題。
參考文章
參考文章
總結
以上是生活随笔為你收集整理的适配器模式(为被封装对象提供不同的接口)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021Q1美妆行业季度观察报告
- 下一篇: 2020年视频号发展白皮书