C#設計模式——代理模式(Proxy Pattern)

Tynam.Yang發表於2020-11-23

引言

在我們的生活中,經常會遇到需要什麼東西,但是自己又不是很方便或者對方不是很方便,則就需要中間的一個代理人去解決。例如代購。
在軟體開發中,也會遇到這樣的問題。有些物件有時候會由於網路或其他的障礙,以至於不能夠或者不能直接訪問到這些物件,如果直接訪問物件給系統帶來不必要的複雜性,這時候可以在客戶端和目標物件之間增加一層中間層,讓代理物件代替目標物件,然後客戶端只需要訪問代理物件,由代理物件去幫我們去請求目標物件並返回結果給客戶端,這樣的一個解決思路就是今天要介紹的代理模式。

概念

代理是一種結構型設計模式, 讓你能提供真實服務物件的替代品給客戶端使用。 代理接收客戶端的請求並進行一些處理 (訪問控制和快取等), 然後再將請求傳遞給服務物件。
代理物件擁有和服務物件相同的介面, 這使得當其被傳遞給客戶端時可與真實物件互換。

結構圖

代理模式所涉及的角色有三個:

抽象主題角色(Person):宣告瞭真實主題和代理主題的公共介面,這樣一來在使用真實主題的任何地方都可以使用代理主題。

代理主題角色(Friend):代理主題角色內部含有對真實主題的引用,從而可以操作真實主題物件;代理主題角色負責在需要的時候建立真實主題物件;代理角色通常在將客戶端呼叫傳遞到真實主題之前或之後,都要執行一些其他的操作,而不是單純地將呼叫傳遞給真實主題物件。例如這裡的PreBuyProduct和PostBuyProduct方法就是代理主題角色所執行的其他操作。

真實主題角色(RealBuyPerson):定義了代理角色所代表的真是物件。

分類

代理模式按照使用目的可以分為以下幾種:

  1. 遠端(Remote)代理:為一個位於不同的地址空間的物件提供一個局域代表物件。這個不同的地址空間可以是本電腦中,也可以在另一臺電腦中。最典型的例子就是——客戶端呼叫Web服務或WCF服務。
  2. 虛擬(Virtual)代理:根據需要建立一個資源消耗較大的物件,使得物件只在需要時才會被真正建立。
  3. Copy-on-Write代理:虛擬代理的一種,把複製(或者叫克隆)拖延到只有在客戶端需要時,才真正採取行動。
  4. 保護(Protect or Access)代理:控制一個物件的訪問,可以給不同的使用者提供不同級別的使用許可權。
  5. 防火牆(Firewall)代理:保護目標不讓惡意使用者接近。
  6. 智慧引用(Smart Reference)代理:當一個物件被引用時,提供一些額外的操作,比如將對此物件呼叫的次數記錄下來等。
  7. Cache代理:為某一個目標操作的結果提供臨時的儲存空間,以便多個客戶端可以這些結果。

在上面所有種類的代理模式中,虛擬代理、遠端代理、智慧引用代理和保護代理較為常見的代理模式。

實現

例如專案A的PM需要購買一個測試工具,但是測試工具的運營商在國外,自己過去不是很方便,所以需要找一個代理商幫助自己去購買。

下面就實現此購買的例子:

using System;


namespace Proxy
{
    class Program
    {
        static void Main(string[] args)
        {

            ProgramManagement PM = new ProgramManagement();
            PM.BuyToolName = "Bug管理工具";
            PM.BuyTestTool();

            ProxyBuyTestTool Tynam = new ProxyBuyTestTool(PM);
            Tynam.BuyTestTool();


            Console.ReadKey();
        }
    }

    public interface ITestTool
    {
        void BuyTestTool();
    }

    public class ProgramManagement : ITestTool
    {

        public string BuyToolName;
        public void BuyTestTool()
        {
            Console.WriteLine($"專案A需要找一個代理商購買國外的一款{this.BuyToolName}的測試工具");
        }
    }

    public class ProxyBuyTestTool : ITestTool
    {
        private ProgramManagement _pm;

        public ProxyBuyTestTool(ProgramManagement pm)
        {
            this._pm = pm;
        }

        public void BuyTestTool()
        {
            Console.WriteLine($"幫助專案A購買測試工具{this._pm.BuyToolName}成功");
        }

    }

}

執行後結果

專案A需要找一個代理商購買國外的一款Bug管理工具的測試工具
幫助專案A購買測試工具Bug管理工具成功

使用場景

當無法或不想直接引用某個物件或訪問某個物件存在困難時,可以通過代理物件來間接訪問。使用代理模式主要有兩個目的:一是保護目標物件,二是增強目標物件。

由於代理模式有許多分類,應用場景又適於多種情況:

  • 遠端代理,這種方式通常是為了隱藏目標物件存在於不同地址空間的事實,方便客戶端訪問。例如,使用者申請某些網盤空間時,會在使用者的檔案系統中建立一個虛擬的硬碟,使用者訪問虛擬硬碟時實際訪問的是網盤空間。
  • 虛擬代理,這種方式通常用於要建立的目標物件開銷很大時。例如,下載一幅很大的影像需要很長時間,因某種計算比較複雜而短時間無法完成,這時可以先用小比例的虛擬代理替換真實的物件,消除使用者對伺服器慢的感覺。
  • 安全代理,這種方式通常用於控制不同種類客戶對真實物件的訪問許可權。
  • 智慧指引,主要用於呼叫目標物件時,代理附加一些額外的處理功能。例如,增加計算真實物件的引用次數的功能,這樣當該物件沒有被引用時,就可以自動釋放它。
  • 延遲載入,指為了提高系統的效能,延遲對目標的載入。例如,Hibernate 中就存在屬性的延遲載入和關聯表的延時載入。

優缺點

優點:

  • 代理模式在客戶端與目標物件之間起到一箇中介作用和保護目標物件的作用。
  • 代理物件可以擴充套件目標物件的功能。
  • 代理模式能將客戶端與目標物件分離,在一定程度上降低了系統的耦合度,增加了程式的可擴充套件性。

缺點:

  • 代理模式會造成系統設計中類的數量增加。
  • 在客戶端和目標物件之間增加一個代理物件,會造成請求處理速度變慢。
  • 增加了系統的複雜度。

 

相關文章