23種設計模式——代理模式(Proxy Pattern)詳解

?作者簡介:大家好,我是 Meteors., 向往著更加簡潔高效的代碼寫法與編程方式,持續分享Java技術內容。
🍎個人主頁:Meteors.的博客
💞當前專欄:設計模式
?特色專欄:知識分享
🥭本文內容:23種設計模式——代理模式(Proxy Pattern)
📚 ** ps **? :閱讀文章如果有問題或者疑惑,歡迎在評論區提問或指出。


目錄

一. 背景

二. 介紹

三. 核心概念

四. 實際應用示例

1. 圖片加載代理

2. 權限控制代理

3. 網絡請求代理

4. 緩存代理

五.?代理模式的類型

六. 代理模式的優勢

七. 注意事項

八. 總結


一. 背景

也行此時你還感覺不到代理模式是多么的好用,我慢慢幫你剖析吧!

不知道讀者對于Java的Spring AOP(方法粒度的面向切面編程)是否了解?其實代理模式可以類比成一種對象粒度的AOP。在我們在項目中創建一個對象的時候,如果還要添加類似于日志、判斷前置條件(如android中的用戶是否允許某種權限)、或者進行緩存判斷(類似Redis)的操作,如果這個時候如果都把代碼寫成一團,功能肯定也可以實現,但是代碼會顯得非常冗余,這個時候代理模式的優勢就體現出來了,讓我們一起來揭開它的面紗!


二. 介紹

代理模式(Proxy Pattern)是面向對象設計模式中的一種結構型模式。它為其他對象提供一種代理以控制對這個對象的訪問。代理模式在客戶端和目標對象之間起到中介作用,可以在不改變目標對象的情況下,增加額外的功能操作(知道是結構型和可以添加功能就夠了~)。


三. 核心概念

在代理模式中,通常涉及三個角色:
抽象主題(Subject):聲明了真實主題和代理主題的共同接口方法功能提到接口
真實主題(RealSubject):定義了代理主題所代表的真實對象原本要New的對象
代理主題(Proxy):保存一個引用使得代理可以訪問實體,并提供一個與Subject的接口相同的接口完成延遲加載和添加日志等功能,后面使用對象的時候只要創建這個對象就夠了


四. 實際應用示例

1. 圖片加載代理

在Android應用中,我們經常需要加載網絡圖片。為了提高性能,可以使用代理模式來實現圖片的延遲加載:

