è½æ¥å¨æ¨¡å¼(Adapter Pattern)
以下程式碼範例來自於Head First Design Pattern一書!
轉接器故名思義,在真實世界中,我們常常會看到,像是三孔轉兩孔的電源插頭、不同國家電壓切換的旅行用轉接頭。
透過轉接器的轉換,就可以讓不同的裝置取得電力或是資訊!就像這樣!
假如我們有一套軟體系統,希望和其他廠商即有的程式庫搭配使用,但是這個新廠商所設計出來的介面,不同於舊廠商的介面。
你一定不會想改變既有的程式碼來解決這個問題,特別是之前講的,當需求一變動,我們就要翻修一些我們既有的系統,這樣非常的不靈活。
轉接器類別就此誔生!我們可以寫一個類別,將新廠商介面轉接成我們所期盼的介面吧!
轉接器實踐了我們所希望的介面,而且也能和廠商的介面溝通!
這個轉接器運作起來就是一個中介人,它將客戶發出的請求轉換成廠商類別所看的懂的請求!
這個東西,看起來就是一隻高檔的長焦鏡頭,而且也有Canon的品牌標籤呢
那麼…他必定可能是一隻Canon的鏡頭具備鏡頭外觀介面轉接器的………………………杯子…
好了,回歸正題,同理可證,如果有一個東西朝你走過來,它走起路來像一隻企鵝,叫起來像一隻企鵝,那麼他必定仍然可能只是一隻具備企鵝轉接器的…鴨子:
那麼這個名叫鴨子轉接器的轉接器到底是怎麼運作的呢?
這一次,企鵝實踐了以下介面,具備企鵝叫以及企鵝走路的能力了。
1: public interface Penguins
3: void Penguin_gobble(); //咯咯叫
1: public class KingPenguins:Penguins //國王企鵝
3: public void Penguin_gobble()
5: Console.WriteLine("企鵝叫");
8: public void Penguin_walk()
10: Console.WriteLine("企鵝走路");
3: void Duck_quack(); //嗄嗄叫
1: public class MallardDuck:Duck //綠頭鴨
3: public void Duck_quack()
5: Console.WriteLine("鴨子叫");
8: public void Duck_walk()
10: Console.WriteLine("鴨子走路");
因此,假如我們目前動物園中因為企鵝生病了,為了讓遊客看到企鵝,園方想用一些鴨子物件來充數的話,因為介面設計的不同,所以不能公然拿來用…。
1: public class DuckAdapter : Penguins
5: public DuckAdapter(Duck pDuck)
11: public void Penguin_gobble()
13: gDuck.Duck_quack(); //因為都是叫,所以直接調用Duck中的方法,就很簡單了!
14: Console.Write("壓低聲音!\n"); //
17: public void Penguin_walk()
20: Console.Write("翅膀向下伸值,左右搖擺!\n"); //
這個轉接器我們要先實踐我們希望轉換成的類別,我們是動物園的企鵝期望被看到,所以我們是實現一個鴨子轉接器,來轉換成企鵝的樣子!
在當中的建構式中,我們要取得被轉換者的參考,也就是取得要充數成企鵝的鴨子。
而明確實作企鵝類別中,我們發現要像企鵝的話,鴨子的叫聲要壓低聲音,然後走路的樣子要模仿企鵝搖擺搖擺!
1: static void Main(string[] args)
4: KingPenguins penguin = new KingPenguins();
5: MallardDuck duck = new MallardDuck(); //要充數成企鵝的鴨子!
7: Penguins duckAdapter = new DuckAdapter(duck); //叫鴨子穿上企鵝套裝(轉接器)
8: Console.Write("\n\n鴨子展示:\n"); //先看看正版鴨子
13: Console.WriteLine("\n\n國王企鵝展示:");
14: testPenguin(penguin);
16: Console.WriteLine("\n\n假裝是企鵝的鴨子展示:");
17: testPenguin(duckAdapter);
上述測試程式的重點就是,我們透過鴨子轉接器來假裝成企鵝的樣子,而我們實作了一個TestPenguin的方法,我們傳入了宣告為penguin的鴨子轉接器的物件。
這個模式可以讓客戶和被轉接者之間是鬆綁的,他們並不認識彼此,而客戶接收到呼叫的結果的時候,並未察覺這一切是透過一個轉接器中介傳導。
這個轉接器的方法,似乎也是省不了多少程式碼的撰寫!不過,幸好的是,相形之下,這個轉接器模式提供了一個轉接器類別,將所有的改變封裝在一個類別中。
比起更改客戶端的程式來呼叫新的介面,這個模式是比較好的做法!
將一個類別的介面,轉換成另一個介面以供客戶使用。轉接器讓原本介面不相容的類別可以合作。
HeadFirst Design Pattern後記:
轉接器分成了”物件轉接器”以及”類別轉接器”,上圖是物件轉接器,若要實踐類別轉接器的話,就需要多重繼承,然而在C#跟Java中都不支援
若後續在多重繼承的語言中,仍然有可能會實作到(且看下一篇)。另一個問題是轉接器只能封裝一個類別嗎?不見得,範例總是最單純的環境狀況,在下下一篇
我們會看到一些情況,需要讓一個轉接器包裝多個被轉接者。也就會涉及下一個設計模式:表象模式(Facade Pattern),就靜待分曉吧。
最後這個轉接器模式充滿著良好的00設計守則:透過使用物件合成,以修改的介面包裝被轉接者,這種做法可以達到讓被轉接者的任何次類別,都可以搭配使用轉接器。最後提醒這個模式是如何讓客戶和介面之間建立關係,而不是讓客戶和實踐的內容建立關係。我們可以使用數個轉接器,每個一個都負責轉換不同組的終端類別。
或是像本例中,加入新的實踐內容,只要遵守目標介面就可以囉。