代理模式
1、背景
假如说我现在想租一间房子,虽然我可以自己去找房源,做卫生检测等一系列的房屋租赁流程,但是这确实太浪费我得时间和精力了。我只是想租一间房而已为什么我还要额外做这么多事呢?于是我就通过中介公司来租房,他们来给我找房源,我只是负责选择自己喜欢的房子,然后付钱就可以了。
为什么要用代理模式?
- 1、中介隔离作用: 在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 2、开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。
- 代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。
- 代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。
- 真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
2、定义
- 继承关系(
is a
):实线、空三角箭头 ,Real Subject
、Proxy
继承Subject
; - 聚合(
has a
):实线、菱形,菱形指向整体,整体包含部分,这里Proxy
是整体,Real Subject
是部分。
定义:
由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
- 1、抽象角色(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
- 2、真实角色(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 3、代理角色(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
3、特征
代理模式的主要优点有:
- 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
- 代理对象可以扩展目标对象的功能;
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
其主要缺点是:
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
- 增加了系统的复杂度;
4、应用场景
- 1、远程代理。
为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。这个不同的地址空间可以是在本机器上,也可以在另一台机器中。 - 2、虚拟代理:根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象,使其只有在真正需要时才被创建。
- 有些图形对象的创建开销很大。但是打开文档必须很迅速,因此我们在打开文档时应避免一次性创建所有开销很大的对象。这里就可以运用代理模式,在打开文档时,并不打开图形对象,而是打开图形对象的代理以替代真实的图形。
- 3、Copy-on-Write 代理。
- 它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
- 4、保护(Protect or Access)代理。
- 控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
- 5、Cache代理。
- 6、防火墙(Firewall)代理。
- 为某一个目标的操作结果提供临时存储空间,以便其他客户的可以共享访问,有点缓存的味道。
- 7、同步化(Synchronization)代理。
- 可以让几个用户同时访问同一个对象而不产生冲突。
- 8、智能引用(Smart Reference)代理。
- 是指当调用真实对象时,代理处理另外一些事,比如记录对此对象的调用次数等。
5、实验案例
案例1
#include <iostream>
using namespace std;
class Subject { // Subject类定义了RealSubject和Proxy的公用接口,这样就在任何使用RealSubject的地方都可以用Proxy
public:
virtual void Request() = 0;
virtual ~Subject() {}
};
class RealSubject : public Subject { // RealSubject类,定义了Proxy所代表的真实实体
public:
void Request() { cout << "RealSubject" << endl; }
};
class Proxy : public Subject { // Proxy类,保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口,这样代理就可以用来代替实体
private:
RealSubject* realSubject;
public:
void Request() {
if (realSubject == NULL) realSubject = new RealSubject();
realSubject->Request();
}
};
int main() {
Proxy* p = new Proxy();
p->Request(); // RealSubject
delete p;
return 0;
}
2、大话设计模式案例
#include<iostream>
#include<string>
class SchoolGirl {
private:
std::string name;
public:
void setName(std::string name) {
this->name = name;
}
std::string getName() {
return name;
}
};
//接口
class IGiveGift {
public:
virtual void GiveDolls() {};
virtual void GiveFlowers() {};
virtual void GiveChocolate() {};
};
// 真正的追求者
class Pursuit :public IGiveGift {
private:
SchoolGirl* realPursuit;
public:
Pursuit(SchoolGirl* realPursuit) {
this->realPursuit = realPursuit;
}
void GiveDolls() {
std::cout << realPursuit->getName() << " give u Dolls" << std::endl;
}
void GiveFlowers() {
std::cout << realPursuit->getName() << " give u Flowers" << std::endl;
}
void GiveChocolate() {
std::cout << realPursuit->getName() << " give u Chocolates" << std::endl;
}
};
//代理者
class Proxy :public IGiveGift {
private:
Pursuit* proxyPursuit;//OBJ
public:
Proxy(SchoolGirl* realPursuit) {
proxyPursuit = new Pursuit(realPursuit);
}
void GiveDolls() {
proxyPursuit->GiveDolls();
}
void GiveFlowers() {
proxyPursuit->GiveFlowers();
}
void GiveChocolate() {
proxyPursuit->GiveChocolate();
}
};
void main() {
SchoolGirl* jiaojiao = new SchoolGirl();
jiaojiao->setName("lijiaojiao");
Proxy* proxy = new Proxy(jiaojiao);
proxy->GiveDolls();
proxy->GiveFlowers();
proxy->GiveChocolate();
delete jiaojiao;
jiaojiao = NULL;
delete proxy;
proxy = NULL;
system("pause");
}
3、虚拟代理
// 抽象类
class Image
{
public :
Image(std::string name) : m_name(name){ }
virtual ~Image( ){ }
virtual void Show( ) = 0; // 显示文档的函数
protected :
std::string m_name; // 文档名
};
// 大型实体类
class BigImage : public Image
{
public :
BigImage(std::string name) : Image(name){ }
virtual ~BigImage( ){ }
void Show( )
{
std::cout <<"This is Big Image..." <<std::endl;
}
};
// 大型图片代理器
class BigImageProxy : public Image
{
public :
BigImageProxy(std::string name) :Image(name), m_bigImage(NULL){ }
virtual ~BigImageProxy( )
{
delete m_bigImage;
}
void Show( )
{
if(this->m_bigImage == NULL)
{
m_bigImage = new BigImage(this->m_name);
}
m_bigImage->Show( );
}
private :
BigImage *m_bigImage;
};
// 客户端代码
int main( )
{
Image *Image = new BigImageProxy("Image.txt");
Image->Show( );
delete Image;
return 0;
}
参考
1、https://www.cnblogs.com/daniels/p/8242592.html
2、http://c.biancheng.net/view/1359.html
3、https://blog.youkuaiyun.com/hguisu/article/details/7542143
4、https://www.cnblogs.com/zle1992/p/9753359.html
5、《大话设计模式》