iT邦幫忙

2023 iThome 鐵人賽

DAY 17
0
Software Development

深入淺出設計模式 - 使用 C++系列 第 17

[Day 17] 控制與物件的接觸 — 代理模式 (Proxy Pattern)

  • 分享至 

  • xImage
  •  

敘述

Proxy Pattern 是一種結構型設計模式,用於代理或替換另一個對象以控制對原始對象的訪問

  • https://ithelp.ithome.com.tw/upload/images/20230929/20138643dZ7LnNPpoh.png

組成

Proxy: 提供和 RealObject 相同的接口,並代理用戶對 RealObject 的訪問 (例: 透過 Proxy Server 控制 Client 對 DB 的訪問)
RealObject: 真正需要被訪問的對象 (例: 資料庫)
Client: 與 Proxy 而不是直接與 RealObject 交互 (例: 訪問資料庫的使用者或應用程式)

  • https://ithelp.ithome.com.tw/upload/images/20230929/20138643KlFFLZjxR7.jpg

簡單範例

Proxy 有太多種變形了,沒辦法一一舉例...

// Image Interface
class Image {
public:
    virtual void display() = 0;
};

// ReadImage Class,真正會從磁碟讀取圖片的類別
class RealImage : public Image {
private:
    std::string fileName;

    void loadFromDisk(std::string fileName) {
        std::cout << "Loading " << fileName << std::endl;
    }

public:
    RealImage(std::string fileName) : fileName(fileName) {
        loadFromDisk(fileName);
    }

    void display() override {
        std::cout << "Displaying " << fileName << std::endl;
    }
};

// ProxyImage Class,轉傳 Request 給 RealImage Class
class ProxyImage : public Image {
private:
    RealImage* realImage;
    std::string fileName;

public:
    ProxyImage(std::string fileName) : fileName(fileName), realImage(nullptr) {}

    void display() override {
        // 若 RealImage 的實例尚未建立,則先建立之 (Lazy-Initialization)
        if (realImage == nullptr) {
            realImage = new RealImage(fileName);
        }
        // 委派 (Delegate) 給 RealImage 的 display 方法
        realImage->display();
    }

    ~ProxyImage() {
        if (realImage) {
            delete realImage;
        }
    }
};

// 使用 ProxyImage 來顯示圖像
int main() {
    Image* image = new ProxyImage("test.jpg");
    image->display();  // 第一次呼叫會加載圖像
    image->display();  // 第二次呼叫不會重新加載,直接顯示
}

分析

優點

  1. 功能擴充 (Functional Extension): 可以在不修改目標物件 (Target Object) 代碼的情況下,為其添加額外功能
  2. 解耦 (Decoupling): 可以將 Client 跟目標物件分離,降低系統的耦合,增加程式的可擴充性
  3. 保護和控制 (Protection and Control): 可以透過代理對目標物件進行訪問控制,例如保護代理可以實現對目標物件的安全性控制

缺點

  1. 性能開銷 (Performance Overhead): 在客戶端和目標物件之間增加了一個代理層,可能會導致請求處理速度變慢
  2. 系統複雜性 (Increased Complexity): 雖然代理模式可以達到多種功能增強和保護控制,但同時也會增加系統的複雜性
  3. 維護成本 (Maintenance Cost): 由於代理物件和目標物件可能有相同的接口,如果接口發生變化,則兩者都需要維護,這會增加維護成本

Proxy 的類型

  • 靜態代理 (Static Proxy): 在程式編譯時就已經確定
  • 動態代理 (Dynamic Proxy): 在執行期間動態生成
  • 保護代理 (Protective Proxy): 用於控制真實對象的訪問權限
  • 虛擬代理 (Virtual Proxy): 用於延遲大型物件的創建 (Lazy-Initialization)
  • 遠程代理 (Remote Proxy): 用於代表在不同地址空間的對象
  • 緩存代理 (Cache Proxy): 為耗時操作提供臨時快取存儲
  • 智能代理 (Smart Proxy): 在訪問對象時添加額外的功能
  • 防火牆代理(Firewall Proxy): 用於控制網絡訪問,過濾出入流量 (inbound & outbound traffic)
  • 反向代理(Reverse Proxy): 代理接收來自客戶端的請求,並將其路由到適當的後端服務。
  • 負載均衡代理(Load Balancing Proxy): 根據負載均衡算法,將請求分發到多個服務實例。
  • 抓取代理(Crawling Proxy): 用於爬取和緩存網站內容。
  • 數據同步代理(Data Synchronization Proxy): 用於在多個數據源之間同步數據
  • 安全保護代理(Anonymizing Proxy): 用於保護用戶的身份,通過隱藏用戶的 IP 地址

應用

資源共享: 資源共享代理用於管理對有限資源的訪問,(例: 資料庫連接池 (Connection Pool),多個 Client 可以共享一組預先建立的資料庫連接)
安全性控制: Proxy Server 可以驗證 Client 的身份,只允許授權的 Client 訪問 DB
數據緩存 (Caching): Proxy Server 可以臨時存儲查詢結果,減少對 DB 的重複查詢
查詢優化: Proxy Server 可以對 Client 的查詢進行優化,然後再傳送到 DB
負載均衡: 如果有多個 DB 實例,Proxy Server 可以根据負載均衡算法分配請求
日誌紀錄 (Logging): Proxy Server 可以記錄所有對 DB 的訪問請求和結果

Reference

  1. https://ianjustin39.github.io/ianlife/design-pattern/proxy-pattern/
  2. https://refactoring.guru/design-patterns/proxy
  3. https://www.tutorialspoint.com/design_pattern/proxy_pattern.htm

上一篇
[Day 16] 讓物件仿佛變成另一個類別 — 狀態模式 (State Pattern)
下一篇
[Day 18] 複合模式的王者 — MVC (Model-View-Controller)
系列文
深入淺出設計模式 - 使用 C++37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言