C++ | 设计模式 | 代理模式

ops/2025/2/27 17:51:09/

代理模式(Proxy Pattern)

代理模式是一种结构型设计模式 ,它为某个对象提供一个代理,以控制对该对象的访问。代理模式可以在不改变原始对象的情况下,通过引入代理对象来扩展功能或控制对原始对象的访问。

核心思想
代理模式的核心思想是通过一个代理对象来代替直接操作目标对象,从而实现对目标对象的访问控制、延迟加载、权限管理等功能。代理对象通常与目标对象实现相同的接口,因此客户端代码可以像使用目标对象一样使用代理对象,而无需感知代理的存在。
适用于需要对对象的访问进行控制或增强的场景。
通过合理使用代理模式,可以在不改变原有对象的基础上,灵活地扩展功能并提升系统的可维护性。

代理模式的分类

根据用途,代理模式可以分为以下几种类型:

远程代理(Remote Proxy)
为一个位于不同地址空间的对象提供本地代理,隐藏远程通信的细节。例如,Java RMI(远程方法调用)就是一种远程代理的实现。
虚拟代理(Virtual Proxy)
延迟创建开销较大的对象,直到真正需要时才初始化。例如,图片加载时先显示占位符,待图片下载完成后替换。
保护代理(Protection Proxy)
控制对目标对象的访问权限。例如,只有特定用户才能访问某些资源。
智能引用代理(Smart Reference Proxy)
在访问目标对象时附加额外的操作,例如引用计数、缓存、日志记录等。

代理模式的组成

Subject(抽象主题)
定义了目标对象和代理对象的共同接口,这样代理对象可以用来替代目标对象。
RealSubject(真实主题)
实现了抽象主题接口,定义了实际的业务逻辑。
Proxy(代理)
持有一个对真实主题的引用,并在需要时调用真实主题的方法。代理可以在调用前后添加额外的逻辑,比如权限检查、日志记录、延迟加载等。
Client(客户端)
使用代理对象完成对目标对象的操作。

实现

#include <iostream>
using namespace std;class VideoSite
{
public:virtual void freeMovie() = 0;virtual void vipMovie() = 0;virtual void ticketMovie() = 0;
};class FixBugVideoSite :public VideoSite
{
public:virtual void freeMovie() {cout << "free Movie" << endl;}virtual void vipMovie() {cout << "vip Movie" << endl;}virtual void ticketMovie() {cout << "ticket movie" << endl;}
};
class FreeVideoSiteProxy :public VideoSite
{
public:FreeVideoSiteProxy() {pVideo = new FixBugVideoSite();}~FreeVideoSiteProxy() { delete pVideo; }virtual void freeMovie(){pVideo->freeMovie();}virtual void vipMovie() {cout<<"error"<<endl;}virtual void ticketMovie() {cout << "error" << endl;}
private:VideoSite* pVideo;
};
class VipVideoSiteProxy :public VideoSite
{
public:VipVideoSiteProxy() {pVideo = new FixBugVideoSite();}~VipVideoSiteProxy() { delete pVideo; }virtual void freeMovie(){pVideo->freeMovie();}virtual void vipMovie() {pVideo->vipMovie();}virtual void ticketMovie() {cout << "error" << endl;}
private:VideoSite* pVideo;
};void watch(VideoSite* p)
{p->freeMovie();p->vipMovie();p->ticketMovie();
}
int main()
{VideoSite* p1 = new FreeVideoSiteProxy();VideoSite* p2 = new VipVideoSiteProxy();watch(p1);watch(p2);std::cout << "Hello World!\n";
}

事例

场景描述
假设我们有一个 Image 类,用于加载和显示图片。由于图片加载可能需要耗费大量资源,我们可以使用虚拟代理来延迟加载图片,直到真正需要显示时才加载。

#include <iostream>
#include <memory> // 使用智能指针管理资源// 抽象主题接口
class Image {
public:virtual void display() = 0; // 显示图片的接口virtual ~Image() = default; // 虚析构函数确保正确释放资源
};// 真实主题类
class RealImage : public Image {
private:std::string fileName;void loadFromDisk() {std::cout << "加载图片: " << fileName << " 从磁盘..." << std::endl;}public:explicit RealImage(const std::string& fileName) : fileName(fileName) {loadFromDisk(); // 模拟图片加载过程}void display() override {std::cout << "显示图片: " << fileName << std::endl;}
};// 代理类
class ProxyImage : public Image {
private:std::unique_ptr<RealImage> realImage; // 使用智能指针管理真实对象std::string fileName;public:explicit ProxyImage(const std::string& fileName) : fileName(fileName), realImage(nullptr) {}void display() override {if (!realImage) {realImage = std::make_unique<RealImage>(fileName); // 延迟加载}realImage->display();}
};// 客户端代码
int main() {// 创建代理对象std::unique_ptr<Image> image1 = std::make_unique<ProxyImage>("photo1.jpg");std::unique_ptr<Image> image2 = std::make_unique<ProxyImage>("photo2.jpg");// 第一次调用 display 时会加载图片std::cout << "第一次调用:" << std::endl;image1->display();// 第二次调用 display 时不会重新加载图片std::cout << "\n第二次调用:" << std::endl;image1->display();// 另一个图片对象std::cout << "\n另一个图片对象:" << std::endl;image2->display();return 0;
}

运行结果

第一次调用:
加载图片: photo1.jpg 从磁盘...
显示图片: photo1.jpg第二次调用:
显示图片: photo1.jpg另一个图片对象:
加载图片: photo2.jpg 从磁盘...
显示图片: photo2.jpg

代码解析

