Java設(shè)計(jì)模式--適配器模式詳解
定義
適配器模式用于解決接口間的兼容問(wèn)題。
當(dāng)我們需要使用某個(gè)類(lèi)提供的接口,但是這個(gè)接口與現(xiàn)在的系統(tǒng)需求不符,由于該接口是由第三方提供的,或者是已經(jīng)在生產(chǎn)上跑了很久的存量類(lèi),我們不想通過(guò)改變這個(gè)類(lèi)來(lái)滿(mǎn)足現(xiàn)在系統(tǒng)的需求,那么這時(shí)候就可以考慮通過(guò)將目標(biāo)類(lèi)封裝成一個(gè)滿(mǎn)足系統(tǒng)需求的新類(lèi),因此適配器(Adapter)也稱(chēng)為包裝器(Wrapper)。
結(jié)構(gòu)
適配器模式包含如下角色:
- Target:目標(biāo)抽象類(lèi),客戶(hù)類(lèi)期望的接口。
- Adapter:適配器類(lèi),適配器模式的核心,實(shí)現(xiàn)目標(biāo)抽象類(lèi)和適配者類(lèi)的轉(zhuǎn)換。
- Adaptee:適配者類(lèi),與目前需求不兼容的類(lèi),即需要被包裝的類(lèi)。
- Client:客戶(hù)類(lèi),調(diào)用在目標(biāo)抽象類(lèi)中定義的業(yè)務(wù)方法。
適配器模式有類(lèi)適配器和對(duì)象適配器兩種實(shí)現(xiàn):
1、在類(lèi)適配器模式中,適配器類(lèi)實(shí)現(xiàn)了目標(biāo)抽象類(lèi)接口并繼承了適配者類(lèi),在目標(biāo)抽象類(lèi)的實(shí)現(xiàn)方法中調(diào)用所繼承的適配者類(lèi)的方法。
2、在對(duì)象適配器模式中,適配器類(lèi)實(shí)現(xiàn)了目標(biāo)抽象類(lèi)并定義了一個(gè)適配者類(lèi)的對(duì)象實(shí)例,在目標(biāo)抽象類(lèi)的實(shí)現(xiàn)方法中調(diào)用適配者類(lèi)實(shí)例的方法。
示例
假如我們手上有一只手機(jī),它只有一個(gè)type-c接口,同時(shí)手上有一條3.5mm的耳機(jī),想聽(tīng)音樂(lè)的時(shí)候就會(huì)發(fā)現(xiàn)二者不兼容,相較于更換手機(jī)或者耳機(jī),一般我們會(huì)選擇一條type-c和3.5mm的轉(zhuǎn)接線來(lái)實(shí)現(xiàn)最高性?xún)r(jià)比。
此時(shí)將3.5mm耳機(jī)比作客戶(hù)端(客戶(hù)類(lèi)),它期望得到音樂(lè)信號(hào)的目標(biāo)是3.5mm接口(目標(biāo)抽象類(lèi)),type-c接口則是手機(jī)提供的音樂(lè)信號(hào)傳輸接口(適配者類(lèi)),與耳機(jī)接頭不兼容,而轉(zhuǎn)接線(適配器類(lèi))可以將type-c接口包裝為耳機(jī)可以插入的3.5mm接口,能夠解決手機(jī)與耳機(jī)的不兼容問(wèn)題,實(shí)現(xiàn)用耳機(jī)接收手機(jī)播放的音樂(lè)信號(hào)。
1、定義目標(biāo)抽象類(lèi),即客戶(hù)類(lèi)期望的接口。
public interface ThreePointFiveConn { //一個(gè)提供音樂(lè)的3.5mm接口 public void playMusic(String connector); }
2、定義適配者類(lèi),即需要被包裝的類(lèi)。
public interface PlayMusicConn { public void playMusicOut(String connector); } public class TypecPlayMusicConn implements PlayMusicConn { //只允許typec接頭插入 public void playMusicOut(String phoneConnType, String musicName) { if("typec".equals(phoneConnType)){ //實(shí)現(xiàn)播放音樂(lè)功能 System.out.println("playing music with typec Player..." + musicName); }else { System.out.println("error!"); } } } public class LightningPlayMusicConn implements PlayMusicConn { //只允許Lightning接頭插入 public void playMusicOut(String phoneConnType, String musicName) { if("lightning".equals(phoneConnType)){ //實(shí)現(xiàn)播放音樂(lè)功能 System.out.println("playing music with lightning Player..." + musicName); }else { System.out.println("error!"); } } }
類(lèi)適配器模式:由于適配器類(lèi)是適配者類(lèi)的子類(lèi),因此可以在適配器類(lèi)中重寫(xiě)適配者類(lèi)的方法,使得適配器類(lèi)更具靈活性。
3、構(gòu)建適配器類(lèi),將適配者類(lèi)PlayMusicConn包裝為目標(biāo)抽象類(lèi)ThreePointFiveConn的一個(gè)子類(lèi)。
public class Transverter extends TypecPlayMusicConn implements ThreePointFiveConn { //調(diào)用繼承的適配者類(lèi)的方法 public void playMusic(String musicName) { super.playMusicOut("typec", musicName); } }
4、客戶(hù)端類(lèi)(耳機(jī))使用
public class EarPhone { public static void main(String[] args) { ThreePointFiveConn earPhone = new Transverter(); earPhone.playMusic("Hey Jude"); } }
運(yùn)行結(jié)果:
playing music with typec Player…Hey Jude
- 對(duì)象適配器模式:一個(gè)對(duì)象適配器類(lèi)可以把多個(gè)不同的適配者類(lèi)及其子類(lèi)適配到同一個(gè)目標(biāo)抽象類(lèi),因此具有更大的兼容性。
3、構(gòu)建適配器類(lèi),將適配者類(lèi)PlayMusicConn包裝為目標(biāo)抽象類(lèi)ThreePointFiveConn的一個(gè)子類(lèi)。
public class Transverter implements ThreePointFiveConn { //定義適配者類(lèi)的對(duì)象實(shí)例 private PlayMusicConn playMusicConn; public Transverter(PlayMusicConn playMusicConn){ this.playMusicConn = playMusicConn; } public void playMusic(String musicName) { if(playMusicConn instanceof TypecPlayMusicConn) { playMusicConn.playMusicOut("typec", musicName); }else if(playMusicConn instanceof LightningPlayMusicConn) { playMusicConn.playMusicOut("lightning", musicName); }else { System.out.print("error!"); } } }
4、客戶(hù)端類(lèi)(耳機(jī))使用
public class EarPhone { public static void main(String[] args) { //typec接口手機(jī)播放音樂(lè) ThreePointFiveConn earPhone = new Transverter(new TypecPlayMusicConn()); earPhone.playMusic("Hey Jude"); //lightning接口手機(jī)播放音樂(lè) ThreePointFiveConn earPhone1 = new Transverter(new LightningPlayMusicConn()); earPhone1.playMusic("Hey Jude"); } }
運(yùn)行結(jié)果:
playing music with typec Player…Hey Jude
playing music with lightning Player…Hey Jude
擴(kuò)展
除類(lèi)適配器和對(duì)象適配器模式外,還有一種接口適配器模式。接口適配器模式是指在定義適配器時(shí),先將其定義為一個(gè)抽象類(lèi)實(shí)現(xiàn)接口,接口中定義了多個(gè)抽象方法,定義該適配器的子類(lèi)時(shí),子類(lèi)只實(shí)現(xiàn)其中的部分抽象方法。
它適用于一個(gè)接口不想使用其所有的方法的情況。因此也稱(chēng)為單接口適配器模式。
public abstract class TransverterInterface implements ThreePointFiveConn { PlayMusicConn playMusicConn = new TypecPlayMusicConn(); public void playMusic(String musicName) { playMusicConn.playMusicOut("typec", musicName); } public void anotherMethod1(){} public void anotherMethod2(){} } public class TransverterInterfaceImpl extends TransverterInterface { public void playMusic(String musicName) { super.playMusic(musicName); } }
總結(jié)
適配器模式的主要優(yōu)點(diǎn)是將目標(biāo)類(lèi)和適配者類(lèi)解耦,增加了類(lèi)的透明性和復(fù)用性,同時(shí)系統(tǒng)的靈活性和擴(kuò)展性都非常好,更換適配器或者增加新的適配器都非常方便,符合“開(kāi)閉原則”。
適配器模式適用情況包括:系統(tǒng)需要使用現(xiàn)有的類(lèi),而這些類(lèi)的接口不符合系統(tǒng)的需要;想要建立一個(gè)可以重復(fù)使用的類(lèi),用于與一些彼此之間沒(méi)有太大關(guān)聯(lián)的一些類(lèi)一起工作。
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
使用SpringBoot Actuator監(jiān)控應(yīng)用示例
Actuator是Spring Boot提供的對(duì)應(yīng)用系統(tǒng)的自省和監(jiān)控的集成功能,可以對(duì)應(yīng)用系統(tǒng)進(jìn)行配置查看、相關(guān)功能統(tǒng)計(jì)等。這篇文章主要介紹了使用SpringBoot Actuator監(jiān)控應(yīng),有興趣的可以了解一下2018-05-05Java中Spring Boot+Socket實(shí)現(xiàn)與html頁(yè)面的長(zhǎng)連接實(shí)例詳解
這篇文章主要介紹了Java中Spring Boot+Socket實(shí)現(xiàn)與html頁(yè)面的長(zhǎng)連接實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Map集合中獲取key-value值的實(shí)現(xiàn)方法
這篇文章主要介紹了Map集合中獲取key-value值的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03基于hibernate框架在eclipse下的配置方法(必看篇)
下面小編就為大家?guī)?lái)一篇基于hibernate框架在eclipse下的配置方法(必看篇)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09Spring?注入靜態(tài)對(duì)象使用三種方式示例
這篇文章主要為大家介紹了Spring注入靜態(tài)對(duì)象使用的三種方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07Spring?boot?Jpa添加對(duì)象字段使用數(shù)據(jù)庫(kù)默認(rèn)值操作
這篇文章主要介紹了Spring?boot?Jpa添加對(duì)象字段使用數(shù)據(jù)庫(kù)默認(rèn)值操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Java中使用Jedis操作Redis的實(shí)現(xiàn)代碼
本篇文章主要介紹了Java中使用Jedis操作Redis的實(shí)現(xiàn)代碼。詳細(xì)的介紹了Redis的安裝和在java中的操作,具有一定的參考價(jià)值,有興趣的可以了解一下2017-05-05