介紹
中譯為轉接器模式,是一種結構型的設計模式( Design Pattern ),而實際上就是一個轉接器概念,將兩個彼此不相容的類別藉由一個轉接器類別轉換使彼此達到相容,進而一起完成任務。
現實情境
假設你有一台 PC 主機用了 DVI
連接螢幕,但某天螢幕壞了無法運作,幸運的是朋友最近要換螢幕所以決定把舊螢幕送你,不幸的是那個螢幕是 HDMI
接口,而你的主機也只能相容 DVI
接口
單兵如何處置?
.
.
.
可能會有以下幾種解決方式:
- 將主機元件替換成
HDMI
接口的設備 - 換一個相容
DVI
的新螢幕 - 使用
HDMI to DVI
的轉接器
該如何選擇?
把現實情境套用到軟體設計
其實主機跟螢幕就是兩個不相容的類別,有發現什麼嗎?
方法 1:需改動到現有主機類別內部的設計
方法 2:打掉重練,等於重新設計了一個符合 DVI
接口的螢幕類別
上述方法很明顯都違反了 SOLID-OCP
!
OCP
定義:對擴充開放對修改封閉,意思是我們應該在不修改既有程式的情況下去擴充新的功能。
看起來就只剩方法 3 了。
沒錯!它就是今天的主角 轉接器模式( Adapter Pattern )
把軟體設計情境套用到實作
首先,開啟 Console Application
專案
建立主機類別 MyHost
以及螢幕類別 MyScreen
MyHost:只相容 DVI 接口並帶入建構式參數,設有Open方法
MyScreen:螢幕為 DVI 規格,設有Connect方法
IDIV
輸出
電腦螢幕都是正常運作狀態。
但在某天,螢幕壞了無法運作!
MyScreen Connect 實作改為
輸出
但經過求助後
朋友剛好有汰換掉的 HDMI
螢幕可以給我!
增加 NewScreen 並且為 HDMI 規格,設有方法 Connect
IHDMI
輸出
編譯失敗,原因為 MyHost
只能注入 IDIV
型別。
這邊可能會疑惑:既然 DVI
跟 HDMI
同屬螢幕又有連接 Connect
的行為,為何不抽出 IScreen
介面再注入對應的 Screen
類別使用呢?
這的確也是一種解決方式。
但現實工作遇到的情況會這麼容易嗎?若來源是自己不可控的第三方套件,或其他不可抗因素導致無法重構既有的架構,那麼較適合的方式就是使用 Adapter Pattern
。
所以
建立 Adapter 類別
Adapter
類別說明:
-
紅底線
:代表要轉換的物件 – Target。目標是要相容主機的DVI
螢幕接口,所以要變成DVI
的形狀,繼承IDIV。 -
綠底線
:代表被轉換的物件 – Adaptee。需求是要將HDMI
的接口相容DVI
,所以把IHDMI
設為建構式參數,而在後續實作Connect
方法的內部邏輯呼叫IHDMI Connect
,藉此達到轉接功能。
輸出
這樣就實現轉接功能囉!
範例成員
總結
如此一來,我們只需建立 Adapter
類別即可完成轉接器功能,並不會更動到原有設計,也印證了前面說的 OCP
原則。
範例原始碼:https://github.com/maxlin0523/AdapterPatternSample