記得剛學Java SE的AWT(新版Swing)編程的時候,那個時候自己特別興奮,因為學了那么久的Java了,沒看到一點實在點的東西,覺得很沒有成就感。后來學到Swing的時候,用它編寫圖形化界面,于是寫了一個小小的計算器和其他簡單的圖形化程序。然而,在知道了Java的在圖形化界面方面做的不是很好以后,心里有點失望,于是對Swing的熱情也慢慢消退了。但是,我并不后悔花了點時間學Swing編程,因為在學習的過程中收獲了喜悅,產生了一點小小的成就感,這些就已經夠了。呵呵,話又說回來,Java的Swing編程還是值得了解或者學習一下的,因為用它來做一些演示還是挺好的。Java SE的那個Java的Applet(Java應用小程序)就簡單了解一下知道Java有這么個小東西就行了,因為現在都基本宣布死亡了。
上面又說了一些廢話,不過,學習Swing也是我第一次接觸適配器模式,知道有Adapter這個東西。后來,學了用Java作為開發語言的Android開發后,我才更加知道了Java的Swing沒有白學,因為不僅可以用Swing編程學一些小的演示程序,而且使得我特別快就上手了Android開發,對Android中的ListView的Adapter模式也特別理解,不僅如此,不知道是不是之前學了Swing還是怎么的,對Android開發非常容易就理解了。到現在,自己可以獨立開發Android了。但是,知識學不完,新技術不斷,對Android還需要進階,達到更高的一個層次,讓我們一起努力,一起進步。下面,直接進入正題。
定義:把一個類的接口擴展成客戶端所期待的另外一個接口,使得原來不能一起使用的兩個類(一個接口和一個使用該接口的類)一起工作。
使用場景:
1.
需要一個統一的輸入接口,而輸入端的類型不可知。這個時候,我們可以暴露一個接口適配器給客戶端,讓客戶端自己定制。如Android的ListView的Adapter;
1.
解決接口不兼容。使得原來的一些接口在新的場景下依舊可以用,而不必寫新的接口。
優點:
1.
更好的復用性。系統通過需要使用現有的類,而此類的接口不符合系統的需要,那么通過適配器模式就可以讓這些功能得到更好的復用,而避免了寫新的接口;
1.
更好的擴展性。通過暴露給客戶端一個適配器,讓客戶端自己定制功能,從而更好地擴展了系統的功能,如Android中既提供了SimpleAdapter,ArrayAdapter還提供了一個抽象適配器BaseAdapter讓用戶自己定制。
缺點:
- 過多使用適配器,讓系統雜亂不堪,不易于整體把握。如我們每次都為一個接口寫一個是適配器(因為我們不需要實現該接口的所有方法)。
以生活中的裁縫鋪為例
代碼實現
衣服(接口)
~~~
/**
* 衣服(接口)
* @author lt
*
*/
public interface Clothes {
public int getSize();
}
~~~
具體的衣服(客戶端)
~~~
/**
* 具體的衣服(客戶端)
* @author lt
*
*/
public class Clothes1 implements Clothes{
/**
* 假設是180尺碼
*/
@Override
public int getSize() {
return 180;
}
}
~~~
裁縫鋪(適配器)
~~~
/**
* 裁縫鋪(Adapter)
* @author lt
*
*/
public class TailorShop implements Clothes{
private Clothes clothes;
public TailorShop(Clothes clothes){
this.clothes = clothes;
}
/**
* 縮短五厘米
*/
@Override
public int getSize() {
return clothes.getSize()-5;
}
/**
* 將衣服拉長5厘米
* @return
*/
public int largen(){
return clothes.getSize()+5;
}
}
~~~
這里的裁縫鋪是把衣服縮短5厘米,當然,裁縫鋪也可以將衣服變長,也不是固定就是5厘米哦,我們可以用一個參數來讓客戶端指定修剪長度,如我們將裁縫鋪角色改造。
~~~
/**
* 裁縫鋪(Adapter)
* @author lt
*
*/
public class TailorShop implements Clothes{
private Clothes clothes;
/**
* 要修剪的長度,正數為拉長,負數縮短
*/
private int ds;
public TailorShop(Clothes clothes,int ds){
this.clothes = clothes;
this.ds = ds;
}
/**
* 縮短五厘米
*/
@Override
public int getSize() {
return clothes.getSize()+ds;
}
}
~~~
當然,裁縫鋪的功能不僅是改變衣服的尺寸哦,還有縫補衣服。這里就不擴展了,要擴展也就添加方法的事了。
測試(有圖有真相):
~~~
public class Test {
public static void main(String[] args) {
// 小明最近長了5里面,原來180,現在185了,但衣服還是180的
Clothes clothes = new Clothes1();
System.out.println("原來的衣服尺碼:"+clothes.getSize());
// 小明說拉長5厘米
TailorShop tailorShop = new TailorShop(clothes,5);
System.out.println("經過裁縫捕裁剪后衣服的尺碼:"+tailorShop.getSize());
}
}
~~~
結果(Run As):

裁縫鋪修剪完后,小明頓時非常開心地穿起了原來自己喜歡但穿不了的衣服高興地…
這個例子向我們演示了兩個類(小明和衣服)原本不能一起工作,后來經過適配器(裁縫鋪)修剪后又可以一起工作了(小明又穿上那件自己喜歡的衣服了)。其實,這個是對象適配器模式,當然還可以有類適配器模式,這兩種模式的區別就是前者為類進行包裹封裝,后者直接擴展類(繼承)。下面再以一個例子結束本文的內容。
對于下面的這個接口:
~~~
public interface DemoInterface {
public void method1();
public void method2();
public void method3();
public void method4();
public void method5();
public void method6();
// ...
}
~~~
我們在使用這個接口的時候,我們每次都要實現6個或者更多的方法,如果我們不需要實現所有的方法,那么我們可以寫一個這樣的適配器
~~~
public abstract class DemoAdapter implements DemoInterface{
@Override
public abstract void method1();
@Override
public void method2() {
}
@Override
public void method3() {
}
@Override
public void method4() {
}
@Override
public void method5() {
}
@Override
public void method6() {
}
}
~~~
除了我們必須要實現的method1外,其它不必實現的給個空的實現,不管他。下次,我們使用個適配器代替原來的接口,通常系統也會為我們提供這樣的一個適配器,如果沒有,我們可以自己寫。
總結:
任何的模式都有優缺點,適配器模式也不例外,如上面的抽象適配器就有一個明顯的缺點,就是將一個接口替換成了抽象類,優點就是可以不用實現我們不需要實現的方法,而只關心我們必須要實現的那些方法,缺點就是由接口變成了類,使用可能會受限,因為java不支持多重繼承,但可以實現多個接口。