欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設(shè)計(jì)模式之適配器模式

 更新時(shí)間:2022年10月11日 09:07:42   作者:tianClassmate  
這篇文章介紹了Java設(shè)計(jì)模式之適配器模式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

本文通過(guò)老王使用紙質(zhì)書(shū)籍閱讀小王使用電子書(shū)籍的故事,詳細(xì)說(shuō)明設(shè)計(jì)模式中的結(jié)構(gòu)型設(shè)計(jì)模式之適配器模式,分別對(duì)對(duì)象適配器和類(lèi)適配器代碼實(shí)現(xiàn),最后為了加深理解,會(huì)列舉適配器設(shè)計(jì)模式在JDK和Spring源碼中的應(yīng)用。

讀者可以拉取完整代碼到本地進(jìn)行學(xué)習(xí),實(shí)現(xiàn)代碼均測(cè)試通過(guò)后上傳到碼云,本地源碼下載

一、引出問(wèn)題

自從小王被老王趕出家門(mén)以后,老王過(guò)了幾天舒心的日子,在家里的書(shū)架上買(mǎi)了許許多多的紙質(zhì)書(shū)。

有一天,小王過(guò)夠了野人生活回來(lái)了,小王也是一個(gè)喜歡讀書(shū)的人,但是小王不喜歡紙質(zhì)書(shū),就要求老王將這些書(shū)換成電子版。

老王立馬就不開(kāi)心了,這是我不知道花費(fèi)多少個(gè)日夜才設(shè)計(jì)好的書(shū)架,給你換成電子版的不僅要花費(fèi)我大量的精力改變?cè)袝?shū)架的結(jié)構(gòu),再想找我想看的書(shū)得有多難,而且老李來(lái)了想看紙質(zhì)版怎么辦,我還要再換回去嗎?

小王隨即想到了一種解決思路:這些書(shū)現(xiàn)在符合你的風(fēng)格,應(yīng)該設(shè)計(jì)一種模式,讓這些書(shū)也能符合我的需求,讓我們倆可以在一起讀書(shū),既不改變你的書(shū)架結(jié)構(gòu),又能擴(kuò)展它的功能。

老王滿(mǎn)意的點(diǎn)了點(diǎn)頭,你說(shuō)的不錯(cuò),這實(shí)際上就是結(jié)構(gòu)型設(shè)計(jì)模式中的適配器模式。

二、概念與使用

引用Gof中對(duì)適配器設(shè)計(jì)模式的概念:將一個(gè)類(lèi)的接口轉(zhuǎn)化成客戶(hù)希望的另一個(gè)接口,由于接口不兼容而不能一起工作的類(lèi)可以一起工作。

很顯然,在適配器設(shè)計(jì)模式中應(yīng)該有三個(gè)角色。

目標(biāo)類(lèi):Target,該角色把其他類(lèi)轉(zhuǎn)換為我們期望的接口,可以是一個(gè)抽象類(lèi)或接口,也可以是具體類(lèi)。
被適配者類(lèi)(源): Adaptee ,原有的接口,也是希望被適配的接口。
適配器: Adapter, 將被適配者和目標(biāo)抽象類(lèi)組合到一起的類(lèi)。

在我們的實(shí)際案例中,老王的紙質(zhì)書(shū)很明顯應(yīng)該是屬于被適配者,小王的電子版就是目標(biāo)類(lèi),適配器應(yīng)該是能調(diào)用老王的紙質(zhì)書(shū),并使用一些相關(guān)的業(yè)務(wù)方法轉(zhuǎn)化成電子版,比如調(diào)用老王書(shū)之前買(mǎi)一個(gè)掃描儀,在老王書(shū)調(diào)出來(lái)以后掃描書(shū)籍。

既然適配器中要調(diào)用老王的紙質(zhì)書(shū),調(diào)用它的方法應(yīng)該是有兩種實(shí)現(xiàn)方式。

一是直接繼承老王,那樣就可以直接調(diào)用老王的方法了。

二是在適配器中創(chuàng)建老王的對(duì)象,然后再調(diào)用老王的方法。

這其實(shí)對(duì)應(yīng)了適配器的兩種方式,根據(jù)適配器類(lèi)與適配者類(lèi)的關(guān)系不同,適配器模式可分為對(duì)象適配器和類(lèi)適配器兩種,在對(duì)象適配器模式中,適配器與適配者之間是關(guān)聯(lián)關(guān)系;在類(lèi)適配器模式中,適配器與適配者之間是繼承(或?qū)崿F(xiàn))關(guān)系。

我們先看類(lèi)適配器實(shí)現(xiàn)方式:

被適配者類(lèi):

