適配器將一個類的介面轉換成客戶希望的另外一個介面。下面用三個例子來反映適配器的不同用途:
情況一:
我買了一個PS2介面的滑鼠,但是我的電腦沒有PS2的介面,僅有USB的介面。為了不浪費這個滑鼠,我跑到商店買了一個PS2到USB的轉接頭,這樣我就用上了PS2的滑鼠。USB轉接頭就是一個典型的適配器。
interface USBPort { void connect();}interface PS2Port { void connect();}class USBMouse implements USBPort { public void connect(){ System.out.println("滑鼠串連上了USB連接埠!"); }}class PS22USBMouseAdapter implements USBPort{ private USBPort usbMouse; public PS22USBMouseAdapter (USBPort usbPort){ usbMouse = usbPort; } public void connect(){ usbMouse.connect(); }}class Adapter1{ public static void main(String[] args) { USBMouse mouse = new USBMouse(); mouse.connect(); USBPort adapter = new PS22USBMouseAdapter(mouse); adapter.connect(); }}
PS22USBMouseAdapter是一個PS2到USB介面的適配器,由於它最終輸出的是USB資訊,因此繼承了USBPort。我們最後執行個體化adapter時,它的類型是USBPort —— 設計模式就是如此,我們一般用對象的抽象來進行聲明和定義,而不是具體的類。PS22USBMouseAdapter實現了PS2介面向USB介面的轉變。
情況二:
星際爭霸中,人族的頂級兵種為戰鬥巡洋艦(Battlecruiser)。巡洋艦上有個技能叫做大和炮(Yamato gun)。
假設我們在設計巡洋艦的時候,並沒有想到它可以裝載大和炮,那麼我們的巡洋艦類(Battlecruiser)中僅有一個attack方法。後來我們希望給巡洋艦增加一個大和炮的技能,但是我們又不想修改巡洋艦類的代碼,這個時候就可以用適配器來實現,此時的適配器可以理解成,我們在巡洋艦上裝一個轉換裝置,使得它可以安裝和發射大和炮。
class Battlecruiser{ public void attack(){ System.out.println("大和戰艦發起進攻!"); }}class YamatoAdapter extends Battlecruiser implements Yamato { public void yamato(){ System.out.println("大和戰艦使用大和炮進行攻擊!"); }}interface Yamato{ void attack(); void yamato();}class Adapter2{ public static void main(String[] args) { Yamato superBattlecruiser = new YamatoAdapter(); superBattlecruiser.attack(); superBattlecruiser.yamato(); }}
注意,Battlecruiser類是我們一開始就設計好的。為了能給巡洋艦裝上大和炮,我們建立了一個Yamato介面,這個介面有原來巡洋艦的attack方法,並且還增加了一個yamato方法。最後,建立一個繼承於巡洋艦的類YamatoAdapter,在測試類別中用Yamato執行個體化一個巡洋艦,它既可以普通攻擊,又可以用大和炮進行攻擊。
你可能會想,明明YamatoAdapter已經繼承了Battlecruiser,為何還要繼承Yamato介面?原因如之前所說,我們用“介面”來定義對象,而不是用具體的類。
情況三:
我需要設計星際爭霸人族兵種的一些抽象過程。如,所有兵種都要繼承於一個介面,這個介面有attack、stop、move等方法。這也就意味著,任何一個兵種類都要實現attack、stop、move這三個方法。
這樣一來會有一個問題:並非所有的兵種都有attack、stop、move這3個行為。例如人族的醫學兵(Medic),她不具有attack行為(遊戲中她是無法攻擊敵人的);再例如人族的禿鷹戰車(Vulture,我們俗稱的布雷車),它可以埋蜘蛛雷。蜘蛛雷在敵人靠近的時候,它才會進行自爆攻擊。也就是說,蜘蛛雷不具有stop和move方法,只具有attack方法。
可見,一旦介面的方法多了起來,我們為了實現它們得手工寫不少代碼,要是其中若干方法是我們該類不會用到的,我們不得不寫一個空方法。為了減少代碼編寫,這時,我們可以使用介面的適配器模式:
interface StarcraftSoldier{ void attack(); void stop(); void move();}abstract class SoldierAdapter implements StarcraftSoldier { public void attack(){} public void stop(){} public void move(){}}class SpiderMine extends SoldierAdapter { public void attack(){ System.out.println("蜘蛛雷發現敵人,進攻!"); }}class Adapter3{ public static void main(String[] args) { new SpiderMine().attack(); }}
介面的適配器SoldierAdapter為介面StarcraftSoldier的所有方法做了空實現,在我們建立SpiderMine時,繼承SoldierAdapter,就不必將介面中的所有方法都實現一次了。
以上就是我所理解的適配器的用途,我把它理解成一個相容裝置,或者轉換裝置。若有牽強的地方,歡迎大家指出。