1.意圖
將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
2 別名
包裝器 Wrapper
3 動機
有時,為復(fù)用和設(shè)計的工具箱類不能夠被復(fù)用的原因僅僅是因為它的接口和專業(yè)應(yīng)用領(lǐng)域所需要的接口不匹配。
例如,有一個繪圖編輯器,這個編輯器允許用戶繪制和排列基本圖元(線,多邊形和正文等)生成圖片和圖表。這個繪圖編輯器的關(guān)鍵抽象是圖形對象。圖形對象有一個可編輯的形狀,并可以繪制自身。圖形對象的接口由一個稱為Shape的抽象類定義。繪圖編輯器為每一種圖形對象定義了一個Shape的子類:LineShape類對應(yīng)直線,PolygonShape類對應(yīng)多邊形等。
像LineShape和PolygonShape這樣的基本幾何圖形的類比較容易實現(xiàn),這是由于它們的繪圖和編輯功能本來就有限。但是對于可以顯示和編輯正文的TextShape子類來說,實現(xiàn)相當(dāng)困難,因為即使是基本的正文編輯也要涉及到復(fù)雜的屏幕刷新和緩沖區(qū)管理。同時,成品的用戶界面工具箱可能已經(jīng)提供了一個復(fù)雜的TextView類用于顯示和編輯正文。理想的情況是我們可以復(fù)用這個TextView以實現(xiàn)TextShape類,但是工具箱的設(shè)計者當(dāng)時沒有考慮Shape的存在,因此TextView和Shape對象不能互換。
一個應(yīng)用可能會有一些類具有不同的接口并且這些接口互不兼容,在這樣的應(yīng)用中像TextView這樣已經(jīng)存在并且不相關(guān)的類如何協(xié)同工作呢?我們可以改變TextView類使它兼容Shape類的接口。但前提是必須有這個工具箱的源代碼。然而即使我們得到了這些源代碼,修改TextView也是沒有什么意義的;因為不應(yīng)該僅僅為了實現(xiàn)一個應(yīng)用,工具箱就不得不采用一些與特定領(lǐng)域相關(guān)的接口。
我們可以不用上面的方法,而定義一個TextShape類,由它來適配TextView的接口和Shape的接口。我們可以用兩種方法做這件事:
- 1 繼承Shape類的接口實現(xiàn)TextView的實現(xiàn);
-
2 將一個TextView實例作為TextShape的組成部分,并且使用TextView的接口實現(xiàn)TextShape。這兩種方法恰恰對應(yīng)Adapter模式的類和對象版本。我們將TextShape稱之為適配器Adapter。
image.png
A d a p t e r時常還要負(fù)責(zé)提供那些被匹配的類所沒有提供的功能,上面的類圖中說明了適配器如何實現(xiàn)這些職責(zé)。
4 適用性
以下情況使用Adapter模式
- 1 你想使用一個已經(jīng)存在的類,而它的接口不符合你的需求;
- 2 你想創(chuàng)建一個可以復(fù)用的類,該類可以與其他不相關(guān)的類或不可預(yù)見的類協(xié)同工作;
- 3 你想使用一些已經(jīng)存在的子類,但是不可能對每一個進行子類化以匹配它們的接口。對象匹配器可以匹配它的父類接口。
5 結(jié)構(gòu)
類適配器使用多重繼承對一個接口與另外一個接口進行匹配,如下圖所示:

對象匹配器依賴于對象組合,如下圖所示:

6 參與者
- Target(Shape)——定義Client使用的與特定領(lǐng)域相關(guān)的接口;
- Client(DrawingEditor)——與符合Target接口的對象協(xié)同。
- Adaptee(TextView)——定義一個已經(jīng)存在的接口,這個接口需要適配
- Adapter(TextShape)——對Adaptee的接口與Target接口進行適配
7 協(xié)作
Client在Adapter實例上調(diào)用一些操作。接著適配器調(diào)用Adaptee的操作實現(xiàn)這個請求。
8 效果
類適配器和對象適配器有不同的權(quán)衡。
類適配器:
- 用一個具體的Adapter類對Adaptee和Target進行匹配。結(jié)果是當(dāng)我們想要匹配一個類以及所有它的子類時,類Adapter將不能勝任。
- 使得Adapter可以重定義Adaptee的部分行為,因為Adapter是Adaptee的一個子類。
- 僅僅引入了一個對象,并不需要額外的指針以間接得到adaptee。
對象適配器:
- 允許一個Adapter與多個Adaptee 即Adaptee 本身以及它的所有子類(如果有子類的話)—同時工作。Adapter也可以一次給所有的Adaptee 添加功能。
- 使得重定義Adaptee的行為比較困難,這就需要生成Adaptee的子類并且使得Adapter引用這個子類不是引用Adaptee本身。
使用Adapter模式時需要考慮的其他一些因素有:
1 Adapter的匹配程度:對Adaptee的接口與Target的接口進行匹配的工作量各個Adapter可能不一樣。工作范圍可能是,從簡單的接口轉(zhuǎn)換(例如改變操作名 )到支持完全不同的操作集合。Adapter的工作量取決于Target接口與Adaptee接口的相似程度。
2 可插入的Adapter:當(dāng)其他的類使用一個類時,如果所需的假定條件越少,這個類就更具可復(fù)用性。如果將接口匹配構(gòu)建為一個類,就不需要假定對其他的類可見的是一個相同的接口。
3 使用雙向適配器提供透明操作:使用適配器的一個潛在問題是,它們不對所有的客戶都透明。被適配的對象不再兼容 Adaptee的接口,因此并不是所有Adaptee對象可以被使用的地方它都可以被使用。雙向適配器提供了這樣的透明性。在兩個不同的客戶需要用不同的方式查看同一個對象時,雙向適配器尤其有用。
9 實現(xiàn)
注意的問題:
- 1 使用C + +實現(xiàn)適配器類:Adapter類應(yīng)該采用公共方式繼承Target類,并且用私有方式繼承Adaptee類。
- 2 可插入的適配器: a.使用抽象操作;b.使用代理對象;c.參數(shù)化的適配器