/**
 * 源對(duì)象
 * @author tcy
 * @Date 04-08-2022
 */
public class AdapteePaperReading {

    public void readPaper(){
        System.out.println("這是老王讀的紙質(zhì)書(shū)...(被適配者方法)");
    }
}

目標(biāo)對(duì)象:

/**
 * 目標(biāo)對(duì)象
 */
public interface TargetOnlineReading {
    public void ReadOnline();
}

適配器:

/**
 * @author tcy
 * @Date 04-08-2022
 */
public class Adapter extends AdapteePaperReading implements TargetOnlineReading{
    @Override
    public void ReadOnline() {

        System.out.println("買(mǎi)一個(gè)掃描儀...");
        readPaper();
        System.out.println("拿到紙質(zhì)書(shū)掃描為電子書(shū)...");
    }
}

客戶(hù)端:

/**
 * @author tcy
 * @Date 04-08-2022
 */
public class Client {

    public static void main(String[] args) {
        Adapter adapter=new Adapter();
        adapter.ReadOnline();

    }
}

以上就實(shí)現(xiàn)類(lèi)適配器,如果我們要實(shí)現(xiàn)對(duì)象適配器也很簡(jiǎn)單,目標(biāo)對(duì)象和被適配者都不變,需要改變的是適配器代碼

/**
 * @author tcy
 * @Date 04-08-2022
 */
public class Adapter implements TargetOnlineReading {

    // 適配者是對(duì)象適配器的一個(gè)屬性
    private AdapteePaperReading adaptee = new AdapteePaperReading();

    @Override
    public void ReadOnline() {

        System.out.println("買(mǎi)一個(gè)掃描儀...");
        adaptee.readPaper();
        System.out.println("拿到紙質(zhì)書(shū)掃描為電子書(shū)...");
    }
}

這樣老王和小王就能在一起讀書(shū)了。但這種方式只能作為系統(tǒng)的一種補(bǔ)救措施,而不是在系統(tǒng)設(shè)計(jì)之初就考慮這種方式,如果老王有十個(gè)八個(gè)兒子都要求按照他們的習(xí)慣來(lái),那系統(tǒng)就會(huì)相當(dāng)?shù)膹?fù)雜,無(wú)異于一場(chǎng)災(zāi)難。而是應(yīng)該考慮重做書(shū)架,將各種情況都考慮進(jìn)去。

需要說(shuō)明的是,類(lèi)適配器之間的耦合度比后者高,且要求程序員了解現(xiàn)有組件庫(kù)中的相關(guān)組件的內(nèi)部結(jié)構(gòu),所以應(yīng)用相對(duì)較少些。

三、應(yīng)用

案例有一些生硬,為了加深對(duì)適配器設(shè)計(jì)模式的把握,我們介紹該模式在Jdk源碼和Spring中的應(yīng)用。

1、JDK應(yīng)用

JDK使用適配器的典型例子是Java線程池FutureTask類(lèi)。我們知道通過(guò)實(shí)現(xiàn)接口實(shí)現(xiàn)多線程一共有兩種方式,Runnable接口和Callable接口。

FutrueTask類(lèi)中有兩個(gè)構(gòu)造方法:

構(gòu)造方法一:傳入?yún)?shù)為Callable接口

// 這是FutureTask的構(gòu)造方法一
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;     
}

構(gòu)造方法二:傳入的參數(shù)為Runnable接口

// 這是FutureTask的構(gòu)造方法二
public FutureTask(Runnable runnable, V result) {
	// 調(diào)用Executors類(lèi)中的callable方法進(jìn)行轉(zhuǎn)化
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;   
}

在構(gòu)造方法中實(shí)際上加傳入的Runnable任務(wù)在內(nèi)部統(tǒng)一被轉(zhuǎn)換為Callable任務(wù)。

可以看到這里采用的是適配器模式,調(diào)用RunnableAdapter<T>(task, result)方法來(lái)適配,實(shí)現(xiàn)如下:

static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

這樣無(wú)論是傳入Runnalbe還是Callable都能適配任務(wù),這個(gè)適配器很簡(jiǎn)單,就是簡(jiǎn)單的實(shí)現(xiàn)了Callable接口,在call()實(shí)現(xiàn)中調(diào)用Runnable.run()方法,然后把傳入的result作為任務(wù)的結(jié)果返回。

通過(guò)這么一個(gè)簡(jiǎn)單案例可以加深對(duì)適配器模式的理解。

2、SpringAOP應(yīng)用

我們知道在Spring的Aop中,使用的 Advice(通知) 來(lái)增強(qiáng)被代理類(lèi)的功能。

