【设计模式学习笔记十三】【结构型模式】【代理模式(Proxy)】

时间:2022-10-01 07:26:21

本文是学习刘伟技术博客和《设计模式-可复用面向对象软件的基础》笔记,博客链接:http://blog.csdn.net/lovelion/article/details/17517213

主要是对博客和书本做提炼和记录,更多是对设计模式的基础框架学习,细节将略去,侧重对每个设计模式框架的理解。

我应该理解和掌握的:

1)能够画出这个设计模式的架构框图;

2)能够根据架构框图写出对应的伪代码;

3)这个模式的应用场景,主要优缺点。

1.代理模式

在软件开发中,有一种模式类似于代购,即客户端由于某种原因不想或不能直接访问一个对象,此时可以通过一个代理对象来实现间接访问,该方案被称为代理模式。

(1)定义

代理模式:为其他对象提供一种代理以控制对这个对象的访问。

代理又可分为四种:

a)远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是同一台主机中,也可以在另一台主机中,远程代理又称为大使。

b)虚拟代理(Virtual Proxy):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正的创建。

c)保护代理(Protect Proxy):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。

d)缓冲代理(Cache Proxy):为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

e)智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来,比如智能指针。

1)代理模式结构图

【设计模式学习笔记十三】【结构型模式】【代理模式(Proxy)】

2)参与者

a) Subject(抽象主题角色):定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用proxy。

b) RealSubject(真实主题角色):定义了Proxy所代表的实体。

c) Proxy(代理):保存一个引用是的代理可以访问实体;提供一个与Subject相同的接口,这样代理就可以用来替代实体;控制对实体的存取,并可能负责创建或删除它;其他功能依赖于代理的类型。

3)看图写代码

/*
** FileName : ProxyPattern
** Author : lin005
** Date : 2015/01/29
** Description : More information, please go to http://blog.csdn.net/amd123456789
*/
#include<iostream>
#include<windows.h>
using namespace std;
//抽象主题角色
class Subject
{
public:
virtual void Request() = 0;
};
//真实主题角色
class RealSubject:public Subject
{
public:
void Request()
{
cout<<"RealSubject Request()"<<endl;
}
};
//代理
class Proxy:public Subject
{
public:
Proxy()
{
real = new RealSubject();
}
~Proxy()
{
if(real != NULL)
{
delete real;
real = NULL;
}
}
void preRequest()
{
cout<<"preRequest()"<<endl;
}
void postRequest()
{
cout<<"postRequest"<<endl;
}
//调用真正实体
void Request()
{
preRequest();
real->Request();
postRequest();
}
private:
RealSubject *real;
};
//客户端测试类
int main()
{

Subject *proxy = new Proxy();
proxy->Request();

if(proxy)
{
delete proxy;
proxy = NULL;
}
return 0;
}

4)智能指针

智能指针,使用引用计数时,也可以看做是代理模式的应用。下面例子中,SmartPtr就是代理类,实际对象是ptr;SmartPtr代理ptr的行为,运用引用计数,实现智能指针。

代码来自百度百科:

/*
** FileName : ProxyPattern
** Author : lin005
** Date : 2015/01/30
** Description : More information, please go to http://blog.csdn.net/amd123456789
*/
//被代理的对象
class Stub
{
public:
void print()
{
cout<<"test"<<endl;
}
~Stub()
{
cout<<"stub::destructor"<<endl;
}
};
//可以看做代理
template<typename T>
class SmartPtr
{
public:
SmartPtr(T* p = 0):ptr(p),count(new size_t(1)){}
SmartPtr(const SmartPtr<T> & src):ptr(src.ptr),count(src.count)
{
++*count;
}
//重载赋值操作符
SmartPtr& operator=(const SmartPtr & src)
{
++*src.count;
release();
ptr = src.ptr;
count = src.count;
return *this;
}
T* operator->()
{
if(ptr)
return ptr;
}
const T* operator->()const
{
if(ptr)
return ptr;
}
T& operator*()
{
if(ptr)
return *ptr;
}
const T& operator*()const
{
if(ptr)
return *ptr;
}
~SmartPtr()
{
release();
}
private:
void release()
{
if(--*count == 0)
{
delete ptr;
delete count;
}
}
private:
T* ptr;//真实对象
size_t* count;//引用计数
};
int main()
{
//智能指针,类型为Stub
SmartPtr<Stub> t;
t->print();//print test

SmartPtr<Stub> t1(new Stub());
SmartPtr<Stub> t2(t1);
SmartPtr<Stub> t3(new Stub());
t3= t2;//call t3 destructor
t1->print(); //print
(*t3).print(); //print
return 0;
/*
输出结果:
test
stub::destructor (析构t3)
test
test
stub::destructor (析构t1)
请按任意键继续. . .
*/
}

(2)总结

1)优点

a) 能够协调调用者和被调用者,在一定程度上降低了系统的耦合。

b) 客户端可以针对抽象角色进行编程。

2)缺点

a) 增加代理对象有些类型的代理模式可能会造成请求的处理速度变慢,例如保护代理。

b) 是在代理模式需要额外的工作,并且有些代理模式实现过程较为复杂,例如远程代理。

(3)适用场景

1)远程代理为一个对象在不同的地址空间提供局部代表;

2)虚代理根据需要创建开销很大的对象。

3)当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时使用保护代理

4)当需要为一个对象的访问提供额外的操作时,可以使用智能引用代理。