1 類適配器模式:
類的適配器模式把適配的類的API轉(zhuǎn)換成為目標(biāo)類的API疗绣。
在上圖中可以看出,Adaptee類并沒有sampleOperation2()方法,而客戶端則期待這個(gè)方法盼樟。為使客戶端能夠使用Adaptee類同窘,提供一個(gè)中間環(huán)節(jié),即類Adapter葵萎,把Adaptee的API與Target類的API銜接起來导犹。Adapter與Adaptee是繼承關(guān)系,這決定了這個(gè)適配器模式是類的:
public interface Target {
public void method1();
public void method2();
}
public class Adaptee {
public void method1(){
System.out.println("method1 from Adaptee");
}
}
public class AdapterTestClass extends Adaptee implements Target{
@Override
public void method2() {
// TODO Auto-generated method stub
System.out.println("method2 implements target interface");
}
public static void main(String[] args) {
AdapterTestClass testClass = new AdapterTestClass();
testClass.method1();
testClass.method2();
}
}
2 對象適配器模式
與類的適配器模式一樣羡忘,對象的適配器模式把被適配的類的API轉(zhuǎn)換成為目標(biāo)類的API谎痢,與類的適配器模式不同的是,對象的適配器模式不是使用繼承關(guān)系連接到Adaptee類卷雕,而是使用委派關(guān)系連接到Adaptee類节猿。
(既不繼承Adaptee 也不實(shí)現(xiàn)接口target)
public class AdapterTestClass2 {
private Adaptee adaptee;
public AdapterTestClass2(Adaptee tee){
this.adaptee = tee;
}
public void method1(){
this.adaptee.method1();
}
public void method2(){
System.out.println("method2 in AdapterTestClass2~");
}
public static void main(String[] args) {
new AdapterTestClass2(new Adaptee()).method1();
new AdapterTestClass2(new Adaptee()).method2();
}
}
類適配器和對象適配器的權(quán)衡
●類適配器使用對象繼承的方式,是靜態(tài)的定義方式;而對象適配器使用對象組合的方式滨嘱,是動態(tài)組合的方式峰鄙。
●對于類適配器,由于適配器直接繼承了Adaptee太雨,使得適配器不能和Adaptee的子類一起工作吟榴,因?yàn)槔^承是靜態(tài)的關(guān)系,當(dāng)適配器繼承了Adaptee后囊扳,就不可能再去處理? Adaptee的子類了吩翻。
對于對象適配器,一個(gè)適配器可以把多種不同的源適配到同一個(gè)目標(biāo)锥咸。換言之狭瞎,同一個(gè)適配器可以把源類和它的子類都適配到目標(biāo)接口。因?yàn)閷ο筮m配器采用的是對象組合的關(guān)系搏予,只要對象類型正確熊锭,是不是子類都無所謂。
●對于類適配器雪侥,適配器可以重定義Adaptee的部分行為碗殷,相當(dāng)于子類覆蓋父類的部分實(shí)現(xiàn)方法。
對于對象適配器校镐,要重定義Adaptee的行為比較困難亿扁,這種情況下,需要定義Adaptee的子類來實(shí)現(xiàn)重定義鸟廓,然后讓適配器組合子類从祝。雖然重定義Adaptee的行為比較困難,但是想要增加一些新的行為則方便的很引谜,而且新增加的行為可同時(shí)適用于所有的源牍陌。
●對于類適配器,僅僅引入了一個(gè)對象员咽,并不需要額外的引用來間接得到Adaptee毒涧。
對于對象適配器,需要額外的引用來間接得到Adaptee贝室。
建議盡量使用對象適配器的實(shí)現(xiàn)方式契讲,多用合成/聚合、少用繼承滑频。當(dāng)然捡偏,具體問題具體分析,根據(jù)需要來選用實(shí)現(xiàn)方式峡迷,最適合的才是最好的银伟。
適配器模式的優(yōu)點(diǎn)
更好的復(fù)用性
系統(tǒng)需要使用現(xiàn)有的類你虹,而此類的接口不符合系統(tǒng)的需要。那么通過適配器模式就可以讓這些功能得到更好的復(fù)用彤避。
更好的擴(kuò)展性
在實(shí)現(xiàn)適配器功能的時(shí)候傅物,可以調(diào)用自己開發(fā)的功能,從而自然地?cái)U(kuò)展系統(tǒng)的功能琉预。
適配器模式的缺點(diǎn)
過多的使用適配器董饰,會讓系統(tǒng)非常零亂,不易整體進(jìn)行把握圆米。比如尖阔,明明看到調(diào)用的是A接口,其實(shí)內(nèi)部被適配成了B接口的實(shí)現(xiàn)榨咐,一個(gè)系統(tǒng)如果太多出現(xiàn)這種情況,無異于一場災(zāi)難谴供。因此如果不是很有必要块茁,可以不使用適配器,而是直接對系統(tǒng)進(jìn)行重構(gòu)桂肌。
3 缺省適配模式
缺省適配(Default Adapter)模式為一個(gè)接口提供缺省實(shí)現(xiàn)数焊,這樣子類型可以從這個(gè)缺省實(shí)現(xiàn)進(jìn)行擴(kuò)展,而不必從原有接口進(jìn)行擴(kuò)展崎场。作為適配器模式的一個(gè)特例佩耳,缺省是適配模式在JAVA語言中有著特殊的應(yīng)用。
缺省適配模式是一種“平庸”化的適配器模式谭跨。(實(shí)現(xiàn)類不必實(shí)現(xiàn)接口所有方法或留空的方法干厚,可以有選擇性了)
public interface DefaultImp {
public? void m1();
public? void m2();
public? void m3();
public? void m4();
public? void m5();
public? void mustBeImp();
}
public abstract class? AbstractDefautImp implements DefaultImp {
/* 可以只 些部分方法*/
public? void m1(){};
public? void m2(){};
public? void m3(){};
public? void m4(){};
public? void m5(){};
public void mustBeImp() {
System.out.println("mustBeImp method in AbstractDefautImp");
}
}
public class AdapterTestClass3 extends AbstractDefautImp{
/*** (實(shí)現(xiàn)類不必實(shí)現(xiàn)接口所有方法或留空的方法,可以有選擇性了)***/
@Override
public void m1() {System.out.println("m1 Override in Adaptertestclass3");};
public static void main(String[] args) {
AdapterTestClass3 test? = new AdapterTestClass3();
test.m1();
test.mustBeImp();
}
}