其中Advice的類(lèi)型有:BeforeAdvice(在執(zhí)行切點(diǎn)前的通知)、AfterReturningAdvice(在運(yùn)行完切點(diǎn)完未返回之前)、ThrowsAdvice(在運(yùn)行完切點(diǎn)時(shí)拋出異常進(jìn)行的通知),AfterAdvice(執(zhí)行完該切點(diǎn)后,進(jìn)行的通知)、Around advice(包裹一個(gè)方法的執(zhí)行)

在每個(gè)類(lèi)型 Advice 都有對(duì)應(yīng)的攔截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、 ThrowsAdviceInterceptor

Spring需要將每個(gè) Advice 都封裝成對(duì)應(yīng)的攔截器類(lèi)型,返回給容器,這時(shí)候采用的就是適配器類(lèi)型。

Advice 就相當(dāng)于適配者,對(duì)應(yīng)的攔截器類(lèi)型就是目標(biāo)類(lèi)。

3、SpringMVC應(yīng)用

Spring MVC中的適配器模式主要用于執(zhí)行目標(biāo) Controller 中的請(qǐng)求處理方法。

在Spring MVC中,DispatcherServlet 作為用戶(hù),HandlerAdapter 作為期望接口,具體的適配器實(shí)現(xiàn)類(lèi)用于對(duì)目標(biāo)類(lèi)進(jìn)行適配,Controller 作為需要適配的類(lèi)。

當(dāng)Spring容器啟動(dòng)后,會(huì)將所有定義好的適配器對(duì)象存放在一個(gè)List集合中,當(dāng)一個(gè)請(qǐng)求來(lái)臨時(shí),DispatcherServlet 會(huì)通過(guò) handler 的類(lèi)型找到對(duì)應(yīng)適配器,并將該適配器對(duì)象返回給用戶(hù),然后就可以統(tǒng)一通過(guò)適配器的 hanle() 方法來(lái)調(diào)用 Controller 中的用于處理請(qǐng)求的方法。

通過(guò)適配器模式我們將所有的 controller 統(tǒng)一交給 HandlerAdapter 處理,免去了寫(xiě)大量的 if-else 語(yǔ)句對(duì) Controller 進(jìn)行判斷,也更利于擴(kuò)展新的 Controller 類(lèi)型。

單純的說(shuō)蒼白無(wú)力,我們手寫(xiě)實(shí)現(xiàn)SpringMVC的核心流程,完整代碼已經(jīng)上傳到碼云。

四、總結(jié)

既然適配器模式可以擴(kuò)展原有類(lèi)的功能,那它和代理模式在一定程度上不是重合了嗎?貌似擴(kuò)展老王的書(shū)架使用代理模式同樣是可以實(shí)現(xiàn)。

其實(shí)我們看結(jié)構(gòu)型設(shè)計(jì)模式的定義:結(jié)構(gòu)型模式涉及到如何組合類(lèi)和類(lèi)以獲得更大的結(jié)構(gòu),結(jié)構(gòu)型類(lèi)模式采用繼承機(jī)制來(lái)組合接口或?qū)崿F(xiàn)。

代理模式與適配器模式都分別有繼承、接口方式實(shí)現(xiàn)的子分類(lèi)模式?;诮涌趯?shí)現(xiàn)的代理模式稱(chēng)為靜態(tài)代理模式、JDK(動(dòng)態(tài))代理模式,基于繼承實(shí)現(xiàn)的代理模式稱(chēng)為Cglib(動(dòng)態(tài))代理模式。

基于接口(同時(shí)含類(lèi)繼承)實(shí)現(xiàn)的適配器模式稱(chēng)為類(lèi)適配器模式,(只)基于繼承(使用委托)實(shí)現(xiàn)的適配器模式稱(chēng)為類(lèi)適配器模式。

代理模式是為其他類(lèi)提供一種代理以控制對(duì)這個(gè)類(lèi)的訪問(wèn)。我們不直接去接觸目標(biāo)類(lèi),而是直接操作代理類(lèi),代理類(lèi)再去操作目標(biāo)類(lèi)。因?yàn)椴恢苯咏佑|目標(biāo)類(lèi),因此我們可以在代理類(lèi)的同名方法中添加或刪除功能模塊,而不用去修改目標(biāo)類(lèi)的原方法。

而適配器模式則主要是協(xié)調(diào)現(xiàn)實(shí)與需求的差異,減少對(duì)已有代碼的改動(dòng),適配不同的接口、類(lèi)類(lèi)型。

