设计模式:代理模式(Proxy Pattern)

文章目录

    • 一、代理模式的定义
    • 二、实例分析
    • 三、示例代码

一、代理模式的定义

  代理模式是一种结构型设计模式,它为某个对象提供一个代理或占位符,以控制对这个对象的访问。简单来说代理对象在客户端和目标对象之间起到中介作用,客户端并不会直接操作目标对象,而是通过代理对象间接访问。
在这里插入图片描述
代理模式常用于以下情况:

  1. 远程代理:为远程对象(在不同地址空间、服务器上)提供本地代理,隐藏远程访问的复杂性。
  2. 虚拟代理:在需要消耗大量资源时,先用代理延迟对象的创建或初始化。(如:大图片的延迟加载)
  3. 保护代理:控制不同用户对对象的访问权限。(如:文件系统访问控制)
  4. 智能代理:在访问对象时附加额外操作(如缓存、日志、计数、线程安全控制)。

代理模式结构:
在这里插入图片描述

二、实例分析

问题:
为什么要控制对于某个对象的访问呢? 举个例子: 有这样一个消耗大量系统资源的巨型对象, 你只是偶尔需要使用它, 并非总是需要。
在这里插入图片描述
你可以实现延迟初始化: 在实际有需要时再创建该对象。 对象的所有客户端都要执行延迟初始代码。 不幸的是, 这很可能会带来很多重复代码。

在理想情况下, 我们希望将代码直接放入对象的类中, 但这并非总是能实现: 比如类可能是第三方封闭库的一部分。

解决方案:
代理模式建议新建一个与原服务对象接口相同的代理类, 然后更新应用以将代理对象传递给所有原始对象客户端。 代理类接收到客户端请求后会创建实际的服务对象, 并将所有工作委派给它。
在这里插入图片描述
这有什么好处呢? 如果需要在类的主要业务逻辑前后执行一些工作, 你无需修改类就能完成这项工作。 由于代理实现的接口与原类相同, 因此你可将其传递给任何一个使用实际服务对象的客户端。

真实世界类比:
在这里插入图片描述
信用卡是银行账户的代理, 银行账户则是一大捆现金的代理。 它们都实现了同样的接口, 均可用于进行支付。 消费者会非常满意, 因为不必随身携带大量现金; 商店老板同样会十分高兴, 因为交易收入能以电子化的方式进入商店的银行账户中, 无需担心存款时出现现金丢失或被抢劫的情况。

代码实现:

  • 抽象接口:Payment,定义统一的 pay(amount) 方法。
  • 真实主题(RealSubject):Cash,表示真正的支付方式(现金支付)
  • 代理(Proxy):CreditCard,作为银行账户的代理,内部持有一个 BankAccount(或 Cash)对象,通过代理实现支付。
#include <iostream>
#include <memory>
using namespace std;// 抽象接口
class Payment {
public:virtual void pay(double amount) = 0;virtual ~Payment() = default;
};// 真实主题:现金支付
class Cash : public Payment {
public:void pay(double amount) override {cout << "支付现金: " << amount << " 元" << endl;}
};// 银行账户(被代理对象)
class BankAccount {
public:void withdraw(double amount) {cout << "从银行账户扣款: " << amount << " 元" << endl;}
};// 代理:信用卡支付
class CreditCard : public Payment {
private:BankAccount* account; // 代理对象内部持有真实对象
public:CreditCard(BankAccount* acc) : account(acc) {}void pay(double amount) override {cout << "使用信用卡支付: " << amount << " 元" << endl;account->withdraw(amount); // 实际通过银行账户扣款}
};// 客户端
int main() {// 使用现金支付unique_ptr<Payment> cashPayment = make_unique<Cash>();cashPayment->pay(100);// 使用信用卡支付(代理)BankAccount bankAcc;unique_ptr<Payment> creditPayment = make_unique<CreditCard>(&bankAcc);creditPayment->pay(200);return 0;
}

三、示例代码

示例一:

#include <iostream>
#include <memory>
using namespace std;// 抽象主题
class Subject {
public:virtual void request() = 0;virtual ~Subject() = default;
};// 真实主题
class RealSubject : public Subject {
public:void request() override {cout << "RealSubject: Handling request." << endl;}
};// 代理类
class Proxy : public Subject {
private:unique_ptr<RealSubject> realSubject;
public:void request() override {if (!realSubject) {cout << "Proxy: Creating RealSubject." << endl;realSubject = make_unique<RealSubject>();}cout << "Proxy: Delegating request to RealSubject." << endl;realSubject->request();}
};// 客户端
int main() {Proxy proxy;proxy.request(); // 第一次访问,创建真实对象proxy.request(); // 第二次访问,直接使用已有对象return 0;
}

示例二:
数据库模块(QSqlQuery)+ 缓存代理的实际应用示例

设计思路:

