代理模式的核心是通过替身控制对真实对象的访问,其目的是在不修改真实对象的前提下实现延迟加载、权限控制等额外逻辑。要实现代理模式,首先要定义共同接口subject,让realsubject和proxy都实现它;其次代理持有真实对象的引用,并在其方法中加入前置或后置处理逻辑;最后根据需求扩展虚拟代理或保护代理。虚拟代理侧重按需加载,适用于资源占用大的场景;保护代理则用于权限检查,确保系统安全。这种设计提升了系统的灵活性、可维护性与安全性。

C++中实现代理模式,本质上是在不直接接触真实对象的情况下,通过一个“替身”来控制对真实对象的访问。虚拟代理常用于延迟加载资源,优化性能,而保护代理则侧重于访问权限控制,确保系统安全。这两种代理模式各有侧重,但都旨在提供更灵活、更安全的面向对象设计。

要实现C++的代理模式,核心在于定义一个共同的接口(Subject),让真实对象(RealSubject)和代理对象(Proxy)都实现它。代理对象内部持有真实对象的引用,并在自己的方法中调用真实对象的方法,但在此之前或之后加入额外的逻辑。
一个典型的结构会是这样:
立即学习“C++免费学习笔记(深入)”;

#include#include #include // For std::this_thread::sleep_for #include // For std::this_thread // 共同接口 class Subject { public: virtual void request() = 0; virtual ~Subject() = default; }; // 真实对象 class RealSubject : public Subject { public: void request() override { // 真实对象执行核心业务逻辑 // 比如:加载大型图片、执行耗时计算、访问敏感数据 std::cout << "RealSubject: Handling request." << std::endl; } }; // 代理对象基类(可以抽象出,也可以直接实现特定代理) // 这里以一个通用的代理为例 class GeneralProxy : public Subject { protected: RealSubject* realSubject; // 代理持有真实对象的引用 public: GeneralProxy() : realSubject(nullptr) {} // 默认构造,可能在需要时才创建RealSubject ~GeneralProxy() { delete realSubject; // 清理资源 } // 代理的核心:在调用真实方法前后加入逻辑 void request() override { // 这是通用代理的模板,具体代理会重写此方法 if (!realSubject) { // 假设这里是虚拟代理的创建逻辑 realSubject = new RealSubject(); std::cout << "GeneralProxy: Creating RealSubject on demand." << std::endl; } // 在调用真实方法前可以做些什么 std::cout << "GeneralProxy: Pre-processing request." << std::endl; realSubject->request(); // 在调用真实方法后可以做些什么 std::cout << "GeneralProxy: Post-processing request." << std::endl; } };
实际应用中,虚拟代理和保护代理会在此基础上增加特有的逻辑。例如,虚拟代理会在 request 首次调用时才创建 RealSubject 实例;保护代理则会在 request 调用前检查调用者的权限。
C++代理模式的核心理念是什么,为何我们应该考虑使用它?
代理模式,说白了,就是给一个对象找个“替身”。这个替身(Proxy)和原对象(RealSubject)实现同一个接口,所以客户端代码完全不知道自己打交道的是替身还是真身。这听起来有点像在玩“障眼法”,但它的价值可不小。

我个人觉得,代理模式最迷人的地方在于它提供了一种“间接性”的控制。我们不需要直接修改真实对象的代码,就能在它被访问时,或者访问它之后,插入各种额外的逻辑。这对于那些我们无法修改、不应该修改或者修改成本很高的第三方库、遗留系统中的类尤其有用。
为什么要用它?想象一下,你有一个非常“重”的对象,比如加载一张几百兆的图片,或者从一个远程数据库拉取大量数据。你肯定不希望在程序启动时就把所有这些东西都加载进来,那样程序会慢得像蜗牛。这时候,代理就能派上用场了。它可以在你真正需要这些数据的时候,才去加载它们。这就是一种性能优化,一种延迟加载的策略。
再比如,你有一个核心的业务逻辑对象,但不是所有用户都能访问它的所有功能。有些功能只允许管理员操作,有些只允许普通用户查看。你当然可以在真实对象的方法里写一堆 if (user.role == ADMIN) 这样的判断,但那样会把真实对象的代码搞得一团糟,而且职责也不清晰。这时候,代理就可以在访问真实对象之前,先检查一下用户的权限。权限不够?直接拒绝访问,连真实对象一眼都看不到。这不就是一种优雅的访问控制吗?
所以,核心理念就是:通过引入一个中间层,在不改变原有接口的前提下,对真实对象的访问进行控制、增强或限制。它提供了一种解耦的方案,让我们可以把一些非核心的、横切的关注点(比如延迟加载、访问控制、日志记录、缓存等)从真实对象中剥离出来,保持真实对象的纯粹性,同时提升系统的灵活性和可维护性。在我看来,这是一种非常“面向对象”的思考方式,把职责划分得清清楚楚。
虚拟代理与其他代理有何不同,何时它能真正发挥作用?
虚拟代理,顾名思义,就是一种“假”的代理,它在开始时并不持有真实对象的实例,而是在真实对象第一次被需要时才去创建它。这与那些一开始就持有真实对象引用的代理(比如保护代理或远程代理)形成了鲜明对比。它的核心思想就是“按需加载”(Lazy Loading)。
我记得有一次,我手头一个项目需要显示一个包含大量高分辨率图片的列表。如果我直接在列表加载的时候就把所有图片都加载到内存里,那程序启动速度会非常慢,而且内存占用会爆炸。用户可能根本不会滚动到列表的底部,或者根本不会点击查看所有图片。这时候,虚拟代理简直是救星。
它的实现通常是这样的:代理对象在构造时并不会创建真实对象,而是持有一个指向真实对象类型,但初始为空的指针。当客户端代码第一次调用代理的某个方法时,代理会检查这个指针是否为空。如果为空,它就负责创建真实对象的实例,然后将后续的请求转发给这个新创建的真实对象










