代理模式的几种应用实例:
1. 远程代理
为远程程序在本地建立局部代理,可以隐藏外部资源存在于不同地址空间的事实,例如建立 agent 代理类处理 Socket 的数据发送与接收控制。生活中的典型例子还有有游戏代理服务器(加速器,远端计算机具有更优秀的计算能力和处理速度,加快响应和数据交互)。
2. 虚代理
延迟大型对象的构造。一开始只建立代理,一直到真正需要大型对象的时候才创建它,类似于 local static 对象。生活中的典型例子有快捷方式,直到点击应用程序才真正启动程序;浏览器解析图片,视频等大文件时,会采取延迟策略,优先显示文本和缩略图,直到用户需要完整图片和视频时才完整显示。
例子:快捷方式
#include <bits/stdc++.h>
#define rep( i , j , n ) for ( int i = int(j) ; i < int(n) ; ++i )
#define dew( i , j , n ) for ( int i = int(n-1) ; i > int(j) ; --i )
#define _PATH __FILE__ , __LINE__
typedef std::pair < int , int > P ;
namespace PROXY {
// 基类提供接口
class Source {
public:
virtual ~Source() = default;
virtual void call() = 0;
virtual void clear() = 0;
virtual void display(std::string) = 0;
} ;
// 隐藏在代理对象背后真正的数据端
class Application : public Source {
private:
// 该应用程序启动需要很多的资源
std::vector<std::string> userData = { "YHL", "Fluence" };
public:
void call() override {
std::cout << "真正的应用程序启动\n\n";
}
void clear() override {
userData.clear();
userData.shrink_to_fit();
}
void display(std::string picturePath) override {
std::cout << "软件界面初始化...\n\n";
}
} ;
// 客户直接操作“代理对象”, 逻辑端
class App_proxy : public Source {
private:
std::shared_ptr<Application> ptr;
public:
// 直到真正需要应用程序 ( call ) 的时候才会构造
void call() override {
if(ptr == nullptr)
ptr = std::make_shared<Application>();
std::cout << "点击快捷方式\n\n";
ptr->call();
}
void clear() override {
// 前期准备工作, if 逻辑判断, 打日志, 线程加锁等
ptr->clear(); // ------ 真正的数据实现
// 后期清理工作, 日志记录, 线程解锁等
}
void display(std::string picturePath) override {
// 根据应用程序是否启动而不同显示
if(ptr != nullptr) {
picturePath = ".../.../main_Picture";
ptr->display(picturePath);
return;
}
// 根据图片资源路径只显示快捷方式的图标......
std::cout << "快捷方式图标初始化...\n\n";
}
} ;
}
int main () {
PROXY::App_proxy proxy;
// 一般情况下不启动, 但是有快捷方式
proxy.display(".../.../...");
// 直到大对象真正被需要的时候再创建
proxy.call();
proxy.display(".../.../...");
return 0;
}
程序运行结果:
优点:
(1)代理类 App_proxy 和大对象 Application 拥有一样的接口,代理可以替代大对象的行为。
(2)逻辑和实现分离,分文件时可以减低文件之间的编译依赖性。例如上述 clear 函数:
void clear() override {
// 前期准备工作, if 逻辑判断, 打日志, 线程加锁等
ptr->clear(); // ------ 真正的数据实现
// 后期清理工作, 日志记录, 线程解锁等
}
(3)延迟生成大对象,直到真正被需要的时候才创建。
缺点:
(1)增加了一层间接访问
(2)如果大对象一定会被创建,会造成一个 shared_ptr 的损失,以及 virtual 机制的损耗(一个 vptr + 虚函数运行时查找)。
3. Pimpl
对象内含一个指针,指向另一个对象(另一个对象常常含真正的数据),就是所谓的 pimpl 手法——典型例子是 std::shared_ptr 等智能指针,代理类。
优点:
(1)方便实现引用计数。
(2)控制数据的建立,访问权限和销毁。
(3)逻辑和实现分离。
(4)大型对象赋值或者交换时只需要交换指针,提高效率。
4. Cache 代理
借鉴计算机高速缓存器的思想,将经常访问的数据(抑或是计算结果)缓存,以局部思想提高数据处理速度。
5. 动态代理模式