昨天在給新買的 MP3 充電的時候,發現這款 MP3 播放器只提供了 USB 接口充電的方式,而它所配備的充電器沒法直接給 USB 接口充電,聰明的廠商爲充電器裝上了一個 USB 接口轉換器解決了問題。java
這個 USB 接口轉接器正是今天要談到的適配器。編程
而在軟件開發中採用相似於上面方式的編碼技巧被稱爲適配器模式。小程序
《設計模式》一書中是這樣給適配器模式定義的:將一個類的接口轉換成客戶但願的另一個接口。設計模式
Adapter 模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。ide
由引子中給出的例子可知,這個定義描述的功能和現實中的適配器的功能是一致的。編碼
可能你仍是不太明白爲何要使用適配器模式。spa
咱們來舉個例子也許能更直接的解除疑惑。設計
好比,在一個畫圖的小程序中,你已經實現了繪製點、直線、方塊等圖形的功能。並且爲了讓客戶程序在使用的時候不用去關心它們的不一樣,還使用了一個抽象類來規範這些圖形的接口。3d
如今你要來實現圓的繪製,這時你發如今系統其餘的地方已經有了繪製圓的實現。代理
在你慶幸之餘,發現系統中已有的方法和你在抽象類中規定的方法名稱不同!
這可怎麼辦?
修改繪製圓的方法名,就要去修改全部使用它的地方;修改你的抽象類的方法名,也要去修改全部圖形的實現方法以及已有的引用。
還有其它的方法沒有?那就是適配器模式了。
能夠看出使用適配器模式是爲了在面向接口編程中更好的複用。
若是你的系統中沒有使用到面向接口編程,沒有使用到多態,我想大概也不會使用到適配器模式。
放上一個簡單的類圖,這只是適配器模式實現的一種狀況:
在《設計模式》一書中將適配器模式分爲類適配器模式和對象適配器模式。
區別僅在於適配器角色對於被適配角色的適配是經過繼承完成的仍是經過組合來完成的。
因爲在 java 中不支持多重繼承,並且繼承有破壞封裝之嫌,衆多的書中(包括《設計模式》)都提倡使用組合來代替繼承。
所以這裏就再也不對類適配器模式進行介紹(其實用的也不多)。
在前面的類圖中描述的就是對象適配器模式。Adapter 對 Adaptee 的轉換是經過組合來完成的
接着上面舉的畫圖程序的例子,先看看在添加繪製圓的需求前的類結構:
添加了圓的繪製之後的類結構:
能夠看出 Shape、Circle 和 TextCircle 三者的關係是和標準適配器模式中 Target、Apater、Apatee 三者的關係相對應的。
咱們只關心這個畫圖程序中是怎麼來使用適配器模式的。
看看Circle 的實現代碼吧:
class Circle extends Shape { //這裏引用了 TextCircle private TextCircle tc; public Circle () { tc= new TextCircle(); //初始化 } void public display() { } tc.displayIt(); //在規定的方法裏面調用 TextCircle 原來的方法 } }
這樣一個簡單的適配器實現就完成了。
其實在適配器角色中不單單能夠完成接口轉換的過程,並且還能夠對其功能進行改進和擴充,固然這就不屬於適配器模式描述的範圍內了。
與代理模式相比,二者的主要區別在於
代理模式應用的狀況是不改變接口命名的,並且是對已有接口功能的一種控制;而適配器模式則強調接口轉換。
在 java 中有一種叫作「缺省適配模式」的應用,它和咱們所講的適配器模式是徹底的兩種東西。
缺省適配模式是爲一個接口提供缺省的實現,這樣子類型就能夠從缺省適配模式中進行擴展 , 避免了從原有接口中擴展時要實現一些本身不關心的接口。
在 java.awt.event 中的XXXAdapter 就是它的很好的例子,有興趣能夠看看。
@成鵬致遠
(blogs:lcw.cnblogs.com)
(email:wwwlllll@126.com)
(qq:552158509)