設計模式:代理模式(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
英文地址,請注明出處:http://en.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; 法律與道德雙…