一、適配器模式
先說說什么是適配器。其實生活中有很多例子。比如2008年的時候買了一台Macbook,有一次做課程設計的時候在課堂上做演示匯報,需要連教室的投影儀。上去的時候突然發現,暈,Macbook的投影接口和教室投影儀的接口根本就對不上,頓時石化。。。后來趕緊去網上查了一下,發現Macbook的投影接口與其他品牌的PC是不一樣的,需要另外花錢買一個轉接器,還好有淘寶,最后花了差不多20大洋終於搞定。這里說的轉接器其實就是一個所謂的適配器。它承擔着讓不同接口之間實現協同工作的功能。家里的水管和各種各樣的水龍頭之間很多時候不能直接接上,中間也許要一些其他的管子、零件什么的在中間。這些管子往往兩頭口子大小是不一樣的。
上面的例子只是為了方便理解,可能並不那么准確,那下面我們說說適配器模式的定義:Convert the interface of a class into another interface clients expect。適配器模式能讓原本互相接口不能匹配的類變得能夠一起工作。也就是說,適配器將一個類的接口變成客戶端所期望的另外一個接口。
適配器模式有兩種類型:類的適配器模式和對象的適配器模式。
類的適配器模式比較通用的類圖如圖所示:

如圖所示,適配器Adapter將被適配的對象的接口轉換成客戶端需要的Target所規定的接口。通過適配器,客戶端可以將Adaptee類當作一個Target來與之協同工作。我們舉個例子。我們首先定義目標Target接口,Target接口之規定了一個方法:request(),其代碼如下所示:
package dp.adapter; public interface Target { public void request(); }
源對象Adaptee代碼如下:
package dp.adapter; public class Adaptee { public void doSth() { System.out.println("做我自己的事情"); } }
對於適配器來說,要達到適配的作用,需要繼承源對象Adaptee並且實現目標接口Target,我們看看代碼:
package dp.adapter; public class Adapter extends Adaptee implements Target{ @Override public void request() { super.doSth(); } }
這樣,客戶端可以通過調用Target對象的request方法,享受到實際上Adaptee對象的doSth中提供的服務。這樣一來,接口不匹配的問題就搞定了,代碼如下:
package dp.adapter; public class Client { public static void main(String[] args) { Target t = new Adapter(); t.request(); } }
運行一下,結果如下:

對象的適配器模式如圖所示:

在這種適配器模式中,適配器類Adapter和源Adaptee之間的關系不再是集成關系,而是一種委托的關系。Adapter往往持有一個Adaptee的引用。我們將上面的代碼例子中Adapter的代碼進行修改:
package dp.adapter; public class Adapter2 implements Target{ private Adaptee adaptee; @Override public void request() { adaptee.doSth(); } }
我們運行Client端程序,結果沒有什么變化。
二、JDK中用到適配器模式的例子
在JDK中,適配器是一個非常重要的設計模式。尤其是在Java IO包的設計上,使用很廣泛。在Java的IO包中有一對類,分別叫做InputStreamReader和OutputStreamWriter。他們負責對字節流和字符流進行轉換,因此有的資料稱他們為橋梁類。盡管名字叫橋梁類,但是他們並不是那個橋梁模式的應用。而是典型的適配器模式的應用。
對於InputStreamReader來說,它一個字節流到字符流的適配器,它的實現主要采用的是對象適配器模式,如圖所示:

對於OutputStreamWriter來說也是類似的。
三、適配器模式的使用場景
適配器模式實際上是一個補償型模式,一般不會在進行系統設計的時候用到。往往當你打算修改正在服役的系統的某個接口時,可以考慮是否用的上。
