結構模式 – 3 個 PK | Proxy vs Decorate vs Adapter | 最佳實踐

結構模式 – 3 個 PK | Proxy vs Decorate vs Adapter | 最佳實踐

Overview of Content

結構類模式在軟件設計中扮演著重要的角色,包括適配器、橋樑、組合、裝飾、門面以及代理模式等。這些模式通過將類組合起來,以實現更大的結構,從而滿足高層次的需求。其中,代理模式、裝飾模式和適配器模式是常見的結構模式,本文將重點討論這三種模式的應用和最佳實踐。

Proxy(代理)模式通過控制物件的訪問,為客戶端提供間接訪問物件的方式。我們將探討代理模式如何管理物件的訪問權限,以及在不同情境下的最佳實踐。

Decorate(裝飾)模式允許動態地為物件添加額外的功能,同時保持其接口不變。我們將深入研究裝飾模式如何增強或減弱物件的功能,並討論裝飾模式與代理模式之間的比較和最佳實踐。

Adapter(適配器)模式通常用於使不兼容的接口能夠協同工作。我們將討論適配器模式如何在不修改現有代碼的情況下使不同接口之間進行通信,並探討適配器模式與裝飾模式之間的差異和最佳實踐。

通過對這三種結構模式的深入研究,我們將提供實用的指南,幫助開發人員更好地理解何時以及如何應用這些模式來提高代碼的可讀性、可維護性和擴展性。


Proxy、Decorate

裝飾模式可以說是代理模式中的一個特別應用!兩者最大的不同點在於 意圖

代理模式:重點是 代理時機的控制

代理者具有絕對的控制權

裝飾模式:重點在於 加強、減弱原本類的功能

原本的類絕對會被執行(代理方無權干預),代理方只能再次增強、減弱原本類的功能


Proxy 之控制權

● 我們來實現網路 VPN 的代理,VPN 有辦法控制你是否可以訪問這個區域的網路

A. 界面

使用者使用代理重點是關注於界面的合約


interface IInternet {
    fun surf(url: String)
}

B. 實做功能類

這個類是實際功能的實做者


class InternetImpl: IInternet {
    override fun surf(url: String) {
        println("surf on internet, to: $url")
    }

}

C. 代理類

該類控制了我們是否真的能訪問到實做類(它有權力控制),這也是 意圖的差別重點


class VPNProxy: IInternet {

    private var internet = InternetImpl()

    override fun surf(url: String) {
        if (url.startsWith("http://")) {
            throw Exception("Unsafe access.")
        }

        internet.surf(url)
    }

}

Decorate 之增強、減弱

裝飾模式如果 省略抽象角色 後,幾本上他們的 UML 類圖可以說是一樣的(所以以下範例把裝飾模式的抽象抽離)

● 同樣網路的案例,我們把網路信號做不同的調整,來達到增強、減弱網路的功能

A. 界面實做功能類:同樣的界面,同樣的實做功能

界面類如下,我們宣告一個簡單的 IInternet 界面,用來接收 URL 做遊覽的動作


interface IInternet {
    fun surf(url: String)
}

實做功能類,簡單的 print 出 url 就行… 重點是該類屬於 Decorate 的核心(原先)類


class InternetImpl: IInternet {
    override fun surf(url: String) {
        println("surf on internet, to: $url")
    }

}

B. 裝飾類

從這個類的意圖,就可以了解到它與代理類的不同;裝飾類不會去控制是否可以訪問,它只做一個加強(或減弱)的行為


class Signal5G: IInternet {

    private var internet = InternetImpl()

    override fun surf(url: String) {
        println("5G use faster line.")

        internet.surf(url)
    }

}

Proxy vs. Decorate 最佳實踐

代理模式:保證原本類的 原汁原味的功能,重點在 控制外部是否可以訪問 這個 原汁原味的類~

● 代理模式到了極致就是 AOP,透過動態代理、反射來達到業務需求

裝飾模式:原本的類功能仍然會有,但是可能被加強,也可能被縮減,但就是 不會做是否訪問原類的判斷(不過率參數...等等)

● Java 的 IO 包內就相當多裝飾模式

Decorate、Adapter

兩者個相同之處在於,都是 透過包裝 某個類來達成委託;但最大的不同點在於 包裝的物件

● 裝飾模式(Decorate):包裝相同 有關連的類

