設計模式(十三)—— 代理模式
模式簡介
為其他對象提供一種代理以控制對這個對象的訪問。
在一些情況下,客戶端不能或者不想直接引用一個對象,可以借助一個第三方代理來實現間接引用。代理對象在客戶端和目標對象之間起到中介作用,通過代理對象,可以去掉客戶不能看到的內容或服務,也可以添加客戶需要的額外服務。
想象一下,商家想找明星藝人演出,要先找到經紀人,談妥了相關事宜,經紀人通知相關藝人在適當的時間進行表演。這裏的經紀人就相當於代理對象。在這個示例中,使用代理帶來了哪些好處呢?
- 控制了目標對象的訪問權限。不是任何人都能找到明星,明星沒有那麽多時間(保護代理)。
- 明星藝人在全世界各地表演,無法與商家見面,經濟人作為代表討論相關事宜(遠程代理)。
- 藝人出場費用較高,開銷太大,商家可以與經紀人先進行討論,待演出時藝人再出場表演,降低成本(虛代理)
結構說明
角色說明
- Subject
抽象主題。定義RealSubject和Proxy的共同接口,以便在任何可以使用RealSubject的地方都能夠使用Proxy。
- RealSubject
Proxy代理的目標實體。
- Proxy
代理類,包含一個指向RealSubject實體的引用。
源碼結構
首先創建抽象主題Subject,它是一個抽象類,包含抽象方法Request。
abstract class Subject { public abstract void Request(); }
創建目標實體類RealSubject,繼承自Subject類,Request方法。
class RealSubject : Subject
{
public override void Request()
{
Console.WriteLine("Request by real subject");
}
}
創建代理類Proxy,其中包含一個私有成員,引用RealSubject目標實體對象,以便將請求轉發給真正的目標實體對象,註意這裏Proxy也繼承自Subject,那麽在使用RealSubject的地方都能夠使用Proxy。
class Proxy : Subject { private Subject _realSubject; public override void Request() { if (_realSubject == null) { _realSubject = new RealSubject(); } _realSubject.Request(); } }
客戶端調用,客戶端不需要知道目標實體類,通過代理就可以完成相應的請求。
class Program
{
static void Main(string[] args)
{
Proxy proxy = new Proxy();
proxy.Request();
Console.ReadLine();
}
}
工作原理
客戶端發送請求給代理,代理對象則在適當的時候向RealSubject轉發請求。
示例分析
生活中一個非常簡單的例子,例如互聯網上面我們很多網站不能訪問。通過代理類檢查用戶訪問的網站是否被禁止,如果沒有,正常訪問;否則,返回Access Denied。
創建抽象類Internet,包含抽象方法Connect(這裏也可以聲明為接口)。
abstract class Internet
{
public abstract void Connect(string url);
}
分別創建RealInternet類以及代理類InternetProxy,RealInternet實現Connect方法,直接訪問傳入的地址。而代理類InternetProxy維護一個禁止訪問的集合,在執行Connect方法時,首先判斷傳入的地址是否包含在該集合中,如果存在,返回Access Denied;否則調用RealInternet的Connect方法。
class RealInternet : Internet
{
public override void Connect(string url)
{
Console.WriteLine($"Connecting to {url}");
}
}
class InternetProxy : Internet
{
private Internet _realInternet = new RealInternet();
private readonly List<string> _bannedSites;
public InternetProxy()
{
_bannedSites = new List<string>
{
"abc.com",
"111.com"
};
}
public override void Connect(string url)
{
if (_bannedSites.Contains(url))
{
Console.WriteLine("Access Denied");
}
else
{
_realInternet.Connect(url);
}
}
}
客戶端調用,通過代理訪問aaa.com以及abc.com,輸出結果如下:
class Program
{
static void Main(string[] args)
{
InternetProxy proxy = new InternetProxy();
proxy.Connect("aaa.com");
proxy.Connect("abc.com");
Console.ReadLine();
}
}
適用場景
根據代理模式的使用目的,常見的代理模式分為以下幾種類型:
- 遠程代理(Remote Proxy)
為一個對象在不同的地址空間提供局部代表。
- 虛代理(Virtual Proxy)
如果需要創建一個資源消耗較大的對象,可以先創建一個消耗較小的代理對象來表示,在適當時間創建真正的對象。
- 保護代理(Protection Proxy)
控制一個對象的訪問,如上一節中的示例。
- 智能指引(Smart Reference)
當一個對象被引用時,提供一些額外的操作,如將此對象被調用的次數記錄下來。
優缺點
優點
遠程代理使得客戶端可以訪問遠程機器上的對象。
- 虛代理可以減少系統資源的消耗。
保護代理可以控制客戶端對真實對象的訪問權限。
缺點
- 因為增加了代理對象,所以系統處理請求的速度會變慢。
代理模式與裝飾者模式的區別
從結構上來看,代理模式和裝飾者模式非常相似,Proxy和Decorator中都包含了對目標對象的引用,在使用時向目標對象發送請求。二者之間的差異主要在於它們的設計目的不同:Proxy主要強調客戶端不能或者不想直接引用一個對象時,為這個對象提供一個替代品。 而Decorator更側重於通過組合的方式,為目標對象增加一些額外的職責。 如《設計模式(十)—— 裝飾者模式》一篇中講到,裝飾者模式可以在客戶端通過多個裝飾者以遞歸組合的方式對組件進行功能上的擴展,而代理模式更強調一種替代關系。
設計模式(十三)—— 代理模式