項(xiàng)目實(shí)施中可能會(huì)出現(xiàn)這樣的情況:當(dāng)前已完成的項(xiàng)目的某一個(gè)包內(nèi)的各個(gè)類(lèi)實(shí)現(xiàn)了一些特定的接口,而客戶(hù)提出了新的需求,要求實(shí)現(xiàn)他所指定的那些接口(拋棄原有的方法或接口),但其業(yè)務(wù)細(xì)節(jié)卻是相同、完全一樣的。此時(shí),我們可能并不想復(fù)制粘貼原代碼到新的方法中去,這就需要將一個(gè)類(lèi)的接口轉(zhuǎn)換成新需求的另一個(gè)接口。

實(shí)現(xiàn)方式有很多,沒(méi)有必要咬文嚼字糾結(jié)使用哪種設(shè)計(jì)模式,設(shè)計(jì)模式本身就是很相似,只要能簡(jiǎn)潔開(kāi)發(fā)流程,讓我們的代碼更好的工作就是完美的。具體使用哪一種就需要讀者熟練掌握各種設(shè)計(jì)模式了,并認(rèn)真體會(huì)他們各自的優(yōu)勢(shì)。

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

相關(guān)文章

  • Java8 Lambda表達(dá)式詳解及實(shí)例

    Java8 Lambda表達(dá)式詳解及實(shí)例

    這篇文章主要介紹了Java8 Lambda表達(dá)式詳解的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • spring boot(四)之thymeleaf使用詳解

    spring boot(四)之thymeleaf使用詳解

    Thymeleaf 是一個(gè)跟 Velocity、FreeMarker 類(lèi)似的模板引擎,它可以完全替代 JSP 。接下來(lái)通過(guò)本文給大家介紹spring boot(四)之thymeleaf使用詳解,需要的朋友可以參考下
    2017-05-05
  • Java集合Set的簡(jiǎn)單使用解析

    Java集合Set的簡(jiǎn)單使用解析

    這篇文章主要介紹了Java集合Set的簡(jiǎn)單使用解析,Set接口是Collection的子接口,Set接口相較于Collection接口沒(méi)有提供額外的方法,Set 集合不允許包含相同的元素,如果試把兩個(gè)相同的元素加入同一個(gè) Set 集合中,則添加操作失敗,需要的朋友可以參考下
    2023-11-11
  • Java 基礎(chǔ)--Arrays工具類(lèi)詳解

    Java 基礎(chǔ)--Arrays工具類(lèi)詳解

    這篇文章主要介紹了Java Arrays工具類(lèi)用法,結(jié)合實(shí)例形式分析了java Arrays工具類(lèi)針對(duì)數(shù)組元素修改、復(fù)制、排序等操作使用技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2021-09-09
  • mybatis的foreach標(biāo)簽語(yǔ)法報(bào)錯(cuò)的解決

    mybatis的foreach標(biāo)簽語(yǔ)法報(bào)錯(cuò)的解決

    這篇文章主要介紹了mybatis的foreach標(biāo)簽語(yǔ)法報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • druid監(jiān)控?zé)o法關(guān)閉的坑以及處理方式

    druid監(jiān)控?zé)o法關(guān)閉的坑以及處理方式

    這篇文章主要介紹了druid監(jiān)控?zé)o法關(guān)閉的坑以及處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 詳解spring cloud整合Swagger2構(gòu)建RESTful服務(wù)的APIs

    詳解spring cloud整合Swagger2構(gòu)建RESTful服務(wù)的APIs

    這篇文章主要介紹了詳解spring cloud整合Swagger2構(gòu)建RESTful服務(wù)的APIs,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • 如何使用java.security.SecureRandom安全生成隨機(jī)數(shù)和隨機(jī)字符串工具類(lèi)

    如何使用java.security.SecureRandom安全生成隨機(jī)數(shù)和隨機(jī)字符串工具類(lèi)

    這篇文章主要給大家介紹了關(guān)于如何使用java.security.SecureRandom安全生成隨機(jī)數(shù)和隨機(jī)字符串工具類(lèi)的相關(guān)資料,SecureRandom擴(kuò)展了Random類(lèi),并通過(guò)在java 8中添加的新方法得到了豐富,需要的朋友可以參考下
    2024-05-05
  • IntelliJ IDEA 15款超級(jí)牛逼插件推薦(自用,超級(jí)牛逼)

    IntelliJ IDEA 15款超級(jí)牛逼插件推薦(自用,超級(jí)牛逼)

    這篇文章主要給大家推薦介紹了IntelliJ IDEA 15款超級(jí)牛逼插件,這15款插件都是自用的,真的非常推薦,需要的朋友可以參考下
    2020-11-11
  • java實(shí)現(xiàn)砸金蛋抽獎(jiǎng)功能

    java實(shí)現(xiàn)砸金蛋抽獎(jiǎng)功能

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)砸金蛋抽獎(jiǎng)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11

最新評(píng)論