● 適配器模式(Adapter):包裝完全沒關係的類,最終達成一個偽裝的類

Decorate 之關係包裝

接下來我們實現一個包裝 Linux Core 的系統概念,透過 Linux 每個不同的組件,對 Linux Core 包裝,並 進行加強

A. 包裝界面:不管是 Decorate 還是 Adapter,他們的核心都是一個界面,指使至中都是針對這個界面的包裝

● 其子類是 is-a 的關係,也就是 子類跟這個界面有一定關係


interface LinuxCore {

    fun deviceSystem()

}

B. 待裝飾類別:有著基礎的核心功能(以可以說是簡陋的基礎功能)


class GnuCore : LinuxCore {

    override fun deviceSystem() {
        println("Use shell to access linux core")
    }

}

C. 裝飾抽象類:主要是它接收一個抽象核心界面作為成員,再操作其成員來達到加強(或削弱)的功能


abstract class Decorate(private val base: LinuxCore) : LinuxCore {

    override fun deviceSystem() {
        base.deviceSystem()
    }

}

D. 裝飾類:裝飾的實做類,它為相關類做處理


class GUI(base: LinuxCore): Decorate(base) {

    override fun deviceSystem() {
        super.deviceSystem()
        println("Use GUI to open window")
    }
}

class Application(base: LinuxCore): Decorate(base) {

    override fun deviceSystem() {
        super.deviceSystem()
        println("Use Application control")
    }
}

● 使用裝飾關係類來包裝的成果


fun main() {
    val root = GnuCore()

    Application(GUI(root)).deviceSystem()

}

Adapter 之偽裝

我們知道 Window 系統與 Linux 系統的本質就是不同,但我們可以透過 Window 虛擬機(Adapter)來建立一個 Linux 系統

A. 核心界面、實做類:它 LinuxCore 的界面、實做,也就是核心界面跟實做(可以說是純正血脈~ 將會被某個類偽裝)


// 抽象
interface LinuxCore {

    fun deviceSystem()

}

// 實做類
class LinuxImpl : LinuxCore {

    override fun deviceSystem() {
        println("Linux core.")
    }

}

B. 假界面:它與核心界面的功能一模一樣,不過其實是外部將會偽裝的界面(就是要假扮所以方法才一樣阿)

● 兩個界面都有 deviceSystem 方法,但其實 兩者是沒有關係的


interface IWindowVM {

    fun deviceSystem()

}

C. 假類:虛擬機類,它內部擁有一個 真實的 LinuxCore 界面實做,透過它來模擬訪問 LinuxCore


class WindowVMAdapter : IWindowVM {

    private val linux = LinuxImpl()
    
    override fun deviceSystem() {
        println("Window VM.")
        linux.deviceSystem()
    }

}

● Window 使用 WindowVM 來運行 Linux


fun main() {
    WindowVMAdapter().deviceSystem()
}

Decorate vs. Adapter 最佳實踐

意圖不同

Decorate:意圖在「加強(減弱)」原生物件的核心功能

Adapter:意圖在於「轉換」,與原來類可以沒有任何關係

施予目標不同

Decorate:裝飾物件必須是自己的同宗,也就是有 相同的父類、界面

Adapter:適配物件則是兩個完全不同的物件,不必有繼承、實做關係

場景不同

Decorate:多用在功能增強上

Adapter比較常用於補救、緊急手段

擴展性不同

Decorate:簡易、方便拓展(或移除)

Adapter:由於兩者之間是靠邏輯手動產生關係的,所以拆開時也需要判別邏輯


更多的物件導向設計

物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)!

設計建模 2 大概念- UML 分類、使用

物件導向設計原則 – 6 大原則(一)

物件導向設計原則 – 6 大原則(二)

創建、行為、結構型設計 8 個比較 | 包裝模式 | 最佳實踐

創建模式:Creation Patterns

創建模式 PK

創建模式 - Creation Patterns

結構模式:Structural Patterns

結構模式 PK

結構模式 - Structural Patterns

結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結

Bridge 橋接模式 | 解說實現 | 物件導向設計

Decorate 裝飾模式 | 解說實現 | 物件導向設計

Proxy 代理模式 | 解說實現 | 分析動態代理

Iterator 迭代設計 | 解說實現 | 物件導向設計

Facade 外觀、門面模式 | 解說實現 | 物件導向設計

Adapter 設計模式 | 解說實現 | 物件導向設計

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

發表迴響