Overview of Content
如有引用參考請詳註出處,感謝
本文將探討 Adapter
設計模式,著重於實現和物件導向設計的相關解說。首先,我們將介紹 Adapter
的定義,明確解釋其在物件導向編程中的角色和功能。接著,探討 Adapter
設計的使用場景,以及在實際應用中如何運作。
進一步深入,我們將提供 Adapter 的 UML
建模圖,以視覺化方式呈現其結構和關係。同時,本文將探討 Adapter 設計的優缺點,幫助讀者了解在何種情境下選擇使用這種設計模式。
在「Adapter 實現」的部分,我們將進行更詳細的探討,包括 Adapter 類別繼承 和 Adapter 物件聚合 的實際實現方式。透過具體的程式碼示例和說明,讀者將更容易理解 Adapter 設計模式的應用和實現細節。
總體而言,本文將提供全面的介紹,從 Adapter 的基本概念到具體實現,以協助讀者深入理解並應用 Adapter 設計模式於其物件導向設計中
Adapter 定義
將原本 A 類的接口轉為另外一個 B 類可用的接口,使兩個原本不同的接口可以批配使用
在做程式設計時,其實並不會一開始就將 Adapter 考慮進去,因為 Adapter 主要是運作在兩個已經正常運行的接口(界面)上
Adapter 概念其實也來自於建築設計,它的概念圖如下,在接合兩個不同的物件界面
Adapter 設計使用場景
● 無法兼容:系統需要此現有的類,但是目前類別的介面不符合要求,
● 共用介面:需要建立一個共用介面,提供重複使用,用於彼此之間沒有特別關係的類別,包括以後想要引進的類別
● 不可預知性:一個統一輸出的介面,但輸入端類型多種,也就存在多種可能性,這時就可以使用適配器
Adapter 的重點是在「偽裝」,它與原本的類 (或其家族) 沒有關係,只是很相像
Adapter 可以將兩個不相容的類融合在一起(類似黏著劑),讓它們能夠協做,最終達到相同目的,使兩個不匹配的物件能夠共同工作
Adapter UML 建模圖
● Adapter 角色介紹
角色 | 功能、說明 |
---|---|
Target | 原本就運行的一個類,使用者就使用這個 Target(舊的界面 或 類) |
Original | 原本就運行的一個類,是原本自身設計好的 Original 接口 (也就是新的界面) |
Adapter | Adapter 的核心角色,把 Target 轉換成 Original 讓我們自己使用,這轉會 可以通過繼承 or 關聯去做 |
● Adapter 有兩種實現方式
A. 類別 Adapter (繼承、實現)
● 使用繼承好嗎 ?
使用繼承原物件的方式,其代價較高,如同里式原則的缺點,可能會繼承到不必要使用的方法,導致使用者混淆,越多類別會導致繼承關係越重
B. 物件 Adapter (聚合、關聯):如果你需要接合多個不同接口時就可以使用聚合或關聯關係
Adapter 設計:優缺點
● Adapter 設計優點:
更好的重用性、擴充性: 方便重用舊系統的開發 & 新系統的開發
● Adapter 設計缺點:
過多 Adapter 會導致系統的混亂,不易整體掌握 (無法掌握原始類別真正得實現),可能常會發生呼叫類別錯誤,所以如果不是必要盡量不要使用 (或不要創建太多 Adapter)
Adapter 實現
Adapter 類別繼承
A. Original 類:原本就存在你自己設計的電壓
interface Volt {
fun get110Volt() : Int
}
open class Volt110 : Volt {
override fun get110Volt(): Int {
return 110
}
}
B. Target 目標類:原本以存在的外部類,而使用者正在使用這個類,我們的目標就是轉換 Volt
接口到 ExternalVolt
interface ExternalVolt {
fun get220Volt() : Int
}
open class Volt220 : ExternalVolt {
override fun get220Volt(): Int {
return 220
}
}
C. Adapter
類:繼承 Target(Volt220
) 類、Original(ExternalVolt
) 接口(使用者才能替換)
class VoltAdapter : Volt220(), Volt {
override fun get110Volt(): Int {
return get220Volt()
}
}
● 使用範例:由於對外 使用者是使用 Volt
界面,所以完全不須改變,直接將其設定成 Adapter 類,就可以進行轉換
fun main() {
var volt : Volt = Volt110()
println("Before adapter: ${volt.getMyVolt()}")
volt = VoltAdapter()
println("After adapter: ${volt.getMyVolt()}")
}
Adapter 物件聚合
● 將繼承替換成 setter 或建構函數注入,這樣就不會有依賴實體類繼承的困擾,可以透過注入抽象來達到不同的結果
A. Adapter
類:透過建構函數注入
class VoltAdapter2 constructor(private val volt: ExternalVolt): Volt {
override fun get110Volt(): Int {
return volt.get220Volt()
}
}
● 使用範例:
使用方式差不多,不過這邊使用者要 自己選擇 Adapter 類
fun main() {
var volt : Volt = Volt110()
println("Before adapter: ${volt.getMyVolt()}")
// Adapter
volt = VoltAdapter2(Volt220())
println("After adapter: ${volt.getMyVolt()}")
}
● 但這裡我們也可以很清楚的看到,使用者會需要指定注入類(暴露了底層實做,不符合迪米特原則(最少知識原則)
更多的物件導向設計
物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)!
創建模式 Creation Patterns
● 創建模式 PK
● 創建模式 - Creation Patterns
:
創建模式用於「物件的創建」,它關注於如何更靈活、更有效地創建物件。這些模式可以隱藏創建物件的細節,並提供創建物件的機制,例如單例模式、工廠模式… 等等,詳細解說請點擊以下連結
● Singleton 單例模式 | 解說實現 | Android Framework Context Service
● Abstract Factory 設計模式 | 實現解說 | Android MediaPlayer
● Factory 工廠方法模式 | 解說實現 | Java 集合設計
● Builder 建構者模式 | 實現與解說 | Android Framwrok Dialog 視窗
● Clone 原型模式 | 解說實現 | Android Framework Intent
行為模式 Behavioral Patterns
● 行為模式 PK
● 行為模式 - Behavioral Patterns
:
行為模式關注物件之間的「通信」和「職責分配」。它們描述了一系列物件如何協作,以完成特定任務。這些模式專注於改進物件之間的通信,從而提高系統的靈活性。例如,策略模式、觀察者模式… 等等,詳細解說請點擊以下連結
● Stragety 策略模式 | 解說實現 | Android Framework 動畫
● Interpreter 解譯器模式 | 解說實現 | Android Framework PackageManagerService
● Chain 責任鏈模式 | 解說實現 | Android Framework View 事件傳遞
● Specification 規格模式 | 解說實現 | Query 語句實做
● Command 命令、Servant 雇工模式 | 實現與解說 | 物件導向設計
● Memo 備忘錄模式 | 實現與解說 | Android Framwrok Activity 保存
● Visitor 設計模式 | 實現與解說 | 物件導向設計
● Template 設計模式 | 實現與解說 | 物件導向設計
● Mediator 模式設計 | 實現與解說 | 物件導向設計
● Composite 組合模式 | 實現與解說 | 物件導向設計
● Observer 觀察者模式 | JDK Observer | Android Framework Listview
結構模式 Structural Patterns
● 結構模式 PK
● 結構模式 - Structural Patterns
:
結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結
● Decorate 裝飾模式 | 解說實現 | 物件導向設計
● Iterator 迭代設計 | 解說實現 | 物件導向設計