一、定義
代理設計模式爲另一個類提供了一對一的轉發接口:調用代理類的FunctionA()將導致調用原始類中的FunctionA()。也就是說,代理類和原始類有相同的接口。
二、結構
接口 + 真實實現類 + 代理類
三、Proxy模式適用的場景
1.Virtual Proxy:通過代理的模式對消耗資源比較大的對象做了一個延遲加載,即什麼時候用到這個對象了纔去創建它;
2.Remote Proxy:爲處於不同地址空間的對象提供一個本地代理。常見的例子就是Java RMI(Remote Method Invocation) stub對象。stub對象作爲Proxy,對stub對象的調用將會使stub對象與位於遠程機器上的skeleton對象進行通信並對其進行相應的調用。
3.Protective Proxy:控制真實對象的訪問權限。在傳遞請求給真實對象前,Proxy對象會檢查調用者是否擁有訪問權限。
4.Smart Proxy:當真實對象被訪問時,會做一下額外的操作。比如:
1>計算對真實對象的引用次數,當引用次數爲0時自動析構真實對象(即智能指針);
2>當真實對象第一次被引用時,將真實對象加載到內存中;
3>在真實對象被訪問前檢查真實對象是否被lock,確保真實對象不能被其他對象改變。
四、優缺點:
優點:
1.代理作爲調用者和真實對象的中間層,降低了模塊間和系統的耦合性;
2.可以以一個小對象代理一個大對象,達到優化系統提高運行速度的目的:
//No Proxy
class RealPicture
{
public:
RealPicture()
{
mid = g_Id;
std::cout << "ctor: " << mid << std::endl;
g_Id++;
}
~RealPicture()
{
std::cout << "dtor: " << mid << std::endl;
}
void Draw()
{
std::cout << "drawing picture: " << mid << std::endl;
}
private:
int mid;
static int g_Id;
};
int RealPicture::g_Id = 1;
int main()
{
RealPicture realPicture[3];
realPicture[1].Draw();
}
Output:
// Use Proxy
class IPicture
{
public:
virtual void Draw() = 0;
};
class RealPicture: public IPicture
{
public:
RealPicture(int id): mid(id)
{
std::cout << "ctor: " << mid << std::endl;
}
~RealPicture()
{
std::cout << "dtor: " << mid << std::endl;
}
void Draw() override
{
std::cout << "drawing picture: " << mid << std::endl;
}
private:
int mid;
};
class ProxyPicture : public IPicture
{
public:
ProxyPicture()
{
mid = g_Id;
g_Id++;
}
~ProxyPicture()
{
if(!realPicture)
delete realPicture;
}
void Draw() override
{
if (!realPicture)
{
std::unique_lock<std::mutex> ulock(mMutex);
if (!realPicture)
realPicture = new RealPicture(mid);
}
realPicture->Draw();
}
private:
RealPicture* realPicture = nullptr;
std::mutex mMutex;
int mid = 0;
static int g_Id;
};
int ProxyPicture::g_Id = 1;
int main()
{
ProxyPicture picture[3];
picture[1].Draw();
}
output:
3.提供真實對象的權限管理;
4.易擴展。真實對象和代理對象都接口化了,真實對象更改業務後只要接口不變,代理對象可以不做任何改變。
缺點:
1.對比優點1,因爲調用者和真實對象多了一箇中間層,所以會增加調用響應的時間。
五、動態代理
以上的介紹都是基於靜態代理,即代理關係都是固定的。當代理多個真實對象的時候就要寫多個代理類,並且會產生冗餘的代碼,擴展性和可維護性都不高,而動態代理是基於反射實現了在程序運行的過程中才決定代理什麼對象。像AOP的核心思想就是動態代理。
先記一下,後面再研究。
參考資料:
《C++ API設計》
https://sourcemaking.com/design_patterns/proxy