適配器模式


一:生活中一些實(shí)例?
???? 簡單說現(xiàn)在家庭中使用的電器一般要求電壓是220V的,但是有的電器使用要求的電壓是110V,怎么辦呢?我們直接在110V電壓電器上直接安裝一個(gè)變壓器這樣不就行了嗎?這樣我們不就可以使用110V電壓的電器了嗎?
??? 相信很多人都知道恒大足球隊(duì)吧,他們隊(duì)里有一些外援,他們語言不同,他們是怎么交流了,按照我們想,讓對(duì)內(nèi)的球員都會(huì)說中文不就好了。這樣對(duì)內(nèi)的交流問題不就解決了。

二:上面實(shí)現(xiàn)功能中會(huì)出現(xiàn)什么問題呢?
???? 如果使用電器中出現(xiàn)其他電壓電器,或者有很多110V電壓的電器,我們就需要每次都添加一個(gè)變壓器,給沒有這個(gè)轉(zhuǎn)換電壓功能,每一次都需要添加一次方法。這樣做的,每一次都需要我們?nèi)ヌ砑臃椒ǎ薷睦锩嬖a,這樣做違反開閉原則,那么我們要如何做呢?我們可以在外面是先一個(gè)接口,然后將轉(zhuǎn)化方法放在里面,我們需要時(shí)候就去調(diào)用,這樣不是會(huì)很方便。
??? 同樣的如果隊(duì)里球員都學(xué)習(xí)中文,第一不說中文學(xué)期很難,第二學(xué)習(xí)也很占用時(shí)間,這樣會(huì)影響球員的休息還有訓(xùn)練。但是如果我們給球員帶一個(gè)翻譯器呢?是不是這樣問題就解決了呢?

三:再設(shè)計(jì)模式中:適配器模式
在適配器模式中如何解決電壓問題呢?
?? 創(chuàng)建接口:


定義變壓器類:


定義改變適配器的類:


定義變壓器地輸出110V:


定義輸出220V電壓類:


這樣我們就在原有類的基礎(chǔ)上,實(shí)現(xiàn)調(diào)用,也解決每次都需要添加麻煩。也讓兩個(gè)不能在一起工作在一起工作。


四:適配器模式定義:
適配器模式(Adapter):就是把一個(gè)類的接口轉(zhuǎn)換成客戶所期待的另一種接口。Adapter使得原本由于接口不兼容而不能在一起工作的那些類可以在一起工作。

一) 適配器模式的結(jié)構(gòu)
?????? 適配器模式有類的適配器模式和對(duì)象的適配器模式兩種不同的形式。
?????? 類適配器通過繼承,是靜態(tài)的定義方式。
?????? 對(duì)象適配器通過代理,是動(dòng)態(tài)組合的方式。
類適配器模式
?????? 類適配器模式把適配的類API轉(zhuǎn)換成目標(biāo)類的API



??? 從圖中可以看出Adaptee中沒有sampleOperation2()方法,而客戶端則期待這個(gè)方法。為了使客戶端能夠使用這個(gè)Apaptee類,所以提供一個(gè)中間環(huán)節(jié),即類Adapter,也就是這個(gè)類把Adaptee與Target類銜接起來。Adapter與Apaptee是繼承關(guān)系,這就決定是類適配器模式。


模式中角色:


?目標(biāo)(Target) 角色:目標(biāo)角色,期待得到的接口。


?源(Adapee)角色: 適配者角色,現(xiàn)在需要適配的接口。


?適配器(Adapter)角色:適配器角色,適配器類是本模式核心。適配器把源接口轉(zhuǎn)換成目標(biāo)接口。顯然這一角色不可能是接口,而必須是具體類。


代碼樣例:


目標(biāo)角色:

源(Adapee)角色:

適配器角色Adapter:

對(duì)象適配器模式
與類的適配器模式一樣,對(duì)像的適配器模式把被適配器的類的API轉(zhuǎn)換成目標(biāo)類的API,與類適配器不同的是,對(duì)象適配器模式不使用繼承關(guān)系連接到Adaptee類,使用了委派關(guān)系連接到了Adaptee類。

從圖中可以看出Adaptee類中沒有sampleOperation2()方法,客戶端是期待這個(gè)方法的。為了使客戶端能夠使用Adaptee類,我們需要提供一個(gè)包裝(Wrapper類)Adapter。這個(gè)包裝類包裝一個(gè)Adatee的實(shí)例,從而能使的包裝類能把Adaptee的API與Target類的API銜接起來。Adater與Adaptee是委派關(guān)系,這就決定是對(duì)象適配器模式
目標(biāo)角色:

