文章摘抄至 http://www.cnblogs.com/java-my-life/archive/2012/04/13/2442795.html
?
適配器模式把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。
? ?
適配器模式的用途
用電器做例子,筆記本電腦的插頭一般都是三相的,即除了陽極、陰極外,還有一個地極。而有些地方的電源插座卻只有兩極,沒有地極。電源插座與筆記本電腦的電源插頭不匹配使得筆記本電腦無法使用。這時候一個三相到兩相的轉換器(適配器)就能解決此問題,而這正像是本模式所做的事情。
? ?
適配器模式的結構
適配器模式有 類的適配器模式 和 對象的適配器模式 兩種不同的形式。
?
類適配器模式
類的適配器模式把適配的類的API轉換成為目標類的API。
??
?
在上圖中可以看出,Adaptee類并沒有sampleOperation2()方法,而客戶端則期待這個方法。為使客戶端能夠使用Adaptee類,提供一個中間環節,即類Adapter,把Adaptee的API與Target類的API銜接起來。 Adapter與Adaptee是繼承關系,這決定了這個適配器模式是類的 :
?
?
模式所涉及的角色有:
目標(Target)角色 :這就是所期待得到的接口。注意:由于這里討論的是類適配器模式,因此目標不可以是類。
源(Adapee)角色 :現在需要適配的接口。
適配器(Adaper)角色 :適配器類是本模式的核心。適配器把源接口轉換成目標接口。顯然,這一角色不可以是接口,而必須是具體類。
??
public interface Target { /** * 這是源類Adaptee也有的方法 */ public void sampleOperation1(); /** * 這是源類Adapteee沒有的方法 */ public void sampleOperation2(); }
?
? ?? 上面給出的是目標角色的源代碼,這個角色是以一個JAVA接口的形式實現的。可以看出,這個接口聲明了兩個方法:sampleOperation1()和sampleOperation2()。而源角色Adaptee是一個具體類,它有一個sampleOperation1()方法,但是沒有sampleOperation2()方法。
?
?public class Adaptee {
public void sampleOperation1(){} }
?
? 適配器角色Adapter擴展了Adaptee,同時又實現了目標(Target)接口。由于Adaptee沒有提供sampleOperation2()方法,而目標接口又要求這個方法,因此適配器角色Adapter實現了這個方法。
?
public class Adapter extends Adaptee implements Target { /** * 由于源類Adaptee沒有方法sampleOperation2() * 因此適配器補充上這個方法 */ @Override public void sampleOperation2() { //寫相關的代碼 } }
?
對象適配器模式
? ? 與類的適配器模式一樣,對象的適配器模式把被適配的類的API轉換成為目標類的API,與類的適配器模式不同的是, 對象的適配器模式不是使用繼承關系連接到Adaptee類,而是使用委派關系連接到Adaptee類
?
?
?
Adaptee類并沒有sampleOperation2()方法,而客戶端則期待這個方法。為使客戶端能夠使用Adaptee類,需要提供一個包裝(Wrapper)類Adapter。這個包裝類包裝了一個Adaptee的實例,從而此包裝類能夠把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是委派關系,這決定了適配器模式是對象的。
?
public interface Target { /** * 這是源類Adaptee也有的方法 */ public void sampleOperation1(); /** * 這是源類Adapteee沒有的方法 */ public void sampleOperation2(); }
?
public class Adaptee { public void sampleOperation1(){} }
?
public class Adapter { private Adaptee adaptee; public Adapter(Adaptee adaptee){ this.adaptee = adaptee; } /** * 源類Adaptee有方法sampleOperation1 * 因此適配器類直接委派即可 */ public void sampleOperation1(){ this.adaptee.sampleOperation1(); } /** * 源類Adaptee沒有方法sampleOperation2 * 因此由適配器類需要補充此方法 */ public void sampleOperation2(){ //寫相關的代碼 } }
?
類適配器和對象適配器的權衡?
類適配器使用對象繼承的方式,是靜態的定義方式;而對象適配器使用對象組合的方式,是動態組合的方式。
?
對于類適配器 ,由于適配器直接繼承了Adaptee,使得適配器不能和Adaptee的子類一起工作,因為繼承是靜態的關系,當適配器繼承了Adaptee后,就不可能再去處理 ?Adaptee的子類了。
?
?對于對象適配器,一個適配器可以把多種不同的源適配到同一個目標。換言之,同一個適配器可以把源類和它的子類都適配到目標接口。因為對象適配器采用的是對象組合的關系,只要對象類型正確,是不是子類都無所謂。
?
對于類適配器 ,適配器可以重定義Adaptee的部分行為,相當于子類覆蓋父類的部分實現方法。
?
?對于對象適配器,要重定義Adaptee的行為比較困難,這種情況下,需要定義Adaptee的子類來實現重定義,然后讓適配器組合子類。雖然重定義Adaptee的行為比較困難,但是想要增加一些新的行為則方便的很,而且新增加的行為可同時適用于所有的源。
?
對于類適配器 ,僅僅引入了一個對象,并不需要額外的引用來間接得到Adaptee。
?
對于對象適配器 ,需要額外的引用來間接得到Adaptee。
?
建議盡量使用對象適配器的實現方式,多用合成/聚合、少用繼承 。當然,具體問題具體分析,根據需要來選用實現方式,最適合的才是最好的。
?
適配器模式的優點
更好的復用性
系統需要使用現有的類,而此類的接口不符合系統的需要。那么通過適配器模式就可以讓這些功能得到更好的復用。
?
更好的擴展性
在實現適配器功能的時候,可以調用自己開發的功能,從而自然地擴展系統的功能。
?
適配器模式的缺點
過多的使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是A接口,其實內部被適配成了B接口的實現,一個系統如果太多出現這種情況,無異于一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
