Java擴充卡模式
擴充卡模式的核心思想
擴充卡模式把一個類的接口變換成用戶端所期待的另一種接口,進而使原本因接口不比對而無法在一起工作的兩個類能夠在一起工作。
簡單比方:用電器做例子,筆記本電腦的插頭一般都是三相的,即除了陽極、陰極外,還有一個地極。而有些地方的電源插座卻隻有兩極,沒有地極。電源插座與筆記本電腦的電源插頭不比對使得筆記本電腦無法使用。這時候一個三相到兩相的轉換器(擴充卡)就能解決此問題,而這正像是本模式所做的事情。
擴充卡模式分為類的擴充卡和對象的擴充卡
類的擴充卡

可以看出被适配者和目标對象之間不能完全比對,被适配者缺少方法operation1(),為了使目标對象能夠使用被适配對象,是以增加了一個适配對象Adapter,通過Adapter将Adaptee與Target銜接起來,因為Adapter是繼承Adaptee的,是以此為類的擴充卡模式。
目标對象:
public interface Target{
void operation0();
void operation1();
}
被适配對象:
public class Adaptee{
void operation0(){
//TODO
}
//缺少operation1方法
}
适配對象
public class Adapter extends Adaptee implements Target{
//補充operation1方法以适配目标對象
void operation1(){
//TODO
}
}
對象擴充卡
與類的擴充卡模式一樣,對象的擴充卡模式是通過适配類把被适配的類的API轉換成為目标類的API,與類的擴充卡模式不同的是,對象的擴充卡模式不是使用繼承關系連接配接到Adaptee類,而是使用委派關系連接配接到Adaptee類。
由圖可以看出,Adaptee類并沒有operation0()方法,而目标對象則需要此方法。為使目标對象能夠使用Adaptee類,需要提供一個包裝(Wrapper)類Adapter。這個包裝類包裝了一個Adaptee的執行個體,進而此包裝類能夠把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是委派關系,是以該模式屬于對象的擴充卡模式。
public interface Target{
void operation0();
void operation1();
}
public class Adaptee{
void operation0(){
//TODO what you want do
}
//缺少operation1方法
}
public class Adapter{
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
//補充operation1方法以适配目标對象
void operation1(){
adaptee.operation1();
}
void operation0(){
//TODO
}
}
類擴充卡和對象擴充卡的權衡
- 類擴充卡使用對象繼承的方式,是靜态的定義方式;而對象擴充卡使用對象組合的方式,是動态組合的方式。
- 對于類擴充卡,由于擴充卡直接繼承了Adaptee,使得擴充卡不能和Adaptee的子類一起工作,因為繼承是靜态的關系,當擴充卡繼承了Adaptee後,就不可能再去處理Adapter的子類了。
- 對于對象擴充卡,一個擴充卡可以把多種不同的源适配到同一個目标。換言之,同一個擴充卡可以把源類和它的子類都适配到目标接口。因為對象擴充卡采用的是對象組合的關系,隻要對象類型正确,是不是子類都無所謂。
- 對于類擴充卡,擴充卡可以重定義Adaptee的部分行為,相當于子類覆寫父類的部分實作方法。
- 對于對象擴充卡,要重定義Adaptee的行為比較困難,這種情況下,需要定義Adaptee的子類來實作重定義,然後讓擴充卡組合子類。雖然重定義Adaptee的行為比較困難,但是想要增加一些新的行為則友善的很,而且新增加的行為可同時适用于所有的源。
- 對于類擴充卡,僅僅引入了一個對象,并不需要額外的引用來間接得到Adaptee。
- 對于對象擴充卡,需要額外的引用來間接得到Adaptee。
建議盡量使用對象擴充卡的實作方式,多用合成/聚合、少用繼承。當然,具體問題具體分析,根據需要來選用實作方式,最适合的才是最好的。
擴充卡模式的優點
- 更好的複用性
- 系統需要使用現有的類,而此類的接口不符合系統的需要。那麼通過擴充卡模式就可以讓這些功能得到更好的複用。
- 更好的擴充性
- 在實作擴充卡功能的時候,可以調用自己開發的功能,進而自然地擴充系統的功能。
擴充卡模式的缺點
- 過多的使用擴充卡,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是A接口,其實内部被适配成了B接口的實作,一個系統如果太多出現這種情況,無異于一場災難。是以如果不是很有必要,可以不使用擴充卡,而是直接對系統進行重構。