源角色:

適配器角色:

我們了解適配器模式,那么我們看看實(shí)際項(xiàng)目中我們應(yīng)當(dāng)怎么使用呢?
例如公司購買了一個(gè)驗(yàn)證客戶信息的離架產(chǎn)品類InfoValidation,但是賣方?jīng)]有提供源碼。此類只提供用于檢查客戶輸入的信息,包含驗(yàn)證姓名、地址、電話區(qū)號(hào)、手機(jī)號(hào)等功能。現(xiàn)在公司需要增加一個(gè)驗(yàn)證社會(huì)安全號(hào)(SSN)的功能,這里我們不就可以使用類適配器來做嗎?這里我們首先想一下類適配器結(jié)構(gòu),然后來構(gòu)建這里所要實(shí)現(xiàn)結(jié)構(gòu)。

結(jié)構(gòu)部分:


下面是我們代碼實(shí)現(xiàn)部分:
根據(jù)我們以上結(jié)構(gòu)來一步一步實(shí)現(xiàn)我們代碼部分:這樣就會(huì)非常簡單
首先編寫接口部分:
public interface CusInfoValidator {

?public abstract boolean isValidName(String name);
?public abstract boolean isValidAddress(String address);
?public abstract boolean isValidZipCode(String zipCode);
?public abstract boolean isValidCellPhoneNum(String phoneNum);
?public abstract boolean isValidSSNNum(String SSNNum);
}
是不是跟我們結(jié)構(gòu)一樣的

接下來我們?cè)賮砭帉懰^承類InfoValidation類(被適配器類)
Class InfoValidation? {

??? public abstract boolean isValidName(String name)? {
??????? boolean isValid=true;
???? String ns = name.trim();
???? String nStr = ns.replaceAll("\\b\\s{1,}\\b", "");
???? int len = nStr.length();

???? System.out.println("******Length = " + len);

???? if(len != 0 ){
??????? for(int m=0; m<len; m++){
?????????? if(Character.isDigit(nStr.charAt(m))==true)
????????????? isValid=false;
??????? }
??????? return isValid;
??????? }
??????? else{
??????? return false;
???? }
??? }
?public abstract boolean isValidAddress(String address){代碼省略}
?public abstract boolean isValidZipCode(String zipCode){代碼省略}
?public abstract boolean isValidCellPhoneNum(String phoneNum){代碼省略}
}

實(shí)現(xiàn)我們適配器代碼:
class InformationAdapter extends InfoValidation implements CusInfoValidator{
??? public boolean isValidSSNNum(String SSNNum){
??? boolean isValid=true;
?????? String ns = SSNNum.trim();
??? String nStr = ns.replaceAll("\\s{1,}", "");
??? int len = nStr.length();

??? if ( (nStr.charAt(3) == '-') && (nStr.charAt(6) == '-') && (len==11) ) {
?????? for(int m=0; m<len; m++){
?????? if(? (m != 3) && (m !=6) && ( Character.isDigit(nStr.charAt(m))==false) ){
????????? isValid=false;
?????? }
?????? }
?????? return isValid;
??? }
??? else{
??? return false;
??? }
?}
}

這樣我們就在原有功能上添加一個(gè)社會(huì)安全號(hào)SSN驗(yàn)證功能。通過這個(gè)實(shí)例,可能就會(huì)有會(huì)問:“適配器模式是不是就是給源角色增加新的方法!”,這樣說也對(duì)但是不全面。
在適配器模式定義中主要講的是讓接口變換成客戶端所期待一種接口,也就是說‘適配器模式’可以用于增加新的方法,但主要還是轉(zhuǎn)換接口。例如下面一般是我們?nèi)宋镄畔⒗樱?/p>


上面結(jié)構(gòu)途中在Person類中是沒有g(shù)etDepartment() 方法,在適配器改變Person類構(gòu)造函數(shù)的參數(shù),添加了demartment參數(shù),適配器是改變是接口。我們這個(gè)設(shè)計(jì)目的不是增加方法,而是改變接口。

