一、定义
代理设计模式为另一个类提供了一对一的转发接口:调用代理类的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