  • 接口类 IDatabase:定义通用的查询接口
  • 真实类 RealDatabase:直接使用 QSqlDatabase + QSqlQuery 访问数据库。
  • 代理类 DatabaseProxy:在真实查询前先检查缓存,缓存命中就直接返回结果,避免重复访问数据库。
#include <QCoreApplication>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QtSql/QSqlError>
#include <QDebug>
#include <QVariant>
#include <QMap>
#include <QStringList>// 抽象接口
class IDatabase {
public:virtual QStringList query(const QString& sql) = 0;virtual ~IDatabase() = default;
};// 真实数据库类
class RealDatabase : public IDatabase {
private:QSqlDatabase db;
public:RealDatabase() {// 连接 SQLite 数据库db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName(":memory:"); // 内存数据库,演示用if (!db.open()) {qWarning() << "Database error:" << db.lastError().text();}// 初始化数据QSqlQuery q;q.exec("CREATE TABLE users (id INT, name TEXT)");q.exec("INSERT INTO users VALUES (1, 'Alice')");q.exec("INSERT INTO users VALUES (2, 'Bob')");}QStringList query(const QString& sql) override {QSqlQuery q;QStringList result;if (!q.exec(sql)) {qWarning() << "SQL error:" << q.lastError().text();return result;}while (q.next()) {result << q.value(0).toString(); // 只取第一列}qDebug() << "[RealDatabase] Executing:" << sql;return result;}
};// 代理类,带缓存
class DatabaseProxy : public IDatabase {
private:RealDatabase* realDb;QMap<QString, QStringList> cache; // SQL -> 查询结果
public:DatabaseProxy() : realDb(nullptr) {}QStringList query(const QString& sql) override {// 缓存检查if (cache.contains(sql)) {qDebug() << "[Proxy] Cache hit for:" << sql;return cache[sql];}// 创建真实对象if (!realDb) {realDb = new RealDatabase();}qDebug() << "[Proxy] Cache miss, querying DB:" << sql;QStringList result = realDb->query(sql);// 存入缓存cache[sql] = result;return result;}~DatabaseProxy() {delete realDb;}
};// 测试
int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);IDatabase* db = new DatabaseProxy();qDebug() << db->query("SELECT name FROM users WHERE id=1");qDebug() << db->query("SELECT name FROM users WHERE id=2");qDebug() << db->query("SELECT name FROM users WHERE id=1"); // 命中缓存delete db;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/97587.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/97587.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据类型序列化-封装

/// <summary> /// 定义泛型接口 /// </summary> /// <typeparam name"T">T</typeparam> public interface ISettingValue<T> {/// <summary>/// value/// </summary>T DoubleValue { get; }/// <summary>/// key//…

PitVis-2023挑战赛:内镜下垂体瘤手术视频中的手术流程识别|文献速递-深度学习人工智能医疗图像

Title题目PitVis-2023 challenge: Workflow recognition in videos of endoscopic pituitary surgeryPitVis-2023挑战赛&#xff1a;内镜下垂体瘤手术视频中的手术流程识别01文献速递介绍内镜视觉挑战赛与PitVis-2023挑战赛背景及核心内容 “内镜视觉&#xff08;EndoVis&#…

2025年8月个人工作生活总结

本文为 2025年8月工作生活总结。研发编码 无处不在的AI 现在很多地方都在推AI&#xff0c;广西的人工智能走在前列&#xff0c;要赋能各行各业。至于我&#xff0c;主要就是在写点代码&#xff0c;写点交差的文档。其实现在我已经有点分析哪些代码哪些文字是AI写的了。我工作用…

Dubbo常见面试题

1、默认使用的是什么通信框架&#xff0c;还有别的选择吗? 默认也推荐使用netty框架&#xff0c;还有mina。 2、服务调用是阻塞的吗&#xff1f; 默认是阻塞的&#xff0c;可以异步调用&#xff0c;没有返回值的可以这么做。 3、一般使用什么注册中心&#xff1f;还有别的…

简单的加密算法

// 加密函数&#xff08;32位版本&#xff09; //这里的 data 是ID&#xff0c; dword encrypt(dword data, dword key, int shift) {data ^ key; // 第一步&#xff1a;异或混淆// 循环左移&#xff08;shift范围1-31&#xff09;return (data << sh…

升级的MS9125S USB投屏控制芯片(VGAHD输出)

MS9125S是一款USB单芯片投屏器&#xff0c;内部集成了USB 2.0控制器和数据收发模块、视频DAC、HD接口和音视频处理模块&#xff0c;支持压缩视频传输。MS9125S可以通过USB接口显示或者扩展PC、智能手机、平板电脑的显示信息到更大尺寸的显示设备上&#xff0c;支持VGA和HD视频接…

求欧拉回路:Hierholzer算法图解模拟

代码模板&#xff1a;List<Integer> resultList new ArrayList<>();List<Integer> hierholzer() {dfs(0);resultList.add(0);// 数组反转Collections.reverse(resultList);return resultList; }void dfs(int start) {for(int end : G[start]) {if(!vis[star…

Kafka面试精讲 Day 2:Topic、Partition与Replica机制

【Kafka面试精讲 Day 2】Topic、Partition与Replica机制 在“Kafka面试精讲”系列的第二天&#xff0c;我们将深入剖析Kafka最核心的三大数据组织机制&#xff1a;Topic&#xff08;主题&#xff09;、Partition&#xff08;分区&#xff09;与Replica&#xff08;副本&#x…

【备战2025数模国赛】(三)数模常见赛题类型及解决办法

在进行数学建模竞赛时&#xff0c;很多同学面临的第一个挑战是如何对赛题进行归类&#xff0c;并选择合适的模型。本篇梳理了数学建模中最常见的几类赛题&#xff0c;并针对每类题型提供了基本的解决思路&#xff0c;帮助大家快速选择合适的解题方法&#xff0c;高效完成模型构…

LabVIEW测斜设备承压试验台

为保障煤矿井下地质勘探钻孔中测斜装备的可靠运行&#xff0c;设计基于 LabVIEW的钻孔测斜设备承压性能试验台。该试验台以气动增压泵为压力执行元件&#xff0c;结合虚拟仪器与 PLC 控制技术&#xff0c;可精准模拟井下压力环境&#xff0c;完成水压、疲劳等试验&#xff0c;实…

四、练习1:Git基础操作

练习1&#xff1a;Git基础操作 练习目标 通过实际操作掌握Git的基本命令&#xff0c;包括初始化仓库、添加文件、提交更改等。 练习步骤 步骤1&#xff1a;环境准备 确保已安装Git配置用户信息&#xff08;如果未配置&#xff09; # 检查Git版本 git --version# 配置用户信息 g…

RK3399内核驱动实战:获取设备号控制LED的四种方法(由浅入深、代码注释详尽)

RK3399 内核驱动实战&#xff1a;获取设备号控制 LED 的四种方法&#xff08;由浅入深、代码注释详尽&#xff09; 在 Linux 字符设备驱动开发中&#xff0c;设备号&#xff08;major minor&#xff09;是内核与用户空间沟通的桥梁。文章围绕设备号这一条线展开&#xff0c;从…

2025年AI智能体开源技术栈全面解析:从基础框架到垂直应用

2025年&#xff0c;开源AI智能体技术正以前所未有的速度重塑人工智能领域&#xff0c;从单一任务处理到复杂多智能体协作&#xff0c;开源生态已成为技术创新的核心驱动力。一、开源AI智能体生态概述 1.1 技术演进与发展历程 AI智能体技术经历了从规则式智能体&#xff08;2015…

Empire: LupinOne靶场渗透

Empire: LupinOne 来自 <https://www.vulnhub.com/entry/empire-lupinone,750/#top> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.128&#xff0c;靶场IP192.16…

飞腾2000+/64核 PCIE扫描异常问题排查

1、背景介绍近期项目中采用全国产飞腾计算模块搭配一块FPGA模块&#xff08;FPGA为复旦微的VU9P&#xff09;&#xff0c;实现业务数据的收发。FPGA中采用了Xilinx的XDMA IP核&#xff0c;飞腾计算模块中的FT2000/64核处理器通过PEU1的一路 PCIE3.0x8与VU9P相连接&#xff0c;发…

证明与激励:Walrus 可编程数据如何通过激励可用性证明获得安全性

Walrus 的可用性证明&#xff08;Proof of Availability&#xff0c;PoA&#xff09; 是部署在 Sui 上的链上凭证&#xff0c;它为数据托管创建了一个可验证的公开记录&#xff0c;并作为存储服务正式启动的标志。PoA 中的“激励”来自一个健全的经济框架&#xff1a;存储节点需…

云存储(参考自腾讯云计算工程师认证)

目录 存储基础知识&#xff1a; RAID&#xff1a; 云存储概述&#xff1a; 云存储产品&#xff1a; CBS&#xff1a; CFS文件存储&#xff1a; COS对象存储&#xff1a; 云存储安全&#xff1a; 存储基础知识&#xff1a; 机械硬盘&#xff1a;HDD&#xff0c;即传统硬…

面试tips--JVM(2)--对象创建的过程

一、创建对象的完整过程1. 类加载检查JVM 遇到 new 指令时&#xff0c;首先去检查这个类 User 是否已经被加载、解析和初始化过。如果没有&#xff0c;就先执行 类加载过程&#xff08;加载 .class 文件到方法区/元空间、创建 Class 对象等&#xff09;。【这个过程就是加载、验…

【Web安全】CRLF注入攻击深度解析:原理、场景与安全测试防御指南

文章目录前言&#xff1a;为什么CRLF注入是安全测试不可忽视的威胁&#xff1f;1. CRLF注入核心原理&#xff1a;从字符定义到协议依赖1.1 什么是CRLF&#xff1f;1.2 CRLF在HTTP协议中的关键作用1.3 CRLF注入的本质&#xff1a;格式混淆攻击2. CRLF注入典型利用场景与安全测试…

【安全学习】DVWA 靶场 SQL 注入漏洞原理分析与防御策略(教育用途)

注意&#xff1a;本文内容仅用于合法授权的安全研究、教学演示及漏洞复现&#xff0c;严禁用于任何未授权的系统或网络环境。 所有操作需在本地沙箱或个人可控靶场中执行&#xff0c;切勿对生产环境、他人系统进行测试&#xff0c;非法使用后果自负。&#x1f4cc; 法律与道德双…