五: 我們又該怎么權(quán)衡類配置器和對(duì)象適配器呢,它們又有什么特點(diǎn)呢?
??? 在上面我們寫到類適配器是適用對(duì)象繼承的方式,是靜態(tài)的方式,而對(duì)象適配使用時(shí)對(duì)象組合方式,是動(dòng)態(tài)組合方式。
??? 對(duì)于類適配器,由于適配器直接繼承了Adaptee,使得適配器不能和Adaptee的子類一起工作,因?yàn)槔^承是靜態(tài)的關(guān)系,當(dāng)適配器繼承了Adaptee后,就不可能再去處理? Adaptee的子類了。
   對(duì)于對(duì)象適配器,一個(gè)適配器可以把多種不同的源適配到同一個(gè)目標(biāo)。換言之,同一個(gè)適配器可以把源類和它的子類都適配到目標(biāo)接口。因?yàn)閷?duì)象適配器采用的是對(duì)象組合的關(guān)系,只要對(duì)象類型正確,是不是子類都無所謂。
 ? 對(duì)于類適配器,適配器可以重定義Adaptee的部分行為,相當(dāng)于子類覆蓋父類的部分實(shí)現(xiàn)方法。
  對(duì)于對(duì)象適配器,要重定義Adaptee的行為比較困難,這種情況下,需要定義Adaptee的子類來實(shí)現(xiàn)重定義,然后讓適配器組合子類。雖然重定義Adaptee的行為比較困難,但是想要增加一些新的行為則方便的很,而且新增加的行為可同時(shí)適用于所有的源。
 對(duì)于類適配器,僅僅引入了一個(gè)對(duì)象,并不需要額外的引用來間接得到Adaptee。
 對(duì)于對(duì)象適配器,需要額外的引用來間接得到Adaptee。
建議盡量使用對(duì)象適配器的實(shí)現(xiàn)方式,多用合成/聚合、少用繼承。當(dāng)然,具體問題具體分析,根據(jù)需要來選用實(shí)現(xiàn)方式,最適合的才是最好的。

六:那么又有哪些適配器模式的又有哪些優(yōu)缺點(diǎn)呢?
優(yōu)點(diǎn):
?? 1.將目標(biāo)類和適配者類解耦,通過一入一個(gè)適配器類來重用現(xiàn)有的適配者類,而無需要修改原有代碼。
?? 2.增加了類的透明度和復(fù)用性,將具體的實(shí)現(xiàn)封裝在適配者類中,對(duì)于客戶端類來說是透明的,而且提高了適配者的復(fù)用性。
?? 3.靈活性和擴(kuò)展性都非常好,通過使用配置文件可以很方便的更換適配器,也可以在不修改原有代碼基礎(chǔ)上增加新的適配器類,完全符合“開閉原則”。
缺點(diǎn):
過多的使用適配器,會(huì)讓系統(tǒng)非常零亂,不易整體進(jìn)行把握。比如,明明看到調(diào)用的是A接口,其實(shí)內(nèi)部被適配成了B接口的實(shí)現(xiàn),一個(gè)系統(tǒng)如果太多出現(xiàn)這種情況,無異于一場災(zāi)難。因此如果不是很有必要,可以不使用適配器,而是直接對(duì)系統(tǒng)進(jìn)行重構(gòu)。

七:我們又該怎樣使用適配器呢?
? 使用場景:
?1).系統(tǒng)中需要使用現(xiàn)有類,而這個(gè)類接口不符合系統(tǒng)的需要,也就是不兼容
?2).想要建立一個(gè)可重復(fù)使用的類,用于關(guān)聯(lián)彼此沒有太大聯(lián)系的一些類
?3).需要一個(gè)統(tǒng)一的輸出接口,而輸入端類型不確定

八:適配器模式總結(jié)
??? 適配器模式可以重用一個(gè)現(xiàn)有的類,滿足客戶需求,將客戶端的調(diào)用轉(zhuǎn)化為現(xiàn)有方法調(diào)用。
??? 類適配器:客戶端的需求通過接口表達(dá)出來,可以創(chuàng)建一個(gè)實(shí)現(xiàn)該接口的適配類,適配類同時(shí)還要繼承現(xiàn)有類。
??? 對(duì)象適配器:客戶端沒有指定接口,創(chuàng)建一個(gè)新的適配器類,實(shí)現(xiàn)繼承客戶端類,在該類中維護(hù)一個(gè)現(xiàn)有的類實(shí)例對(duì)象作為成員變量。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容