java設(shè)計模式之適配器模式
感謝《Android源碼設(shè)計模式解析與實戰(zhàn)》 何紅輝 關(guān)愛民 著
適配器模式在我們的開發(fā)中使用率極高,從代碼中隨處可見的Adapter就可以判斷出來,從最早的ListView、GridView、到現(xiàn)在最新的RecyclerView都需要使用Adapter,并且在開發(fā)中我們遇到的優(yōu)化問題、出錯概率較大的地方也基本都出自Adapter。
適配器是將兩個不兼容的火龍融合在一起,將不同的東西通過一種轉(zhuǎn)換使得它們能夠協(xié)作起來,例如,經(jīng)常碰到要在兩個沒有關(guān)系的類型之間進(jìn)行交互,第一個解決方案是修改各自類的接口,但是如果沒有源代碼或者我們不愿意為了一個應(yīng)用而修改各自的接口,這種情況我們往往會使用一個Adapter,這個Adapter會將這兩個接口進(jìn)行兼容,在不修改原有代碼的情況下滿足需求。
假設(shè)已有一個軟件系統(tǒng),你希望它能和一個新的廠商類庫搭配使用,但是這個新廠商所設(shè)計出來的接口,不用于舊廠商的接口:
你不想改變現(xiàn)有的代碼,解決這個問題(也不能改變廠商的代碼),應(yīng)該怎么做?你可以寫一個類(適配器),將新廠商接口轉(zhuǎn)接成你所期望的接口,這個適配器工作起來就如同一個中間人,它將客戶所發(fā)出的請求轉(zhuǎn)換成廠商類能理解的請求。
適配器模式可分為兩種:
對象適配器:充滿著良好的OO設(shè)計原則,使用對象組合,可以應(yīng)用在適配者是接口和它所有的子類,不能夠重寫適配器的方法,因為沒有繼承關(guān)系,但是也能夠“重新實現(xiàn)”適配者中方法,客戶端和適配者完全不相干,只有適配器擁有適配者的引用。
類適配器:使用繼承的方式達(dá)到適配的工作,只能是適配者是接口,不能利用它子類的接口,當(dāng)類適配器建立時,它就靜態(tài)地與適配者關(guān)聯(lián),適配者作為適配器的基類,所以適配器能夠重寫適配器中的方法,客戶端代碼對適配者中聲明的代碼是可見的客戶端代碼對適配者中聲明的代碼是可見的。
定義:
適配器模式把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。
使用場景:
1.系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要,即接口不兼容。
2.想要建立一個可以重復(fù)使用的類,用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類,包括一些可能在將來引進(jìn)的類一起工作。
3.需要一個統(tǒng)一的輸出接口,而輸入端的類型不可預(yù)知。
UML類圖:
首先看下類適配器:
類適配器是通過實現(xiàn)Target接口以及繼承Adaptee類來實現(xiàn)接口轉(zhuǎn)換,例如,目標(biāo)接口需要的是operation2,但是Adaptee對象只有一個operation3,因此就出現(xiàn)了不兼容的情況。此時通過Adapter實現(xiàn)一個operation2函數(shù)將Adaptee的operation3轉(zhuǎn)換成Target需要的operation2,以此實現(xiàn)兼容。
Target : 目標(biāo)角色,也就是所期待得到的接口。注意:由于這里討論的是類適配器模式,因此目標(biāo)不可以是類。
Adaptee : 現(xiàn)在需要適配的接口。
Adapter: 適配器角色,也是本模式的核心,適配器把源接口轉(zhuǎn)換成目標(biāo)接口。這一角色不可以是接口,而必須是具體類。
類適配器模式示例:
以大陸電壓為220v,手機(jī)電壓為5v為例
/** * 電壓類 Target目標(biāo) * @author Administrator * */ public interface Voltage { public int getVoltage(); }public class ChinaVoltage implements Voltage{ @Override public int getVoltage() { // 大陸電壓為220 return 220; } }<pre name="code" class="java">/** * 手機(jī)類, Adaptee 被適配者類 * @author Administrator * */ public class PhoneVoltage { /** * 手機(jī)電壓為5v * @return */ public int getPhoneVoltage(){ return 5; } } <pre name="code" class="java">/** * 充電器 Adapter 適配器類 * @author Administrator * */ public class Charger extends PhoneVoltage implements Voltage { @Override public int getVoltage() { return getPhoneVoltage(); } } public class Client { public static void main(String[] args) { ChinaVoltage vol = new ChinaVoltage(); System.out.println("大陸電壓為 : " + vol.getVoltage()); //為手機(jī)接入充電器時的電壓 Chargerr character = new Chargerr(); System.out.println("通過充電器轉(zhuǎn)換后的電壓 : " + character.getVoltage()); } }
運(yùn)行結(jié)果:
大陸電壓為 : 220
通過充電器轉(zhuǎn)換后的電壓 : 5
再看一下對象適配器類圖:
下面以對象適配器修改Chargerr類
<pre name="code" class="java">/** * 充電器 Adapter 適配器類 * @author Administrator * */ public class Chargerr implements Voltage{ private PhoneVoltage phoneV; public Chargerr(PhoneVoltage phoneV) { this.phoneV = phoneV; } @Override public int getVoltage() { return phoneV.getPhoneVoltage(); } }
對象適配器實現(xiàn)方式直接將要被適配的對象傳遞到Adapter中,使用組合的形式實現(xiàn)接口兼容的效果,這比類適配器方式更為靈活,它的另一個好處是被適配對象中的方法不會暴露出來,而類適配器由于繼承了被適配對象,因此,被適配對象類的函數(shù)在Adapter類中也都含有,這使得Adapter類出現(xiàn)一些奇怪的接口,用戶使用成本較高。因此,對象適配器模式更加靈活、實用。
public class Client { public static void main(String[] args) { // ChinaVoltage vol = new ChinaVoltage(); // System.out.println("大陸電壓為 : " + vol.getVoltage()); // //為手機(jī)接入充電器時的電壓 // Chargerr character = new Chargerr(); // System.out.println("通過充電器轉(zhuǎn)換后的電壓 : " + character.getVoltage()); //被適配者 PhoneVoltage phoneV = new PhoneVoltage(); Chargerr chargerr = new Chargerr(phoneV); System.out.println("通過充電器轉(zhuǎn)換后的電壓:" + chargerr.getVoltage()); } //運(yùn)行結(jié)果: // 通過充電器轉(zhuǎn)換后的電壓:5 }
總結(jié):
Adapter模式的經(jīng)典實現(xiàn)在于將原本不兼容的接口融合在一起,使之能夠很好地進(jìn)行合作。但是,在實際開發(fā)中,Adapter模式也有一些靈活的實現(xiàn)。例如ListView中的隔離變化,使得整個UI架構(gòu)變得更靈活,能夠擁抱變化。Adapter模式在開發(fā)呂運(yùn)用非常廣泛。
優(yōu)點:
更好的復(fù)用性:系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要。那么通過適配器模式就可以讓這些功能得到更好的復(fù)用。
更好的擴(kuò)展性:在實現(xiàn)適配器功能的時候,可以調(diào)用自己開發(fā)的功能,從而自然地擴(kuò)展系統(tǒng)的功能。
缺點:
過多的使用適配器,會讓系統(tǒng)非常零亂,不易速體把握。例如,明明看到調(diào)用的昌A接口,其實內(nèi)部被適配成了B接口的實現(xiàn),一個系統(tǒng)如果太多出現(xiàn)這種情況,無異于一場災(zāi)難。因此,如果不是有必要,可以不使用適配器,而是直接對系統(tǒng)進(jìn)行重構(gòu)。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java之next()、nextLine()區(qū)別及問題解決
這篇文章主要介紹了Java之next()、nextLine()區(qū)別及問題解決,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08詳解Spring?Security怎么從數(shù)據(jù)庫加載我們的用戶
這篇文章主要為大家介紹了Spring?Security怎么從數(shù)據(jù)庫加載我們的用戶示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01SpringMVC源碼解讀之HandlerMapping - AbstractUrlHandlerMapping系列re
這篇文章主要介紹了SpringMVC源碼解讀之HandlerMapping - AbstractUrlHandlerMapping系列request分發(fā) 的相關(guān)資料,需要的朋友可以參考下2016-02-02深入分析java并發(fā)編程中volatile的實現(xiàn)原理
這篇文章主要介紹了深入分析java并發(fā)編程中Volatile的實現(xiàn)原理,涉及Volatile的官方定義,實現(xiàn)原理,使用優(yōu)化等相關(guān)內(nèi)容,具有一定參考價值,需要的朋友可以了解下。2017-11-11解決SpringBoot 測試類無法自動注入@Autowired的問題
這篇文章主要介紹了解決SpringBoot 測試類無法自動注入@Autowired的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03SpringBoot使用validation-api實現(xiàn)參數(shù)校驗的示例
這篇文章主要介紹了SpringBoot使用validation-api實現(xiàn)參數(shù)校驗的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Java中的getClass()以及getName()方法使用
這篇文章主要介紹了Java中的getClass()以及getName()方法使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12