結構型模式之代理模式
6.1 模式動機:
在某些情況下,一個客戶不想或者不能直接引用一個物件,此時可以通過一個稱之為“代理”的第三者來實現間接引用。
代理物件可以在客戶端和目標物件之間起到中介的作用,並且可以通過代理物件去掉客戶不能看到的內容和服務或者新增客戶需要的額外服務。
通過引入一個新的物件(如小圖片和遠端代理物件)來實現對真實物件的操作或者將新的物件作為真實物件的一個替身,這種實現機制即 為代理模式,通過引入代理物件來間接訪問一 個物件,這就是代理模式的模式動機。
6.2 模式定義:
代理模式(Proxy Pattern) :給某一個物件提供一個代理,並由代理物件控制對原物件的引用。代理模式的英文叫做Proxy或Surrogate,它是一種物件結構型模式。
6.3 模式結構:
代理模式包含如下角色:
- Subject: 抽象主題角色
- Proxy: 代理主題角色
- RealSubject: 真實主題角色
6.4 時序圖:
6.5 程式碼分析:
#include <iostream>
#include "RealSubject.h"
#include "Proxy.h"
using namespace std;
int main(int argc, char *argv[])
{
Proxy proxy;
proxy.request();
return 0;
}
///////////////////////////////////////////////////////////
// Proxy.h
// Implementation of the Class Proxy
// Created on: 07-十月-2014 16:57:54
// Original author: colin
///////////////////////////////////////////////////////////
#if !defined(EA_56011290_0413_40c6_9132_63EE89B023FD__INCLUDED_)
#define EA_56011290_0413_40c6_9132_63EE89B023FD__INCLUDED_
#include "RealSubject.h"
#include "Subject.h"
class Proxy : public Subject
{
public :
Proxy();
virtual ~Proxy();
void request();
private:
void afterRequest();
void preRequest();
RealSubject *m_pRealSubject;
};
#endif // !defined(EA_56011290_0413_40c6_9132_63EE89B023FD__INCLUDED_)
///////////////////////////////////////////////////////////
// Proxy.cpp
// Implementation of the Class Proxy
// Created on: 07-十月-2014 16:57:54
// Original author: colin
///////////////////////////////////////////////////////////
#include "Proxy.h"
#include <iostream>
using namespace std;
Proxy::Proxy(){
//有人覺得 RealSubject物件的建立應該是在main中實現;我認為RealSubject應該
//對使用者是透明的,使用者所面對的介面都是通過代理的;這樣才是真正的代理;
m_pRealSubject = new RealSubject();
}
Proxy::~Proxy(){
delete m_pRealSubject;
}
void Proxy::afterRequest(){
cout << "Proxy::afterRequest" << endl;
}
void Proxy::preRequest(){
cout << "Proxy::preRequest" << endl;
}
void Proxy::request(){
preRequest();
m_pRealSubject->request();
afterRequest();
}
6.6 優點:
代理模式能夠協調呼叫者和被呼叫者,在一定程度上降低了系統的耦合度。
遠端代理使得客戶端可以訪問在遠端機器上的物件,遠端機器 可能具有更好的計算效能與處理速度,可以快速響應並處理客戶端請求。
虛擬代理通過使用一個小物件來代表一個大物件,可以減少系 統資源的消耗,對系統進行優化並提高執行速度。
保護代理可以控制對真實物件的使用許可權。
6.7 缺點:
由於在客戶端和真實主題之間增加了代理物件,因此 有些型別的代理模式可能會造成請求的處理速度變慢。
實現代理模式需要額外的工作,有些代理模式的實現 非常複雜。
6.8 適用環境:
遠端(Remote)代理:為一個位於不同的地址空間的物件提供一個本地的代理物件,這個不同的地址空間可以是在同一臺主機中,也可是在另一臺主機中,遠端代理又叫做大使(Ambassador)。
虛擬(Virtual)代理:如果需要建立一個資源消耗較大的物件,先建立一個消耗相對較小的物件來表示,真實物件只在需要時才會被真正建立。
Copy-on-Write代理:它是虛擬代理的一種,把複製(克隆)操作延遲 到只有在客戶端真正需要時才執行。一般來說,物件的深克隆是一個 開銷較大的操作,Copy-on-Write代理可以讓這個操作延遲,只有物件被用到的時候才被克隆。
保護(Protect or Access)代理:控制對一個物件的訪問,可以給不同的使用者提供不同級別的使用許可權。
緩衝(Cache)代理:為某一個目標操作的結果提供臨時的儲存空間,以便多個客戶端可以共享這些結果。
防火牆(Firewall)代理:保護目標不讓惡意使用者接近。
同步化(Synchronization)代理:使幾個使用者能夠同時使用一個物件而沒有衝突。
智慧引用(Smart Reference)代理:當一個物件被引用時,提供一些額外的操作,如將此物件被呼叫的次數記錄下來等。
6.9 模式應用:
EJB、Web Service等分散式技術都是代理模式的應用。在EJB中使用了RMI機制,遠端伺服器中的企業級Bean在本地有一個樁代理,客戶端通過樁來呼叫遠端物件中定義的方法,而無須直接與遠端物件互動。
在EJB的使用中需要提供一個公共的介面,客戶端針對該介面進行程式設計,無須知道樁以及遠端EJB的實現細節。
6.10 模式擴充套件:
幾種常用的代理模式:
圖片代理:一個很常見的代理模式的應用例項就是對大圖瀏覽的控制。
使用者通過瀏覽器訪問網頁時先不載入真實的大圖,而是通過代理物件的方法來進行處理,在代理物件的方法中,先使用一個執行緒向客戶端瀏覽器載入一個小圖片,然後在後臺使用另一個執行緒來呼叫大圖片的載入方法將大圖片載入到客戶端。當需要瀏覽大圖片時,再將大圖片在新網頁中顯示。如果使用者在瀏覽大圖時載入工作還沒有完成,可以再啟動一個執行緒來顯示相應的提示資訊。通過代理技術結合多執行緒程式設計將真實圖片的載入放到後臺來操作,不影響前臺圖片的瀏覽。
遠端代理:遠端代理可以將網路的細節隱藏起來,使得客戶端不必考慮網路的存在。客戶完全可以認為被代理的遠端業務物件是局域的而不是遠端的,而遠端代理物件承擔了大部分的網路通訊工作。
虛擬代理:當一個物件的載入十分耗費資源的時候,虛擬代理的優勢就非常明顯地體現出來了。虛擬代理模式是一種記憶體節省技術,那些佔用大量記憶體或處理複雜的物件將推遲到使用它的時候才建立。
動態代理:
- 動態代理是一種較為高階的代理模式,它的典型應用就是Spring AOP。
- 在傳統的代理模式中,客戶端通過Proxy呼叫RealSubject類的request()方法,同時還在代理類中封裝了其他方法(如preRequest()和postRequest()),可以處理一些其他問題。
- 如果按照這種方法使用代理模式,那麼真實主題角色必須是事先已經存在的,並將其作為代理物件的內部成員屬性。如果一個真實主題角色必須對應一個代理主題角色,這將導致系統中的類個數急劇增加,因此需要想辦法減少系統中類的個數,此外,如何在事先不知道真實主題角色的情況下使用代理主題角色,這都是動態代理需要解決的問題。
6.11 總結:
在代理模式中,要求給某一個物件提供一個代理,並由代理物件控制對原物件的引用。代理模式的英文叫做Proxy或Surrogate,它是一種物件結構型模式。
- 代理模式包含三個角色:抽象主題角色聲明瞭真實主題和代理主題的共同介面;代理主題角色內部包含對真實主題的引用,從而可以在任何時候操作真實主題物件;真實主題角色定義了代理角色所代表的真實物件,在真實主題角色中實現了真實的業務操作,客戶端可以通過代理主題角色間接呼叫真實主題角色中定義的方法。
代理模式的優點在於能夠協調呼叫者和被呼叫者,在一定程度上降低了系統的耦合度;其缺點在於由於在客戶端和真實主題之間增加了代理物件,因此有些型別的代理模式可能會造成請求的處理速度變慢,並且實現代理模式需要額外的工作,有些代理模式的實現非常複雜。遠端代理為一個位於不同的地址空間的物件提供一個本地的代表物件,它使得客戶端可以訪問在遠端機器上的物件,遠端機器可能具有更好的計算效能與處理速度,可以快速響應並處理客戶端請求。
如果需要建立一個資源消耗較大的物件,先建立一個消耗相對較小的物件來表示,真實物件只在需要時才會被真正建立,這個小物件稱為虛擬代理。虛擬代理通過使用一個小物件來代表一個大物件,可以減少系統資源的消耗,對系統進行優化並提高執行速度。
保護代理可以控制對一個物件的訪問,可以給不同的使用者提供不同級別的使用許可權。