这是个人学习编程模式的系列学习笔记第四篇。
采用Qt Creator进行编写,但尽量采用C++基础语法。
代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。有四种常用的情况:(1)远程代理( Remote Proxy ),(2)虚代理(Virtual Proxy),(3)保护代理(Protection Proxy),(4)智能引用(Smart Reference)。
个人理解,由于某些原因,不直接访问具体的对象,需要通过一个代理类来访问对象。比如:
(1)具体要访问的对象在网络上,通过代理类进行访问可以进行网络层面的转换,实现对远程对象的访问,这是远程代理的应用;
(2)具体对象较为复杂,初始化比较慢,占用资源较多。采用代理类来在需要的时候才进行具体对象的实际加载(比如文档中的图片对象的加载比较慢,为保障文档打开的速度,通常在开始只加载图像的代理对象),这是虚代理的应用;
(3)具体对象需要某种保护或权限控制,不允许直接访问具体对象,通过代理对象对访问进行一定的权限控制或安全检查,这是保护代理的应用;
(4)智能引用可理解为更为灵活的指针,可以根据实际需求进行灵活的引用或创建控制(比如在实际第一次引用时加载具体对象,多次引用是计数,没有引用时销毁,或者引用的时候检测使用有别人在用等)。
在实现方式上,代理模式和装饰模式比较类似,先定义接口类,然后具体对象类和代理类都继承这个接口,具有一致的行为模式(代理必然需要与他代理的人具有类似的行为模式)。代理类需要知道具体的代理对象,并有具体的标识能标识其所代理的对象(比如用文件名标识具体的文件对象)。用户调用代理类时,代理类将具体的动作转发给具体的对象进行实际的操作(当然在这之前代理类会根据自己的角色完成对应的工作)。
以下主要用一个例子来演示两种代理模式:虚代理和保护代理。为方便,这两种模式在一个例子中实验,也就是说这个代理同时体现了虚代理和保护代理的工作。
场景描述
假设有一个公司要发布一款新型车,但是新车研发和制作时间长,因此这个公司决定先不研发新车,只有用户提出需要车辆实际上路测试的时候才研发制造新车。(虚代理)
甚至为了尽可能的降低这种制造新车的可能,如果发布会在中国召开的话,就算有上路测试的需求,也只提供测试视频来代替(保护代理)。
设计思路
定义一个Vehicle类作为接口类,再定义一个Car类作为新型号汽车类,一个PPT类作为发布会的演示产品。
定义一个Presentation类作为客户端类,完成演示交互。
UML图
代码
#include <algorithm>
#include <iostream>
using namespace std;
class Vehicle
{
protected:
string m_Model;
public:
Vehicle(string model):m_Model(model) {}
virtual ~Vehicle(){}
virtual void run(){}
};
class Car : public Vehicle
{
public:
Car(string model):Vehicle(model) {}
void run() { cout<<"This is the new style car on the road! -----"<<m_Model<<"\n"; }
};
class PPT : public Vehicle
{
private:
string m_Local;
Car* m_Car = 0;
public:
PPT(string model, string locale):Vehicle(model),m_Local(locale) {}
~PPT(){delete m_Car;}
void run()
{
if(!m_Car)
{
if(m_Local == "CHINA")
{
cout<<"This is the new style car on the movie!----"<<m_Model<<"\n";
}
else
{
m_Car = new Car(m_Model);
m_Car->run();
}
return;
}
m_Car->run();
return;
}
};
class Presentation
{
private:
Vehicle* m_News = 0;
public:
Presentation(Vehicle* news):m_News(news) {}
~Presentation() {delete m_News;}
void show(){m_News->run();}
};
int main()
{
string model = "";
string local = "";
cout<<"Please name the new car: ";
getline(cin, model);
cout<<"Please input the nation: ";
getline(cin, local);
transform(local.begin(), local.end(), local.begin(), ::toupper);
PPT* ppt = new PPT(model, local);
Presentation* presentation = new Presentation(ppt);
presentation->show();
delete presentation;
return 0;
}