本章介紹 PROXY 模式GATEWAY 模式(特別是 Table Data Gateway),說明它們如何管理物件與外部系統(資料庫、第三方 API)之間的關係。

PROXY 模式#

動機:購物車問題#

Figure 34.1: Simple shopping cart object model

Figure 34.2: Shopping cart relational data model

  • 有一個簡單的購物車物件模型(ProductOrderItem),但需要將資料持久化到關聯式資料庫
  • 問題:商業邏輯不應該知道資料庫的存在——如果 Product 類別直接包含 SQL 程式碼,就違反了 SRP

PROXY 的三方拆分#

Figure 34.3: PROXY static model

Figure 34.4: PROXY dynamic model

  • PROXY 將一個物件拆成三個部分:
    1. 介面(如 Product):宣告業務方法
    2. 實作(如 ProductImplementation):包含純粹的業務邏輯
    3. Proxy(如 ProductDBProxy):也實作介面,但在業務方法之外加入資料庫存取邏輯
public interface Product
{
    string Name { get; set; }
    double Price { get; set; }
}

public class ProductDBProxy : Product
{
    private string name;
    private double price;

    public string Name
    {
        get
        {
            // 延遲載入:如果尚未從資料庫讀取,先讀取
            if (name == null)
                LoadFromDatabase();
            return name;
        }
        set
        {
            name = value;
            SaveToDatabase();
        }
    }
    // ...
}
  • 客戶端只知道 Product 介面,不知道背後是記憶體版本還是資料庫 Proxy
  • 測試時使用 ProductImplementation,正式環境使用 ProductDBProxy

依賴反轉#

Figure 34.5: Initial relationship between an application and a third-party

Figure 34.7: Inverting the dependency between the application and the

Figure 34.8: How the Proxy inverts the dependency between the

  • PROXY 模式自然地實現了 DIP:應用程式依賴抽象介面,Proxy 是橋接抽象與具體實作的機制
  • 第三方程式庫的依賴被隔離在 Proxy 中,應用程式核心完全不受影響

重點: PROXY 模式的核心價值是透明性——客戶端完全不知道它操作的是 Proxy 而非真實物件。這讓持久化、遠端呼叫、快取等橫切關注點可以在不修改業務邏輯的情況下加入。

GATEWAY 模式#

Table Data Gateway#

Figure 34.9: TABLE DATA GATEWAY pattern

  • Table Data Gateway(TDG) 是一種特殊的 FACADE,為資料庫表格提供 CRUD 操作的統一介面
  • 每個資料表對應一個 Gateway 類別,封裝所有相關的 SQL 操作
public interface EmployeeGateway
{
    void AddEmployee(int empId, string name, string address);
    DataRow GetEmployee(int empId);
    void DeleteEmployee(int empId);
}

public class SqlEmployeeGateway : EmployeeGateway
{
    public void AddEmployee(int empId, string name, string address)
    {
        string sql = "INSERT INTO Employee VALUES (@id, @name, @address)";
        // 執行 SQL...
    }
    // ...
}

測試用的記憶體 Gateway#

  • 為了測試,可以建立 InMemoryEmployeeGateway,用 DictionaryDataTable 取代真實資料庫
  • 這與 FACTORY 模式搭配使用:測試時注入記憶體 Gateway,正式環境注入 SQL Gateway

技巧: Table Data Gateway 的命名慣例是「表名 + Gateway」,如 EmployeeGatewayOrderGateway。介面定義在高層模組中,具體實作(SqlEmployeeGateway)放在低層模組中,確保 DIP。

PROXY vs. GATEWAY#

特性PROXYGATEWAY
粒度物件層級表格/服務層級
透明性客戶端不知道 Proxy 的存在客戶端明確使用 Gateway
典型用途延遲載入、遠端呼叫、存取控制資料庫存取、第三方 API 封裝
複雜度較高(三方拆分)較低(簡單封裝)

補充: 在實務中,PROXY 和 GATEWAY 可以搭配使用——例如 GATEWAY 負責與資料庫通訊,而 PROXY 利用 GATEWAY 來實現物件的透明持久化。

本章小結#

PROXY 模式透過三方拆分(介面、實作、代理)實現了物件的透明代理,讓橫切關注點(如持久化)不會污染業務邏輯。GATEWAY 模式(特別是 Table Data Gateway)則提供了更簡單直接的方式來封裝外部系統的存取,兩者都是建構可測試、可維護系統的重要工具。