設計模式學習之Adapter模式
今天要說適配器模式了,適配器模式其實非常好理解,因為現實中存在很多不同種類的適配器,像usb轉串口線就是講usb接口和串口進行轉換,VGA轉HDMI線就是講VGA接口和HDMI接口進行轉換,這些都是硬件層次的,那么軟件層次的就更好舉例了,比如現在有某些usb設備,像usb無線鍵盤/鼠標啊,usb網卡等等如果直接插到電腦上是不會工作的,必須在電腦端還要裝上相應的驅動程序,那么這個驅動程序其實就是一個軟件適配器,將usb設備轉換成為操作系統能夠識別的設備,其實,usb設備遠不止這些,到淘寶一查,我來個去,真是什么都有啊:
其實這些設備不是都有適配器的,有很多只用使用usb進行供電,把usb當電源了,但有些數碼設備是確實有適配器的,很簡單的就是手機的充電線,現在的智能手機都有一根充電線和一個充電器,充電線的一頭是連接手機的,另一頭則是一個usb接口,這條線連接到充電器就能給手機充電,連接到電腦就能使電腦和手機之間傳輸數據。
其實很早以前,就連鼠標鍵盤這種最常見的設備,都不是用的usb接口,而是用的PS/2接口,但現在支持usb接口的設備是越來越多啊,姑且不論usb到底為什么這么受歡迎(其實就是方便
),我們只看這么多設備是如何做到支持usb接口的,難道說他們都會升級固件?那恐怕不盡然,除非是在usb接口普及之后所生產的新產品,否則那些舊產品要支持新的接口是不現實的,因為是硬件,廠商不可能回收后重做再給用戶啊,那多虧啊。那這么說,那些舊產品就不能使用usb接口了啊,那usb接口怎么可能普及的這么快呢?答案是:適配器,不管是硬件的,還是軟件的(驅動程序),都能
使采用舊接口的設備使用新的接口。
就比如usb網卡,一個usb網卡其實內部包含了一個usb接口與網卡的轉接器,而在電腦端也有相應的網卡驅動讓系統識別這是個網卡,它就有硬件和軟件兩個適配器,當用戶需要從網絡中請求數據時,操作系統會將請求編碼后通過驅動程序從usb接口轉發給網卡,網卡中的適配器對收到的請求進行解碼后發送給網卡處理,網卡從互聯網獲得數據后將數據通過網卡適配器進行編碼后通過usb接口發給電腦,電腦端操作系統通過驅動程序將數據再次解碼后交給用戶,這是不是有些復雜?
哎,扯了這么多,還沒進入正題呢,既然適配器適用于不同接口之間的轉換,那么在設計模式中是如何做到的呢?
還是照本宣科,先把定義擺出來:
適配器模式:
將一個類的接口轉換成客戶希望的另外一個接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
適用性:
- 你想使用一個已經存在的類,而它的接口不符合你的需求。
- 你想創建一個可以復用的類,該類可以與其他不相關的類或不可預見的類(即那些接口可能不一定兼容的類)協同工作。
- (僅適用于對象Adapter )你想使用一些已經存在的子類,但是不可能對每一個都進行子類化以匹配它們的接口。對象適配器可以適配它的父類接口。
定義總是概括性太強,不適合理解啊,有點懵了吧,下面來看個例子吧,就拿usb網卡來說,比如要做一個usb網卡驅動,操作系統提供的網卡API為:
public interface INetCard { public Host connect(IPAddr ip); public NetData getData(Host host); public void sendData(Host host, NetData data); }
而usb接口提供的API為:
public interface IUsb { public UsbData getData(); public sendData(UsbData data); }
網卡端的解碼的方式為:
public class NetCardDecoder { private UsbData data; public void NetCardDecoder(data) { this.data=data; } public void doWork(Operator operator) { operator.execute(); } public Operator decode(UsbData data) { //對USB接口獲取的數據進行解析后對不同的請求返回不同的操作對象 } }
現在我們要做網卡驅動,所以需要將網卡接口適配成Usb接口,所以我們創造一個網卡適配器:
//網卡數據格式與Usb數據格式的轉換工具類 public class DataConvertorTool { //將UsbData轉換NetData public static NetData usbData2Net(UsbData data) { } //將NetData轉換UsbData public static UsbData netData2Usb(NetData data) { } } //網卡適配器類 public class NetCardAdapter implements INetCard { private IUsb usb; public class NetCardAdapter(IUsb usb)//將被適配者傳給適配器 { this.usb=usb; } //適配網卡接口 public Host connect(IPAddr ip) { UsbData data=new UsbData("connect"); data.addParam("ip", ip); usb.sendData(data); } public NetData getData(Host host) { UsbData dataRequest=new UsbData("get"); data.addParam("host", host); usb.sendData(data); UsbData dataUsbReceive=usb.getData(); NetData dataNetReceive=DataConvertorTool.usbData2Net(dataUsbReceive); return dataNetReceive; } public void sendData(Host host, NetData data) { UsbData dataRequest=new UsbData("send"); dataRequest.addParam("host", host); dataRequest.addParam("data",data); usb.sendData(data); } }
從上述代碼可以看出,適配器通過實現用戶接口,并通過組合被適配者接口來實現接口之間的轉換,但上述代碼中我們只是實現了適配器的一種方式,即用組合的方式實現適配,其實,適配器模式還能使用另外一種方式,即類的多繼承,但java中無法實現多繼承,所以無法實現,但java支持多接口的繼承,所以我個人認為其實概念上也是可以實現的,如果使用第二種方式,可以這樣來寫適配器:
//網卡適配器類 public class NetCardAdapter implements INetCard, IUsb { private IUsb usb; public class NetCardAdapter(IUsb usb)//將被適配者傳給適配器 { this.usb=usb; } //適配網卡接口 public Host connect(IPAddr ip) { UsbData data=new UsbData("connect"); data.addParam("ip", ip); usb.sendData(data); } public NetData getData(Host host) { UsbData dataRequest=new UsbData("get"); data.addParam("host", host); usb.sendData(data); UsbData dataUsbReceive=usb.getData(); NetData dataNetReceive=DataConvertorTool.usbData2Net(dataUsbReceive); return dataNetReceive; } public void sendData(Host host, NetData data) { UsbData dataRequest=new UsbData("send"); dataRequest.addParam("host", host); dataRequest.addParam("data",data); usb.sendData(data); } //繼承了Usb接口 public UsbData getData() { } public sendData(UsbData data) { } }
但由于只能繼承接口,所以對于Usb接口方法還必須重新實現,顯然是不現實的,因為這樣就不能實現代碼的復用和封閉了,自然是沒有意義的,但若在c++或其他支持多繼承的語言中,通過多繼承被適配器類而不是接口可以方便的實現代碼復用。
適配器模式與裝飾者模式有些類似,它們都是結構型設計模式,然后都是對某個接口進行操作,但它們卻有本質的不同:
首先, 適配器模式是將一個接口轉換為另一個接口,而裝飾者模式并不改變接口,只是在原實現上面動態的添加某種職責 。
其次, 它們的引用對象不一樣,適配器模式引用被適配者(屬于另一個接口),而裝飾者模式引用自身(同一個接口) 。
最后, 它們的使用方式不一樣,裝飾者模式通過product=new ProductDecorator(product)來包裝自身,而適配器模式通過product=new ProductAdapter(otherProduct)來像product一樣使用otherProduct 。
作者:everdom
出處:http://everdom.cnblogs.com/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,否則保留追究法律責任的權利。


浙公網安備 33010602011771號