日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

不兼容结构的协调——适配器模式

發(fā)布時(shí)間:2024/2/28 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 不兼容结构的协调——适配器模式 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文轉(zhuǎn)載自 :http://blog.csdn.net/lovelion/article/details/8624325


我的筆記本電腦的工作電壓是20V,而我國(guó)的家庭用電是220V,如何讓20V的筆記本電腦能夠在220V的電壓下工作?答案是引入一個(gè)電源適配器(AC Adapter),俗稱充電器或變壓器,有了這個(gè)電源適配器,生活用電和筆記本電腦即可兼容,如圖9-1所示:

9-1?電源適配器示意圖

????? 在軟件開(kāi)發(fā)中,有時(shí)也存在類似這種不兼容的情況,我們也可以像引入一個(gè)電源適配器一樣引入一個(gè)稱之為適配器的角色來(lái)協(xié)調(diào)這些存在不兼容的結(jié)構(gòu),這種設(shè)計(jì)方案即為適配器模式。

?

9.1?沒(méi)有源碼的算法庫(kù)

?????? Sunny軟件公司在很久以前曾開(kāi)發(fā)了一個(gè)算法庫(kù),里面包含了一些常用的算法,例如排序算法和查找算法,在進(jìn)行各類軟件開(kāi)發(fā)時(shí)經(jīng)常需要重用該算法庫(kù)中的算法。在為某學(xué)校開(kāi)發(fā)教務(wù)管理系統(tǒng)時(shí),開(kāi)發(fā)人員發(fā)現(xiàn)需要對(duì)學(xué)生成績(jī)進(jìn)行排序和查找,該系統(tǒng)的設(shè)計(jì)人員已經(jīng)開(kāi)發(fā)了一個(gè)成績(jī)操作接口ScoreOperation,在該接口中聲明了排序方法sort(int[])?和查找方法search(int[], int),為了提高排序和查找的效率,開(kāi)發(fā)人員決定重用算法庫(kù)中的快速排序算法類QuickSort和二分查找算法類BinarySearch,其中QuickSortquickSort(int[])方法實(shí)現(xiàn)了快速排序,BinarySearch?binarySearch (int[], int)方法實(shí)現(xiàn)了二分查找。

?????? 由于某些原因,現(xiàn)在Sunny公司開(kāi)發(fā)人員已經(jīng)找不到該算法庫(kù)的源代碼,無(wú)法直接通過(guò)復(fù)制和粘貼操作來(lái)重用其中的代碼;部分開(kāi)發(fā)人員已經(jīng)針對(duì)ScoreOperation接口編程,如果再要求對(duì)該接口進(jìn)行修改或要求大家直接使用QuickSort類和BinarySearch類將導(dǎo)致大量代碼需要修改。

?????? Sunny軟件公司開(kāi)發(fā)人員面對(duì)這個(gè)沒(méi)有源碼的算法庫(kù),遇到一個(gè)幸福而又煩惱的問(wèn)題:如何在既不修改現(xiàn)有接口又不需要任何算法庫(kù)代碼的基礎(chǔ)上能夠?qū)崿F(xiàn)算法庫(kù)的重用?

???????通過(guò)分析,我們不難得知,現(xiàn)在Sunny軟件公司面對(duì)的問(wèn)題有點(diǎn)類似本章最開(kāi)始所提到的電壓?jiǎn)栴},成績(jī)操作接口ScoreOperation好比只支持20V電壓的筆記本,而算法庫(kù)好比220V的家庭用電,這兩部分都沒(méi)有辦法再進(jìn)行修改,而且它們?cè)臼莾蓚€(gè)完全不相關(guān)的結(jié)構(gòu),如圖9-2所示:

9-2?需協(xié)調(diào)的兩個(gè)系統(tǒng)的結(jié)構(gòu)示意圖

?????? 現(xiàn)在我們需要ScoreOperation接口能夠和已有算法庫(kù)一起工作,讓它們?cè)谕粋€(gè)系統(tǒng)中能夠兼容,最好的實(shí)現(xiàn)方法是增加一個(gè)類似電源適配器一樣的適配器角色,通過(guò)適配器來(lái)協(xié)調(diào)這兩個(gè)原本不兼容的結(jié)構(gòu)。如何在軟件開(kāi)發(fā)中設(shè)計(jì)和實(shí)現(xiàn)適配器是本章我們將要解決的核心問(wèn)題,下面就讓我們正式開(kāi)始學(xué)習(xí)這種用于解決不兼容結(jié)構(gòu)問(wèn)題的適配器模式。