// 抽象接口
public interface Image {void display();
}// 真實主題 - 真實圖片
public class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadFromDisk();}private void loadFromDisk() {System.out.println("從磁盤加載圖片: " + filename);// 模擬耗時操作try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void display() {System.out.println("顯示圖片: " + filename);}
}// 代理主題 - 圖片代理
public class ImageProxy implements Image {private RealImage realImage;private String filename;public ImageProxy(String filename) {this.filename = filename;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(filename);}realImage.display();}
}// 使用示例
public class MainActivity {public void onCreate() {// 創建代理對象,不會立即加載圖片Image image = new ImageProxy("photo.jpg");// 只有在需要顯示時才真正加載圖片image.display(); // 此時才加載并顯示圖片}
}

這種方式可以有效減少內存使用,只有在真正需要顯示圖片時才加載,提高了應用性能。

2. 權限控制代理

在Android應用中,某些功能需要特定權限才能訪問,可以使用代理模式進行權限檢查:

// 抽象接口
public interface Camera {void takePhoto();void recordVideo();
}// 真實主題 - 相機功能實現
public class RealCamera implements Camera {@Overridepublic void takePhoto() {System.out.println("拍照成功");}@Overridepublic void recordVideo() {System.out.println("開始錄像");}
}// 代理主題 - 帶權限檢查的相機代理
public class CameraPermissionProxy implements Camera {private RealCamera realCamera;private Context context;public CameraPermissionProxy(Context context) {this.context = context;}@Overridepublic void takePhoto() {if (checkCameraPermission()) {if (realCamera == null) {realCamera = new RealCamera();}realCamera.takePhoto();} else {System.out.println("沒有相機權限,無法拍照");}}@Overridepublic void recordVideo() {if (checkCameraPermission()) {if (realCamera == null) {realCamera = new RealCamera();}realCamera.recordVideo();} else {System.out.println("沒有相機權限,無法錄像");}}private boolean checkCameraPermission() {// 檢查相機權限return ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;}
}// 使用示例
public class CameraActivity {private Camera camera;public void onCreate() {camera = new CameraPermissionProxy(this);}public void onTakePhotoClick() {camera.takePhoto(); // 自動檢查權限}
}

3. 網絡請求代理

在網絡請求中,可以使用代理模式添加日志、緩存等功能:

// 抽象接口
public interface HttpClient {String get(String url);String post(String url, String data);
}// 真實主題 - 真實的HTTP客戶端
public class RealHttpClient implements HttpClient {@Overridepublic String get(String url) {// 模擬網絡請求System.out.println("發送GET請求到: " + url);return "Response from " + url;}@Overridepublic String post(String url, String data) {System.out.println("發送POST請求到: " + url + " 數據: " + data);return "Response from " + url;}
}// 代理主題 - 帶日志功能的HTTP客戶端代理
public class LoggingHttpClientProxy implements HttpClient {private RealHttpClient realHttpClient;private boolean enableLogging;public LoggingHttpClientProxy(boolean enableLogging) {this.enableLogging = enableLogging;}@Overridepublic String get(String url) {long startTime = System.currentTimeMillis();if (realHttpClient == null) {realHttpClient = new RealHttpClient();}if (enableLogging) {System.out.println("開始GET請求: " + url);}String result = realHttpClient.get(url);if (enableLogging) {long endTime = System.currentTimeMillis();System.out.println("GET請求完成,耗時: " + (endTime - startTime) + "ms");}return result;}@Overridepublic String post(String url, String data) {long startTime = System.currentTimeMillis();if (realHttpClient == null) {realHttpClient = new RealHttpClient();}if (enableLogging) {System.out.println("開始POST請求: " + url);}String result = realHttpClient.post(url, data);if (enableLogging) {long endTime = System.currentTimeMillis();System.out.println("POST請求完成,耗時: " + (endTime - startTime) + "ms");}return result;}
}// 使用示例
public class NetworkManager {private HttpClient httpClient;public NetworkManager() {// 開發環境啟用日志boolean isDebug = true;httpClient = new LoggingHttpClientProxy(isDebug);}public void fetchData() {String result = httpClient.get("https://api.example.com/data");System.out.println("獲取到數據: " + result);}
}

4. 緩存代理

在數據訪問中,代理模式可以用來實現緩存機制:

// 抽象接口
public interface DataService {String getData(String key);
}// 真實主題 - 真實的數據服務
public class RealDataService implements DataService {@Overridepublic String getData(String key) {// 模擬從數據庫或網絡獲取數據System.out.println("從數據庫獲取數據,鍵: " + key);try {Thread.sleep(1000); // 模擬耗時操作} catch (InterruptedException e) {e.printStackTrace();}return "Data for " + key;}
}// 代理主題 - 帶緩存功能的數據服務代理
public class CachedDataServiceProxy implements DataService {private RealDataService realDataService;private Map<String, String> cache = new HashMap<>();@Overridepublic String getData(String key) {// 先檢查緩存if (cache.containsKey(key)) {System.out.println("從緩存獲取數據,鍵: " + key);return cache.get(key);}// 緩存未命中,從真實服務獲取if (realDataService == null) {realDataService = new RealDataService();}String data = realDataService.getData(key);cache.put(key, data); // 存入緩存System.out.println("數據已緩存,鍵: " + key);return data;}public void clearCache() {cache.clear();System.out.println("緩存已清空");}
}// 使用示例
public class DataRepository {private DataService dataService = new CachedDataServiceProxy();public void displayData(String key) {// 第一次調用String data1 = dataService.getData(key);System.out.println("第一次獲取: " + data1);// 第二次調用(從緩存獲取)String data2 = dataService.getData(key);System.out.println("第二次獲取: " + data2);}
}

五.?代理模式的類型

代理模式還可以根據作用,分為下面幾種類型:

遠程代理(Remote Proxy):為一個位于不同地址空間的對象提供本地代表。

虛擬代理(Virtual Proxy):根據需要創建開銷很大的對象。

保護代理(Protection Proxy):控制對原始對象的訪問,常用于對象應該有不同的訪問權限時。

智能引用(Smart Reference):取代簡單的指針,在訪問對象時執行一些附加操作。


六. 代理模式的優勢

延遲加載:虛擬代理可以實現對象的延遲初始化,節省系統資源
權限控制:保護代理可以在訪問真實對象前進行權限檢查
功能增強:可以在不修改原始類的情況下添加額外功能(如日志、緩存等)
遠程訪問:遠程代理可以隱藏網絡通信的復雜性
對象訪問控制:可以控制對昂貴資源的訪問


七. 注意事項

性能開銷:代理模式會增加系統的復雜性和可能的性能開銷
代碼復雜性:引入代理會增加類的數量,使系統更加復雜
調試困難:代理模式可能使調試變得更加困難
合理使用:不是所有場景都需要代理,應根據實際需求選擇


八. 總結

代理模式是開發中非常實用的設計模式,它可以在不改變原有代碼結構的情況下,為對象提供額外的功能。通過合理使用代理模式,我們可以實現延遲加載、權限控制、日志記錄、緩存等功能,提高應用的性能和用戶體驗。
在實際開發中,我們可以根據具體需求選擇合適的代理類型,如虛擬代理用于延遲加載,保護代理用于權限控制,智能引用代理用于添加額外功能等。正確使用代理模式可以讓我們的代碼更加優雅、高效和易于維護!


最后,

? ? ? ? 其它設計模式會陸續更新,希望文章對你有所幫助!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/98326.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/98326.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/98326.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

webpack scope hositing 和tree shaking

Scope Hoisting&#xff08;作用域提升&#xff09; 和 Tree Shaking&#xff08;搖樹優化&#xff09; 是現代前端構建中至關重要的概念。它們是構建工具&#xff08;如 Webpack、Rollup、Vite&#xff09;用來優化最終打包產物的核心技術。 核心概念快速理解 Tree Shaking&am…

手寫React狀態hook

在日常開發中&#xff0c;我們經常用到 React 的狀態管理 Hook&#xff1a;useState 和 useReducer。 但你有沒有想過&#xff1a;這些 Hook 內部是怎么實現的&#xff1f;為什么調用 setState 之后組件會重新渲染&#xff1f; 今天我們就來從零手寫 useState 和 useReducer&am…

力扣hot100:相交鏈表與反轉鏈表詳細思路講解(160,206)

問題描述核心思路&#xff1a;雙指針交替遍歷算法思想&#xff1a; 使用兩個指針 pa 和 pb 分別從鏈表A和鏈表B的頭節點出發&#xff0c;同步向后遍歷。當任一指針走到鏈表末尾時&#xff0c;將其重定位到另一鏈表的頭節點繼續遍歷。若兩鏈表相交&#xff0c;pa 和 pb 最終會在…

跨平臺游戲引擎 Axmol-2.8.1 發布

所有使用 axmol-2.8.0 的開發者都應更新至此版本 Axmol 2.8.1 版本是一個以錯誤修復和功能改進為主的次要 LTS 長期支持版本&#xff0c;發布時間: 2025 年 9 月 5 日 &#x1f64f;感謝所有對 axmol 項目的貢獻者&#xff0c;包括財務贊助者&#xff1a;scorewarrior、peter…

通過PXE的方式實現Ubuntu 24.04 自動安裝

PXE自動化安裝Ubuntu 24.04的配置文件之前都是通過PXE來自動化安裝Redhat系列的&#xff0c;例如&#xff1a;Rocky9、Rocky10、CentOS7、銀河麒麟 Kylin-V10、Kylin-V11、OpenEuler 24.03等。現在安裝Ubuntu系列的跟紅帽的不太一樣&#xff0c;所以在這里介紹下。創建三個文件…

AOSP Framework開發的一些超方便的快捷命令

在系統源碼中發現的一些命令和快捷方式。我們在編譯源碼之前執行的source build/envsetup.sh,通過cat build/envsetup.sh發現如下命令 - lunch: lunch <product_name>-<build_variant>Selects <product_name> as the product to build, and <build_…

【Protues仿真】基于AT89C52單片機的數碼管驅動事例

目錄 0案例視頻效果展示 1 AT89C52單片機驅動單個數碼管 1.1 數碼管基礎知識 1.1.1外觀與引腳 1.1.2 共陰(CC) vs 共陽(CA) 1.1.3段碼表(以數字1為例) 1.1.4驅動方式A. 直連IO(最簡單,占用IO多)一個段一根線,共陰或共陽公共端固定接GND/VCC。適合單個數碼管、…

01-Redis 發展簡史與核心定位解析:從誕生到三大產品矩陣

目錄引言一、Redis 的起源與發展&#xff1a;從定制工具到開源生態二、Redis 的核心定位&#xff1a;不止是緩存的多面手三、Redis 三大產品矩陣&#xff1a;按需選擇的完整解決方案3.1 Redis Open Source&#xff08;社區版&#xff09;&#xff1a;入門與輕量場景首選3.2 Red…

記錄jilu~

centos1、安裝最小版Linux 安裝必要工具yum -install -y epel-releaseyum -install -y net-toolsyum -install -y vim2、修改hostname hostnamectl net-hostname newhostname3、網絡配置文件&#xff0c;網關 &#xff0c; 使用ip &#xff0c;dns。。/etc/sysconfig/network-s…

【Linux基礎】fdisk命令詳解:從入門到精通的磁盤分區管理完全指南

目錄 前言 1 fdisk命令概述 1.1 什么是fdisk 1.2 fdisk的應用場景 1.3 fdisk與其他分區工具的比較 2 fdisk命令的安裝與基本語法 2.1 在不同Linux發行版中安裝fdisk 2.2 fdisk的基本語法 3 fdisk命令參數詳解 3.1 主要參數說明 3.2 交互式命令 4 fdisk操作流程詳解…

Flowable 工作流引擎

1、核心類 Flowable 引擎通過 ProcessEngine 作為總入口點&#xff0c;提供了多個核心服務接口&#xff0c;每個服務都負責特定的功能領域&#xff1a;服務名稱 (Service Name)主要功能 (Main Functionality)關鍵操作 (Key Operations)RepositoryService管理流程定義和部署&…

(RDFS)隨機深度特征選擇方法解釋:簡而言之,RDFS主要針對的是惡意的服務器,它建立在客戶端是誠實的前提下。

1. 隨機深度特征選擇是怎么實現的&#xff1f;隨機深度特征選擇 是一種在分布式機器學習&#xff08;特別是聯邦學習&#xff09;中用于保護客戶端數據隱私的技術。它的核心思想是&#xff1a;在每一輪訓練中&#xff0c;每個客戶端隨機選擇模型的一個子集&#xff08;即“深度…

C++20格式化字符串:std::format的使用與實踐

在C編程中&#xff0c;字符串格式化是一項常見的任務。在C20引入std::format之前&#xff0c;開發者通常依賴于一些傳統的解決方案&#xff0c;如printf系列函數、sstream&#xff0c;或者第三方庫如boost.format。然而&#xff0c;這些方法在代碼可讀性、類型安全性和靈活性方…

【漏洞復現】CVE-2025-8088|WinRAR 路徑穿越漏洞:從原理到藍屏攻擊全流程

【漏洞復現】CVE-2025-8088&#xff5c;WinRAR 路徑穿越漏洞&#xff1a;從原理到藍屏攻擊全流程 前言 WinRAR 作為 Windows 平臺最常用的壓縮管理工具之一&#xff0c;幾乎是每臺電腦的 “標配軟件”。但在 2025 年 8 月&#xff0c;一款影響范圍覆蓋 WinRAR 0 至 7.12 全版本…

uniapp中使用echarts并且支持pc端的拖動、拖拽和其他交互事件

npm install echarts -D ? // "echarts": "^5.3.2", [推薦版本] // "zrender": "^5.3.2" [如果報錯的話就安裝這個]<template><view class"container"><view id"myChart" class"chart"…

Qt中QProxyStyledrawControl函數4個參數的意義

Qt中QProxyStyle::drawControl函數4個參數的意義 我們來詳細解釋一下 Qt 中 QProxyStyle::drawControl 函數的四個參數。 這個函數是 Qt 樣式系統中的一個核心方法&#xff0c;用于繪制標準 UI 元素&#xff08;如按鈕、復選框、菜單欄等&#xff09;。當你繼承 QProxyStyle 并…

idf-esp32 PWM呼吸燈(LEDC頭文件)

相關宏和變量#define LED_PIN GPIO_NUM_3 #define LEDC_CHANNEL LEDC_CHANNEL_0 #define LEDC_TIMER LEDC_TIMER_0 #define LEDC_MODE LEDC_LOW_SPEED_MODE #define LEDC_DUTY_RES LEDC_TIMER_13_BIT // 2^13 8192級亮度 #define LEDC_FREQUENCY 50…

PLC_博圖系列?基本指令”S_ODTS:分配保持型接通延時定時器參數并啟動“

PLC_博圖系列?基本指令”S_ODTS&#xff1a;分配保持型接通延時定時器參數并啟動“ 文章目錄PLC_博圖系列?基本指令”S_ODTS&#xff1a;分配保持型接通延時定時器參數并啟動“背景介紹S_ODTS&#xff1a; 分配保持型接通延時定時器參數并啟動說明參數脈沖時序圖示例關鍵字&a…

OneCode 可視化揭秘系列(三):AI MCP驅動的智能工作流邏輯編排

OneCode 可視化揭秘系列&#xff08;三&#xff09;&#xff1a;AI MCP驅動的智能工作流邏輯編排 引言 在前兩篇系列博文中&#xff0c;我們詳細探討了OneCode可視化動作的基礎配置與界面設計&#xff0c;以及組件交互與數據流管理。在本篇文章中&#xff0c;我們將深入剖析邏輯…

TypeORM、Sequelize、Hibernate 的優缺點對比:新手常見 SQL 與 ORM 踩坑總結

1. ORM 與關系型數據庫&#xff08;MySQL、PostgreSQL&#xff09; 的使用 SQL 語句編寫&#xff08;JOIN、GROUP BY、索引使用、事務控制&#xff09;與 ORM 映射&#xff08;如 Sequelize、TypeORM、Hibernate&#xff09;之間的差異會讓新手非常糾結&#xff1b;尤其是理解…