  1. 抽象主题接口 (Image)
  • 定义了 display() 方法,作为所有图片对象的统一接口。
  • 使用虚析构函数确保子类对象能够被正确释放。
  1. 真实主题类 (RealImage)
  • 实现了 display() 方法,负责实际的图片加载和显示。
  • 在构造函数中模拟了从磁盘加载图片的过程。
  1. 代理类 (ProxyImage)
  • 持有一个指向 RealImage 的智能指针 (std::unique_ptr)。
  • 在第一次调用 display() 时创建 RealImage 对象(延迟加载)。
  • 后续调用直接复用已创建的 RealImage 对象。
  1. 客户端代码
  • 客户端通过代理对象访问图片,无需感知图片是否已经加载。

代理模式的优点(在 C++ 中体现)

  1. 资源管理优化
    延迟加载减少了不必要的资源消耗,尤其适用于大型文件或高开销对象。
  2. 代码解耦
    客户端代码与真实对象的实现完全解耦,符合开闭原则。
  3. 功能扩展
    可以轻松扩展代理类的功能,例如添加日志记录、权限检查等。

http://www.ppmy.cn/ops/161739.html

相关文章

WPS接入DeepSeek模型免费版本

WPS灵犀正式上线DeepSeek R1&#xff01; 参考原文&#xff1a;WPS接入DeepSeek模型免费版本 今年年初&#xff0c;WPS 官方正式发布重磅消息&#xff1a;WPS 全面接入 DeepSeek R1 大模型。用户只需将 WPS 更新到最新版本&#xff0c;登录账号后&#xff0c;点击界面左侧的「…

解锁C# XML编程:从新手到实战高手的蜕变之路

一、引言&#xff1a;XML 在 C# 中的关键地位 在 C# 开发的广袤领域中&#xff0c;XML&#xff08;可扩展标记语言&#xff0c;eXtensible Markup Language&#xff09;宛如一颗璀璨的明星&#xff0c;占据着举足轻重的地位。它以其独特的结构化和自描述特性&#xff0c;成为了…

IDEA创建Spring配置文件Spring Config的方法

作为刚刚开始学Spring框架的小白&#xff0c;而且我也是刚刚学怎么用idea&#xff0c;不会简单的操作也是很正常的是吧。这个问题其实只是我傻傻的不懂&#xff0c;是个很简单的问题&#xff0c;我现在把它记录下来。 在idea创建maven项目后&#xff0c;我们在左边右键新建xml文…

爬虫案例-爬取某猫的电影数据

文章目录 1.爬取的代码2.效果图 1.爬取的代码 import requests import time import random import hashlib import pandas as pdurl "https://piaofang.maoyan.com/dashboard-ajax?"header {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; …

DeepSeek-R1论文阅读及本地调用

前言 DeepSeek已经火了一段时间了&#xff0c;对于这项“国运级”的技术成果&#xff0c;即便研究的不是这个方向&#xff0c;也不免好奇前来看看。本文将先解析一下DeepSeek-R1这篇论文&#xff0c;再对DeepSeek的本地部署使用进行研究配置。 论文标题&#xff1a;DeepSeek-…

一周学会Flask3 Python Web开发-Jinja2模板过滤器使用

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 在Jinja2中&#xff0c;过滤器(filter)是一些可以用来修改和过滤变量值的特殊函数&#xff0c;过滤器和变量用一个竖线 | &a…

Java基础关键_011_ String 类与正则表达式(二)

目 录 一、正则表达式 1.说明 2.应用 3. 相关方法 &#xff08;1&#xff09;replace(CharSequence target, CharSequence replacement) &#xff08;2&#xff09;replaceAll(String regex, CharSequence replacement) &#xff08;3&#xff09;split(String regex) &…

huggingface部署本地大模型DeepSeek-R1-Distill-Llama-70B使用streamlit构建交互式 Web 应用

文章目录 一、Streamlit介绍二、模型下载三 、模型部署四、效果展示 一、Streamlit介绍 Streamlit 是一个开源的 Python 库&#xff0c;专门用于快速构建和部署交互式 Web 应用程序&#xff0c;尤其适合数据科学和机器学习领域。以下是关于 Streamlit 的详细介绍&#xff1a; …