一、適配器(Adapter)模式
是把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。
二、優點
- 更好的復用性
系統需要使用現有的類,而此類的接口不符合系統的需要。那么通過適配器模式就可以讓這些功能得到更好的復用。
- 更好的擴展性
在實現適配器功能的時候,可以調用自己開發的功能,從而自然地擴展系統的功能。
三、缺點
過多的使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是A接口,其實內部被適配成了B接口的實現,一個系統如果太多出現這種情況,無異于一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
四、用途
用電器做例子,筆記本電腦的插頭一般都是三相的,即除了陽極、陰極外,還有一個地極。而有些地方的電源插座卻只有兩極,沒有地極。電源插座與筆記本電腦的電源插頭不匹配使得筆記本電腦無法使用。這時候一個三相到兩相的轉換器(適配器)就能解決此問題,而這正像是本模式所做的事情。
五、結構
適配器模式有類的適配器模式和對象的適配器模式兩種不同的形式。
① 類適配器模式(類的適配器模式把適配的類的API轉換成為目標類的API。)
在上圖中可以看出,Adaptee類并沒有sampleOperation2()方法,而客戶端則期待這個方法。為使客戶端能夠使用Adaptee類,提供一個中間環節,即類Adapter,把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是繼承關系,這決定了這個適配器模式是類的:
模式所涉及的角色有:
● 目標(Target)角色:這就是所期待得到的接口。注意:由于這里討論的是類適配器模式,因此目標不可以是類。
● 源(Adapee)角色:現在需要適配的接口。
● 適配器(Adaper)角色:適配器類是本模式的核心。適配器把源接口轉換成目標接口。顯然,這一角色不可以是接口,而必須是具體類。
eg:
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是委派關系,這決定了適配器模式是對象的。
eg:
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(){ //寫相關的代碼 } }
文章列表