C#設計模式系列:代理模式(Proxy)

libingql發表於2014-04-01

  代理模式提供了一箇中介控制對某個物件的訪問。現實生活中,我們可能會用支票在市場交易中用來代替現金,支票就是賬戶中資金的代理。

1、代理模式簡介

1.1>、定義  

  代理模式(Proxy)定義:代理模式為客戶端程式提供一種中間層以控制對這個物件的訪問。

1.2>、使用頻率

   中高

2、代理模式結構

2.1>、結構圖

2.2>、參與者

  代理模式參與者:

  ◊ Proxy

    ° 維持一個引用,使得代理可以訪問Subject。

    ° 提供一個與Subject的介面相同的介面,這樣代理就可以替代Subject。

    ° 控制對Subject的訪問,並可能負責對Subject的建立和刪除。

  ◊ Subject:定義ConcreteSubject與Proxy的共用介面,從而在任何使用ConcreteSubject的地方都可以使用Proxy。

  ◊ ConcreteSubject:定義Proxy所代表的Subject。

  ◊ Client:維持一個對Subject的引用

  在代理模式中,由於Proxy與ConcreteSubject繼承同一介面,所以Client呼叫ConcreteSubject可以轉化為Client呼叫Proxy在呼叫ConcreteSubject,類Proxy為中間代理。

3、代理模式結構實現

  Subject.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.ProxyPattern.Structural
{
    public abstract class Subject
    {
        public abstract void Request();
    }
}

  ConcreteSubject.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.ProxyPattern.Structural
{
    public class ConcreteSubject : Subject
    {
        public override void Request()
        {
            Console.WriteLine("Called ConcreteSubject.Request()");
        }
    }
}

  Proxy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.ProxyPattern.Structural
{
    public class Proxy : Subject
    {
        private ConcreteSubject _concreteSubject;

        public override void Request()
        {
            // Use 'lazy initialization'
            if (_concreteSubject == null)
            {
                _concreteSubject = new ConcreteSubject();
            }

            _concreteSubject.Request();
        }
    }
}

  Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DesignPatterns.ProxyPattern.Structural;

namespace DesignPatterns.ProxyPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create proxy and request a service
            Proxy proxy = new Proxy();
            proxy.Request();
        }
    }
}

  執行輸出:

Called ConcreteSubject.Request()
請按任意鍵繼續. . .

4、代理模式實踐應用

  IMath.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.ProxyPattern.Practical
{
    /// <summary>
    /// The 'Subject interface
    /// </summary>
    public interface IMath
    {
        double Add(double x, double y);
        double Sub(double x, double y);
        double Mul(double x, double y);
        double Div(double x, double y);
    }
}

  Math.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.ProxyPattern.Practical
{
    /// <summary>
    /// The 'ConcreteSubject' class
    /// </summary>
    public class Math : IMath
    {
        public double Add(double x, double y)
        {
            return x + y;
        }
        public double Sub(double x, double y)
        {
            return x - y;
        }
        public double Mul(double x, double y)
        {
            return x * y;
        }
        public double Div(double x, double y)
        {
            return x / y;
        }
    }
}

  MathProxy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.ProxyPattern.Practical
{
    public class MathProxy : IMath
    {
        private Math _math = new Math();

        public double Add(double x, double y)
        {
            return _math.Add(x, y);
        }

        public double Sub(double x, double y)
        {
            return _math.Sub(x, y);
        }

        public double Mul(double x, double y)
        {
            return _math.Mul(x, y);
        }

        public double Div(double x, double y)
        {
            return _math.Div(x, y);
        }
    }
}

  Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DesignPatterns.ProxyPattern.Practical;

namespace DesignPatterns.ProxyPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create math proxy
            MathProxy proxy = new MathProxy();

            // Do the math
            Console.WriteLine("4 + 2 = " + proxy.Add(4, 2));
            Console.WriteLine("4 - 2 = " + proxy.Sub(4, 2));
            Console.WriteLine("4 * 2 = " + proxy.Mul(4, 2));
            Console.WriteLine("4 / 2 = " + proxy.Div(4, 2));
        }
    }
}

  執行輸出:

4 + 2 = 6
4 - 2 = 2
4 * 2 = 8
4 / 2 = 2
請按任意鍵繼續. . .

5、代理模式應用分析

  代理模式適用範圍很廣,不同的代理適合於不同的情形。

  ◊ 遠端代理為一個物件在不同的地址空間提供區域性代表。

  ◊ 虛代理在需要建立開銷很大的物件時快取物件資訊。

  ◊ 保護代理控制對原始物件的訪問。保護代理用於物件應該有不同的訪問許可權的時候。

  ◊ 智慧指引取代了簡單指引,它在訪問物件時執行了一些附加操作。它的典型用途包括:對指向實際物件的引用計數,這樣當該物件沒有引用時,可以自動釋放。當第一次引用一個持久物件時,將它裝入記憶體。在訪問一個實際物件前,檢查是否已經鎖定了它,以確保其他物件不能改變它。

  代理模式特點:

  ◊ 代理模式在訪問物件時引入一定程度的間接性,可以隱藏物件的位置。

  ◊ 代理模式可以對使用者隱藏一種稱之為copy-on-write的優化方式。當進行一個開銷很大的複製操作的時候,如果複製沒有被修改,則代理延遲這一複製過程,這一可以保證只有當這個物件被修改的時候才對它進行復制。

6、代理模式與裝飾模式比較分析

  裝飾器模式關注於在一個物件上動態的新增方法,代理模式關注於控制對物件的訪問。

  裝飾器模式中Decorator和ConcreteComponent都實現Component,代理模式中Proxy和ConcreteSubject都實現Subject。使用這兩種模式,都可以很容易地在具體物件的方法前面或者後面加上自定義的方法。

  Proxy 可以對Client隱藏物件的具體資訊,在使用代理模式時,常在Proxy中建立一個物件的例項。Proxy與ConcreteSubject之間的關係在編譯時就能確定。
  在使用裝飾模式時,常是將ConcreteComponent物件作為一個引數傳給ConcreteDecorator的構造器,Decorator在執行時遞迴的被構造。

相關文章