?

9.2 適配器模式概述

?????? 與電源適配器相似,在適配器模式中引入了一個(gè)被稱為適配器(Adapter)的包裝類,而它所包裝的對(duì)象稱為適配者(Adaptee),即被適配的類。適配器的實(shí)現(xiàn)就是把客戶類的請(qǐng)求轉(zhuǎn)化為對(duì)適配者的相應(yīng)接口的調(diào)用。也就是說(shuō):當(dāng)客戶類調(diào)用適配器的方法時(shí),在適配器類的內(nèi)部將調(diào)用適配者類的方法,而這個(gè)過(guò)程對(duì)客戶類是透明的,客戶類并不直接訪問(wèn)適配者類。因此,適配器讓那些由于接口不兼容而不能交互的類可以一起工作。

?????? 適配器模式可以將一個(gè)類的接口和另一個(gè)類的接口匹配起來(lái),而無(wú)須修改原來(lái)的適配者接口和抽象目標(biāo)類接口。適配器模式定義如下:

適配器模式(Adapter Pattern):將一個(gè)接口轉(zhuǎn)換成客戶希望的另一個(gè)接口,使接口不兼容的那些類可以一起工作,其別名為包裝器(Wrapper)。適配器模式既可以作為類結(jié)構(gòu)型模式,也可以作為對(duì)象結(jié)構(gòu)型模式。

【注:在適配器模式定義中所提及的接口是指廣義的接口,它可以表示一個(gè)方法或者方法的集合。】

?????? 在適配器模式中,我們通過(guò)增加一個(gè)新的適配器類來(lái)解決接口不兼容的問(wèn)題,使得原本沒(méi)有任何關(guān)系的類可以協(xié)同工作。根據(jù)適配器類與適配者類的關(guān)系不同,適配器模式可分為對(duì)象適配器和類適配器兩種,在對(duì)象適配器模式中,適配器與適配者之間是關(guān)聯(lián)關(guān)系;在類適配器模式中,適配器與適配者之間是繼承(或?qū)崿F(xiàn))關(guān)系在實(shí)際開(kāi)發(fā)中,對(duì)象適配器的使用頻率更高,對(duì)象適配器模式結(jié)構(gòu)如圖9-3所示:

?9-3?對(duì)象適配器模式結(jié)構(gòu)圖

?????? 在對(duì)象適配器模式結(jié)構(gòu)圖中包含如下幾個(gè)角色:

?????? ●?Target(目標(biāo)抽象類):目標(biāo)抽象類定義客戶所需接口,可以是一個(gè)抽象類或接口,也可以是具體類。

?????? ●?Adapter(適配器類):適配器可以調(diào)用另一個(gè)接口,作為一個(gè)轉(zhuǎn)換器,對(duì)AdapteeTarget進(jìn)行適配,適配器類是適配器模式的核心,在對(duì)象適配器中,它通過(guò)繼承Target并關(guān)聯(lián)一個(gè)Adaptee對(duì)象使二者產(chǎn)生聯(lián)系。

?????? ●?Adaptee(適配者類):適配者即被適配的角色,它定義了一個(gè)已經(jīng)存在的接口,這個(gè)接口需要適配,適配者類一般是一個(gè)具體類,包含了客戶希望使用的業(yè)務(wù)方法,在某些情況下可能沒(méi)有適配者類的源代碼。

?????? 根據(jù)對(duì)象適配器模式結(jié)構(gòu)圖,在對(duì)象適配器中,客戶端需要調(diào)用request()方法,而適配者類Adaptee沒(méi)有該方法,但是它所提供的specificRequest()方法卻是客戶端所需要的。為了使客戶端能夠使用適配者類,需要提供一個(gè)包裝類Adapter,即適配器類。這個(gè)包裝類包裝了一個(gè)適配者的實(shí)例,從而將客戶端與適配者銜接起來(lái),在適配器的request()方法中調(diào)用適配者的specificRequest()方法。因?yàn)檫m配器類與適配者類是關(guān)聯(lián)關(guān)系(也可稱之為委派關(guān)系),所以這種適配器模式稱為對(duì)象適配器模式。典型的對(duì)象適配器代碼如下所示:

[java]?view plaincopy
  • class?Adapter?extends?Target?{??
  • ????private?Adaptee?adaptee;?//維持一個(gè)對(duì)適配者對(duì)象的引用??
  • ??????
  • ????public?Adapter(Adaptee?adaptee)?{??
  • ????????this.adaptee=adaptee;??
  • ????}??
  • ??????
  • ????public?void?request()?{??
  • ????????adaptee.specificRequest();?//轉(zhuǎn)發(fā)調(diào)用??
  • ????}??
  • }??
  • ?

    ?

    思考

    ?????? 在對(duì)象適配器中,一個(gè)適配器能否適配多個(gè)適配者?如果能,應(yīng)該如何實(shí)現(xiàn)?如果不能,請(qǐng)說(shuō)明原因?



    9.3 完整解決方案

    ????? Sunny軟件公司開(kāi)發(fā)人員決定使用適配器模式來(lái)重用算法庫(kù)中的算法,其基本結(jié)構(gòu)如圖9-4所示:

    9-4??算法庫(kù)重用結(jié)構(gòu)圖

    ?????? 在圖9-4中,ScoreOperation接口充當(dāng)抽象目標(biāo),QuickSortBinarySearch類充當(dāng)適配者,OperationAdapter充當(dāng)適配器。完整代碼如下所示:

    [java]?view plaincopy
  • //抽象成績(jī)操作類:目標(biāo)接口??
  • interface?ScoreOperation?{??
  • ????public?int[]?sort(int?array[]);?//成績(jī)排序??
  • ????public?int?search(int?array[],int?key);?//成績(jī)查找??
  • }??
  • ??
  • //快速排序類:適配者??
  • class?QuickSort?{??
  • ????public?int[]?quickSort(int?array[])?{??
  • ????????sort(array,0,array.length-1);??
  • ????????return?array;??
  • ????}??
  • ??
  • ????public?void?sort(int?array[],int?p,?int?r)?{??
  • ????????int?q=0;??
  • ????????if(p<r)?{??
  • ????????????q=partition(array,p,r);??
  • ????????????sort(array,p,q-1);??
  • ????????????sort(array,q+1,r);??
  • ????????}??
  • ????}??
  • ??
  • ????public?int?partition(int[]?a,?int?p,?int?r)?{??
  • ????????int?x=a[r];??
  • ????????int?j=p-1;??
  • ????????for?(int?i=p;i<=r-1;i++)?{??
  • ????????????if?(a[i]<=x)?{??
  • ????????????????j++;??
  • ????????????????swap(a,j,i);??
  • ????????????}??
  • ????????}??
  • ????????swap(a,j+1,r);??
  • ????????return?j+1;???
  • ????}??
  • ??
  • ????public?void?swap(int[]?a,?int?i,?int?j)?{?????
  • ????????int?t?=?a[i];?????
  • ????????a[i]?=?a[j];?????
  • ????????a[j]?=?t;?????
  • ????}??
  • }??
  • ??
  • //二分查找類:適配者??
  • class?BinarySearch?{??
  • ????public?int?binarySearch(int?array[],int?key)?{??
  • ????????int?low?=?0;??
  • ????????int?high?=?array.length?-1;??
  • ????????while(low?<=?high)?{??
  • ????????????int?mid?=?(low?+?high)?/?2;??
  • ????????????int?midVal?=?array[mid];??
  • ????????????if(midVal?<?key)?{????
  • low?=?mid?+1;????
  • }??
  • ????????????else?if?(midVal?>?key)?{????
  • high?=?mid?-1;????
  • }??
  • ????????????else?{????
  • return?1;?//找到元素返回1????
  • }??
  • ????????}??
  • ????????return?-1;??//未找到元素返回-1??
  • ????}??
  • }??
  • ??
  • //操作適配器:適配器??
  • class?OperationAdapter?implements?ScoreOperation?{??
  • ????private?QuickSort?sortObj;?//定義適配者QuickSort對(duì)象??
  • ????private?BinarySearch?searchObj;?//定義適配者BinarySearch對(duì)象??
  • ??
  • ????public?OperationAdapter()?{??
  • ????????sortObj?=?new?QuickSort();??
  • ????????searchObj?=?new?BinarySearch();??
  • ????}??
  • ??
  • ????public?int[]?sort(int?array[])?{????
  • return?sortObj.quickSort(array);?//調(diào)用適配者類QuickSort的排序方法??
  • }??
  • ??
  • ????public?int?search(int?array[],int?key)?{????
  • return?searchObj.binarySearch(array,key);?//調(diào)用適配者類BinarySearch的查找方法??
  • }??
  • }??
  • ???????為了讓系統(tǒng)具備良好的靈活性和可擴(kuò)展性,我們引入了工具類XMLUtil和配置文件,其中,XMLUtil類的代碼如下所示:

    [java]?view plaincopy
  • import?javax.xml.parsers.*;??
  • import?org.w3c.dom.*;??
  • import?org.xml.sax.SAXException;??
  • import?java.io.*;??
  • class?XMLUtil?{??
  • //該方法用于從XML配置文件中提取具體類類名,并返回一個(gè)實(shí)例對(duì)象??
  • ????public?static?Object?getBean()?{??
  • ????????try?{??
  • ????????????//創(chuàng)建文檔對(duì)象??
  • ????????????DocumentBuilderFactory?dFactory?=?DocumentBuilderFactory.newInstance();??
  • ????????????DocumentBuilder?builder?=?dFactory.newDocumentBuilder();??
  • ????????????Document?doc;?????????????????????????????
  • ????????????doc?=?builder.parse(new?File("config.xml"));???
  • ??????????
  • ????????????//獲取包含類名的文本節(jié)點(diǎn)??
  • ????????????NodeList?nl?=?doc.getElementsByTagName("className");??
  • ????????????Node?classNode=nl.item(0).getFirstChild();??
  • ????????????String?cName=classNode.getNodeValue();??
  • ??????????????
  • ????????????//通過(guò)類名生成實(shí)例對(duì)象并將其返回??
  • ????????????Class?c=Class.forName(cName);??
  • ????????????Object?obj=c.newInstance();??
  • ????????????return?obj;??
  • ????????}?????
  • ????????catch(Exception?e)?{??
  • ????????????e.printStackTrace();??
  • ????????????return?null;??
  • ????????}??
  • ????}??
  • }??
  • ???????配置文件config.xml中存儲(chǔ)了適配器類的類名,代碼如下所示:

    [html]?view plaincopy
  • <?xml?version="1.0"?>??
  • <config>??
  • ????<className>OperationAdapter</className>??
  • </config>??
  • ???????編寫(xiě)如下客戶端測(cè)試代碼:

    [java]?view plaincopy
  • class?Client?{??
  • ????public?static?void?main(String?args[])?{??
  • ????????ScoreOperation?operation;??//針對(duì)抽象目標(biāo)接口編程??
  • ????????operation?=?(ScoreOperation)XMLUtil.getBean();?//讀取配置文件,反射生成對(duì)象??
  • ????????int?scores[]?=?{84,76,50,69,90,91,88,96};?//定義成績(jī)數(shù)組??
  • ????????int?result[];??
  • ????????int?score;??
  • ??????????
  • ????????System.out.println("成績(jī)排序結(jié)果:");??
  • ????????result?=?operation.sort(scores);??
  • ??
  • ????????//遍歷輸出成績(jī)??
  • ????????for(int?i?:?scores)?{??
  • ????????????System.out.print(i?+?",");??
  • ????????}??
  • ????????System.out.println();??
  • ??????????
  • ????????System.out.println("查找成績(jī)90:");??
  • ????????score?=?operation.search(result,90);??
  • ????????if?(score?!=?-1)?{??
  • ????????????System.out.println("找到成績(jī)90。");??
  • ????????}??
  • ????????else?{??
  • ????????????System.out.println("沒(méi)有找到成績(jī)90。");??
  • ????????}??
  • ??????????
  • ????????System.out.println("查找成績(jī)92:");??
  • ????????score?=?operation.search(result,92);??
  • ????????if?(score?!=?-1)?{??
  • ????????????System.out.println("找到成績(jī)92。");??
  • ????????}??
  • ????????else?{??
  • ????????????System.out.println("沒(méi)有找到成績(jī)92。");??
  • ????????}??
  • ????}??
  • }??
  • ??????? 編譯并運(yùn)行程序,輸出結(jié)果如下:

    成績(jī)排序結(jié)果:

    50,69,76,84,88,90,91,96,

    查找成績(jī)90

    找到成績(jī)90

    查找成績(jī)92

    沒(méi)有找到成績(jī)92

    ?????? 在本實(shí)例中使用了對(duì)象適配器模式,同時(shí)引入了配置文件,將適配器類的類名存儲(chǔ)在配置文件中。如果需要使用其他排序算法類和查找算法類,可以增加一個(gè)新的適配器類,使用新的適配器來(lái)適配新的算法,原有代碼無(wú)須修改。通過(guò)引入配置文件和反射機(jī)制,可以在不修改客戶端代碼的情況下使用新的適配器,無(wú)須修改源代碼,符合“開(kāi)閉原則”。

    9.4?類適配器

    ???????除了對(duì)象適配器模式之外,適配器模式還有一種形式,那就是類適配器模式,類適配器模式和對(duì)象適配器模式最大的區(qū)別在于適配器和適配者之間的關(guān)系不同,對(duì)象適配器模式中適配器和適配者之間是關(guān)聯(lián)關(guān)系,而類適配器模式中適配器和適配者是繼承關(guān)系,類適配器模式結(jié)構(gòu)如圖9-5所示:

    ?9-5?類適配器模式結(jié)構(gòu)圖

    ?????? 根據(jù)類適配器模式結(jié)構(gòu)圖,適配器類實(shí)現(xiàn)了抽象目標(biāo)類接口Target,并繼承了適配者類,在適配器類的request()方法中調(diào)用所繼承的適配者類的specificRequest()方法,實(shí)現(xiàn)了適配。

    ?????? 典型的類適配器代碼如下所示:

    [java]?view plaincopy
  • class?Adapter?extends?Adaptee?implements?Target?{??
  • ????public?void?request()?{??
  • ????????specificRequest();??
  • ????}??
  • }??
  • ?????? 由于JavaC#等語(yǔ)言不支持多重類繼承,因此類適配器的使用受到很多限制,例如如果目標(biāo)抽象類Target不是接口,而是一個(gè)類,就無(wú)法使用類適配器;此外,如果適配者Adapter為最終(Final)類,也無(wú)法使用類適配器。在Java等面向?qū)ο缶幊陶Z(yǔ)言中,大部分情況下我們使用的是對(duì)象適配器,類適配器較少使用。

    ?

    思考

    ?????? 在類適配器中,一個(gè)適配器能否適配多個(gè)適配者?如果能,應(yīng)該如何實(shí)現(xiàn)?如果不能,請(qǐng)說(shuō)明原因?

    ??

    ?

    9.5?雙向適配器

    ???????在對(duì)象適配器的使用過(guò)程中,如果在適配器中同時(shí)包含對(duì)目標(biāo)類和適配者類的引用,適配者可以通過(guò)它調(diào)用目標(biāo)類中的方法,目標(biāo)類也可以通過(guò)它調(diào)用適配者類中的方法,那么該適配器就是一個(gè)雙向適配器,其結(jié)構(gòu)示意圖如圖9-6所示:

    9-6?雙向適配器結(jié)構(gòu)示意圖

    ?????? 雙向適配器的實(shí)現(xiàn)較為復(fù)雜,其典型代碼如下所示:

    [java]?view plaincopy
  • class?Adapter?implements?Target,Adaptee?{??
  • ????//同時(shí)維持對(duì)抽象目標(biāo)類和適配者的引用??
  • ????private?Target?target;??
  • ????private?Adaptee?adaptee;??
  • ??????
  • ????public?Adapter(Target?target)?{??
  • ????????this.target?=?target;??
  • ????}??
  • ??????
  • ????public?Adapter(Adaptee?adaptee)?{??
  • ????????this.adaptee?=?adaptee;??
  • ????}??
  • ??????
  • ????public?void?request()?{??
  • ????????adaptee.specificRequest();??
  • ????}??
  • ??????
  • ????public?void?specificRequest()?{??
  • ????????target.request();??
  • ????}??
  • }??
  • ?????? 在實(shí)際開(kāi)發(fā)中,我們很少使用雙向適配器。

    9.6 缺省適配器??????

    ???????缺省適配器模式是適配器模式的一種變體,其應(yīng)用也較為廣泛。缺省適配器模式的定義如下:

    缺省適配器模式(Default Adapter Pattern):當(dāng)不需要實(shí)現(xiàn)一個(gè)接口所提供的所有方法時(shí),可先設(shè)計(jì)一個(gè)抽象類實(shí)現(xiàn)該接口,并為接口中每個(gè)方法提供一個(gè)默認(rèn)實(shí)現(xiàn)(空方法),那么該抽象類的子類可以選擇性地覆蓋父類的某些方法來(lái)實(shí)現(xiàn)需求,它適用于不想使用一個(gè)接口中的所有方法的情況,又稱為單接口適配器模式。

    ?????? 缺省適配器模式結(jié)構(gòu)如圖9-7所示:

    ?

    9-7??缺省適配器模式結(jié)構(gòu)圖

    ?????? 在缺省適配器模式中,包含如下三個(gè)角色:

    ??????●?ServiceInterface(適配者接口):它是一個(gè)接口,通常在該接口中聲明了大量的方法。

    ??????●?AbstractServiceClass(缺省適配器類):它是缺省適配器模式的核心類,使用空方法的形式實(shí)現(xiàn)了在ServiceInterface接口中聲明的方法。通常將它定義為抽象類,因?yàn)閷?duì)它進(jìn)行實(shí)例化沒(méi)有任何意義。

    ??????●?ConcreteServiceClass(具體業(yè)務(wù)類):它是缺省適配器類的子類,在沒(méi)有引入適配器之前,它需要實(shí)現(xiàn)適配者接口,因此需要實(shí)現(xiàn)在適配者接口中定義的所有方法,而對(duì)于一些無(wú)須使用的方法也不得不提供空實(shí)現(xiàn)。在有了缺省適配器之后,可以直接繼承該適配器類,根據(jù)需要有選擇性地覆蓋在適配器類中定義的方法。

    ?????? 在JDK類庫(kù)的事件處理包java.awt.event中廣泛使用了缺省適配器模式,如WindowAdapterKeyAdapterMouseAdapter等。下面我們以處理窗口事件為例來(lái)進(jìn)行說(shuō)明:在Java語(yǔ)言中,一般我們可以使用兩種方式來(lái)實(shí)現(xiàn)窗口事件處理類,一種是通過(guò)實(shí)現(xiàn)WindowListener接口,另一種是通過(guò)繼承WindowAdapter適配器類。如果是使用第一種方式,直接實(shí)現(xiàn)WindowListener接口,事件處理類需要實(shí)現(xiàn)在該接口中定義的七個(gè)方法,而對(duì)于大部分需求可能只需要實(shí)現(xiàn)一兩個(gè)方法,其他方法都無(wú)須實(shí)現(xiàn),但由于語(yǔ)言特性我們不得不為其他方法也提供一個(gè)簡(jiǎn)單的實(shí)現(xiàn)(通常是空實(shí)現(xiàn)),這給使用帶來(lái)了麻煩。而使用缺省適配器模式就可以很好地解決這一問(wèn)題,在JDK中提供了一個(gè)適配器類WindowAdapter來(lái)實(shí)現(xiàn)WindowListener接口,該適配器類為接口中的每一個(gè)方法都提供了一個(gè)空實(shí)現(xiàn),此時(shí)事件處理類可以繼承WindowAdapter類,而無(wú)須再為接口中的每個(gè)方法都提供實(shí)現(xiàn)。如圖9-8所示:

    ?

    9-8? WindowListenerWindowAdapter結(jié)構(gòu)圖

    ?

    9.7 適配器模式總結(jié)

    ????? 適配器模式將現(xiàn)有接口轉(zhuǎn)化為客戶類所期望的接口,實(shí)現(xiàn)了對(duì)現(xiàn)有類的復(fù)用,它是一種使用頻率非常高的設(shè)計(jì)模式,在軟件開(kāi)發(fā)中得以廣泛應(yīng)用,在Spring等開(kāi)源框架、驅(qū)動(dòng)程序設(shè)計(jì)(如JDBC中的數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序)中也使用了適配器模式。

    ?

    ?????? 1.?主要優(yōu)點(diǎn)

    ?????? 無(wú)論是對(duì)象適配器模式還是類適配器模式都具有如下優(yōu)點(diǎn):

    ?????? (1)?將目標(biāo)類和適配者類解耦,通過(guò)引入一個(gè)適配器類來(lái)重用現(xiàn)有的適配者類,無(wú)須修改原有結(jié)構(gòu)。

    ?????? (2)?增加了類的透明性和復(fù)用性,將具體的業(yè)務(wù)實(shí)現(xiàn)過(guò)程封裝在適配者類中,對(duì)于客戶端類而言是透明的,而且提高了適配者的復(fù)用性,同一個(gè)適配者類可以在多個(gè)不同的系統(tǒng)中復(fù)用。

    ?????? (3)?靈活性和擴(kuò)展性都非常好,通過(guò)使用配置文件,可以很方便地更換適配器,也可以在不修改原有代碼的基礎(chǔ)上增加新的適配器類,完全符合“開(kāi)閉原則”。

    ????? 具體來(lái)說(shuō),類適配器模式還有如下優(yōu)點(diǎn):

    ????? 由于適配器類是適配者類的子類,因此可以在適配器類中置換一些適配者的方法,使得適配器的靈活性更強(qiáng)。

    ????? 對(duì)象適配器模式還有如下優(yōu)點(diǎn):

    ????? (1)?一個(gè)對(duì)象適配器可以把多個(gè)不同的適配者適配到同一個(gè)目標(biāo)

    ????? (2)?可以適配一個(gè)適配者的子類,由于適配器和適配者之間是關(guān)聯(lián)關(guān)系,根據(jù)“里氏代換原則”,適配者的子類也可通過(guò)該適配器進(jìn)行適配。

    ?

    ????? 2.?主要缺點(diǎn)

    ?????類適配器模式的缺點(diǎn)如下:

    ????? (1)?對(duì)于JavaC#等不支持多重類繼承的語(yǔ)言,一次最多只能適配一個(gè)適配者類,不能同時(shí)適配多個(gè)適配者

    ????? (2)?適配者類不能為最終類,如在Java中不能為final類,C#中不能為sealed類;

    ????? (3)?JavaC#等語(yǔ)言中,類適配器模式中的目標(biāo)抽象類只能為接口,不能為類,其使用有一定的局限性。

    ??????對(duì)象適配器模式的缺點(diǎn)如下:

    ????? 與類適配器模式相比,要在適配器中置換適配者類的某些方法比較麻煩。如果一定要置換掉適配者類的一個(gè)或多個(gè)方法,可以先做一個(gè)適配者類的子類,將適配者類的方法置換掉,然后再把適配者類的子類當(dāng)做真正的適配者進(jìn)行適配,實(shí)現(xiàn)過(guò)程較為復(fù)雜。

    ?

    ????? 3.?適用場(chǎng)景

    ????? 在以下情況下可以考慮使用適配器模式:

    ?????? (1)?系統(tǒng)需要使用一些現(xiàn)有的類,而這些類的接口(如方法名)不符合系統(tǒng)的需要,甚至沒(méi)有這些類的源代碼。

    ?????? (2)?想創(chuàng)建一個(gè)可以重復(fù)使用的類,用于與一些彼此之間沒(méi)有太大關(guān)聯(lián)的一些類,包括一些可能在將來(lái)引進(jìn)的類一起工作。

    ?

    練習(xí)

    ?????? Sunny軟件公司OA系統(tǒng)需要提供一個(gè)加密模塊,將用戶機(jī)密信息(如口令、郵箱等)加密之后再存儲(chǔ)在數(shù)據(jù)庫(kù)中,系統(tǒng)已經(jīng)定義好了數(shù)據(jù)庫(kù)操作類。為了提高開(kāi)發(fā)效率,現(xiàn)需要重用已有的加密算法,這些算法封裝在一些由第三方提供的類中,有些甚至沒(méi)有源代碼。試使用適配器模式設(shè)計(jì)該加密模塊,實(shí)現(xiàn)在不修改現(xiàn)有類的基礎(chǔ)上重用第三方加密方法。




    超強(qiáng)干貨來(lái)襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

    總結(jié)

    以上是生活随笔為你收集整理的不兼容结构的协调——适配器模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。