設計模式精講 Day 12:代理模式(Proxy Pattern)

【設計模式精講 Day 12】代理模式(Proxy Pattern)


文章內容

在軟件開發中,代理模式是一種常見的結構型設計模式,它通過引入一個代理對象來控制對真實對象的訪問。這種模式不僅能夠增強系統的安全性、靈活性和可擴展性,還能在不修改原有代碼的基礎上實現功能增強。

作為“設計模式精講”系列的第12天,我們將深入探討 代理模式(Proxy Pattern) 的核心思想、實現方式、適用場景以及實際應用案例。本文面向Java開發工程師和架構師,旨在幫助讀者理解如何在項目中合理使用代理模式,并提升系統的設計質量與性能。


模式定義:代理模式的核心思想

代理模式是一種結構型設計模式,它提供了一個代理對象,用于控制對另一個對象的訪問。代理對象通常會封裝真實對象的操作,并在調用之前或之后執行額外的邏輯,如權限校驗、日志記錄、延遲加載等。

核心思想:
  • 解耦:通過代理對象隔離客戶端與真實對象之間的直接依賴。
  • 控制訪問:允許在調用真實對象之前或之后添加額外行為。
  • 增強功能:在不修改真實對象的前提下,為對象增加新的能力。

模式結構:UML類圖與關鍵角色說明

代理模式包含以下幾個關鍵角色:

角色職責
Subject抽象接口,定義了真實對象和代理對象的公共方法。
RealSubject真實對象,實現了 Subject 接口,提供實際的功能。
Proxy代理對象,也實現了 Subject 接口,負責控制對 RealSubject 的訪問。
UML類圖描述(文字版)
  • Subject 是一個抽象接口,定義了 operation() 方法。
  • RealSubject 實現了 Subject 接口,提供具體的功能實現。
  • Proxy 同樣實現了 Subject 接口,內部持有 RealSubject 的引用,并在調用 operation() 時進行額外處理。

適用場景:代理模式最適合應用的具體業務場景

場景說明
權限控制在訪問資源前驗證用戶權限,如數據庫連接、文件讀寫等。
延遲加載只有在真正需要時才初始化對象,如大文件加載、大數據查詢。
遠程調用為遠程服務提供本地代理,隱藏網絡細節,如RPC框架。
日志與監控在調用前后記錄日志,用于調試或審計。
安全防護防止非法操作,如只讀對象、只讀屬性等。

實現方式:完整的Java代碼實現(帶詳細注釋)

下面是一個基于 Java 的完整代理模式實現示例,模擬了一個簡單的圖像加載器,其中代理負責控制圖像的加載過程。

// 1. 抽象接口:Subject
interface Image {void display();
}// 2. 真實對象:RealSubject
class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadFromDisk();}private void loadFromDisk() {System.out.println("Loading image from disk: " + fileName);}@Overridepublic void display() {System.out.println("Displaying image: " + fileName);}
}// 3. 代理對象:Proxy
class ProxyImage implements Image {private String fileName;private RealImage realImage;public ProxyImage(String fileName) {this.fileName = fileName;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(fileName);}realImage.display();}
}// 4. 客戶端代碼
public class ProxyDemo {public static void main(String[] args) {Image image1 = new ProxyImage("photo1.jpg");image1.display(); // 第一次加載,觸發真實對象創建Image image2 = new ProxyImage("photo2.jpg");image2.display(); // 第二次加載,復用已有對象}
}
代碼解釋:
  • RealImage 是真正的圖像對象,只有在構造時才會加載圖像。
  • ProxyImage 是代理對象,僅在調用 display() 時才創建 RealImage 實例,實現延遲加載
  • 客戶端通過 ProxyImage 訪問圖像,無需關心其是否已加載。

工作原理:代理模式如何解決問題的底層機制

代理模式的核心在于控制訪問增強功能。當客戶端調用代理對象的方法時,代理可以執行以下操作:

  1. 預處理:在調用真實對象之前,執行一些邏輯,如權限檢查、參數驗證。
  2. 調用真實對象:根據需求決定是否創建或復用真實對象。
  3. 后處理:在調用完成后,執行一些邏輯,如日志記錄、資源釋放。

通過這種方式,代理模式能夠在不修改真實對象的前提下,為系統增加額外的行為,同時降低模塊間的耦合度。


優缺點分析:使用該模式的優勢和局限性

優點缺點
提高系統的靈活性和可擴展性增加了系統的復雜度
解耦客戶端與真實對象代理對象可能成為性能瓶頸
支持延遲加載、安全控制等功能不適合所有場景,如簡單對象無需代理

案例分析:真實項目中的代理模式應用

應用場景:Spring AOP 中的代理模式

在 Spring 框架中,AOP(面向切面編程) 就是基于代理模式實現的。Spring 使用動態代理(JDK Proxy 或 CGLIB)來為目標對象添加橫切關注點(如日志、事務管理等)。

示例代碼:
// 1. 定義一個接口
interface UserService {void login(String username, String password);
}// 2. 實現類
class UserServiceImpl implements UserService {@Overridepublic void login(String username, String password) {System.out.println("User " + username + " is logging in...");}
}// 3. 使用 Spring AOP 添加日志功能
@Aspect
@Component
public class LoggingAspect {@Before("execution(* com.example.service.UserService.login(..))")public void logBefore(JoinPoint joinPoint) {System.out.println("Logging before method call: " + joinPoint.getSignature().getName());}
}
工作原理:
  • Spring AOP 使用 JDK ProxyCGLIB 創建 UserService 的代理對象。
  • 當調用 login() 方法時,實際上調用的是代理對象。
  • 代理對象會在方法調用前后插入日志邏輯,從而實現無侵入式的功能增強。

與其他模式的關系:與相關設計模式的比較和組合使用方式

模式關系
裝飾器模式(Decorator Pattern)兩者都用于增強對象功能,但裝飾器模式強調動態添加功能,而代理模式更側重于控制訪問
適配器模式(Adapter Pattern)適配器用于兼容不同接口,而代理用于控制對對象的訪問,二者目的不同。
單例模式(Singleton Pattern)代理對象可以使用單例模式確保唯一性,尤其在遠程調用中非常常見。
工廠模式(Factory Pattern)代理對象可以通過工廠模式創建,以統一管理對象的生成過程。

總結:關鍵知識點復習與下一天內容預告

本篇詳細介紹了 代理模式 的核心思想、實現方式、適用場景以及實際應用案例。我們通過 Java 代碼展示了如何構建一個完整的代理模式系統,并結合 Spring AOP 案例說明了其在企業級應用中的價值。

通過代理模式,我們可以有效控制對象的訪問權限、實現延遲加載、增強系統功能,同時降低模塊間的耦合度。在后續的開發中,建議結合具體業務場景,靈活運用代理模式,以提升系統的可維護性和可擴展性。

下一天我們將進入行為型模式的講解,重點介紹責任鏈模式(Chain of Responsibility Pattern),敬請期待!


文章標簽

design-patterns,proxy-pattern,java-design-patterns,software-architecture,object-oriented-programming


文章簡述

本文是“設計模式精講”系列的第12天,圍繞 代理模式(Proxy Pattern) 展開,深入解析了其核心思想、實現方式、適用場景及實際應用。文章提供了完整的 Java 代碼示例,展示了如何通過代理對象控制對真實對象的訪問,并結合 Spring AOP 案例說明了其在企業級開發中的重要性。此外,文章還對比了代理模式與其他設計模式的關系,并總結了其優缺點。無論是初學者還是有經驗的 Java 開發者,都能從中獲得實用的技術指導和設計思路。


進一步學習資料

  1. Design Patterns: Elements of Reusable Object-Oriented Software
  2. Refactoring Guru - Proxy Pattern
  3. Java Design Patterns - Proxy Pattern
  4. Spring AOP with Proxy Pattern

核心設計思想總結

本篇文章的核心設計思想是:通過代理對象控制對真實對象的訪問,增強系統功能并降低耦合度。在實際項目中,當我們需要實現權限控制、延遲加載、遠程調用等功能時,可以考慮使用代理模式。通過合理設計代理類,可以在不修改原有代碼的前提下,為系統增加新的能力。在后續開發中,建議結合具體業務場景,靈活運用代理模式,以提升系統的可維護性和可擴展性。

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

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

相關文章

企業級知識庫私有化部署:騰訊混元+云容器服務TKE實戰

1. 背景需求分析 在金融、醫療等數據敏感行業,企業需要構建完全自主可控的知識庫系統。本文以某證券機構智能投研系統為原型,演示如何基于騰訊混元大模型與TKE容器服務實現: 千億級參數模型的私有化部署金融領域垂直場景微調高并發低延遲推…

Qt事件系統詳解

一、Qt事件系統概述 Qt事件系統是Qt框架中處理用戶輸入、窗口交互、定時器、異步操作等機制的核心。所有事件均繼承自QEvent類,并通過事件循環(Event Loop)分發到目標對象。 事件系統基本概念 事件(Event):描述應用程序內部或外…

CPU性能篇-系統中出現大量不可中斷進程和僵尸進程怎么辦? Day 05

在上下文切換的文章中,學習并分析了系統 CPU 使用率高的問題,剩下的等待 I/O 的 CPU 使用率(以下簡稱為 iowait)升高,也是最常見的一個服務器性能問題。今天就來看一個多進程 I/O 的案例,并分析這種情況。 …

ASP.NET Core + Jenkins 實現自動化發布

一、安裝Jenkins 我這邊服務器是Linux CentOS 7 ,使用SSH 登錄云服務器后,輸入以下命令安裝jenkins. sudo wget -O /etc/yum.repos.d/jenkins.repo \https://pkg.jenkins.io/redhat-stable/jenkins.repo sudo rpm --import https://pkg.jenkins.io/red…

Java項目RestfulAPI設計最佳實踐

大家好,我是鋒哥。今天分享關于【Java項目RestfulAPI設計最佳實踐】面試題。希望對大家有幫助; Java項目RestfulAPI設計最佳實踐 超硬核AI學習資料,現在永久免費了! 設計一個高效、易維護的 Java 項目中的 RESTful API 涉及到一…

FANUC機器人教程:用戶坐標系標定及其使用方法

目錄 概述 工作站創建 任務描述 用戶坐標系標定方法 用戶坐標系標定操作 用戶坐標系手動測試 用戶坐標系在程序中的應用 用戶坐標系選擇指令介紹 機器人示教編程 仿真運行 仿真案例資源下載 概述 FANUC機器人的用戶坐標系,是用戶對每個作業空間定義的直…

動態庫與靜態庫【Linux】

程序編譯過程 源代碼(.cpp) → 預處理(.i) → 編譯(.s) → 匯編(.o) → 鏈接(可執行文件) g -o main.i -E main.cpp 參數說明: 參數功能輸出文件類型-E僅預處理.i-S預處理 編譯.s-c預處理 編譯 匯編.o無完整流程(預處理→編譯→匯編→鏈接&…

MySQL MHA 故障轉移-VIP

MHA故障轉移-VIP #手工在主庫添加VIP ifconfig ens33:1 192.168.80.200/24配置VIP腳本 vim /usr/local/bin/master_ip_failoverchmod x /usr/local/bin/#!/usr/bin/env perl use strict; use warnings FATAL > all;use Getopt::Long;my ( $command, $ssh_user, $orig_mast…

Elasticsearch索引字段的類型

在 Elasticsearch 中,索引字段的類型(即 Mapping 中的字段類型)對搜索和存儲性能影響很大。下面是各種常用數據類型的用途及推薦使用場景總結: 1. keyword 類型(精確匹配) 適合數據: 不需要分詞…

kubernetes證書續簽-使用kubeadm更新證書(下)

#作者:任少近 文章目錄 查看kubelet證書查看kubelet當前所使用的證書 更換 node上的kubelet證書生成node1所需要的kubelet.conf文件生成node2所需要的kubelet.conf文件查看csr 更新 ~/.kube/config 文件重啟相關組件 查看kubelet證書 以上少了kubelet的證書&#…

AI智能體長期記憶系統架構設計:從認知模型到生產實踐

1 長期記憶:AI智能體的認知基石 1.1 人類記憶與AI記憶的類比 #mermaid-svg-VIPKAFe7VgN4UHFA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-VIPKAFe7VgN4UHFA .error-icon{fill:#552222;}#mermaid-svg-VIPKAFe7V…

快速上手:利用音頻大模型與Java提取視頻文案

文章目錄 1、前言2、需求說明2.1 需求說明2.2 數據準備 3、功能實現3.1 使用視頻理解大模型能力3.1.1 三方平臺視頻在線鏈接解析3.1.2 三方平臺視頻內網鏈接解析3.1.3 三方平臺視頻轉存本地服務 3.2 使用音頻識別大模型能力3.2.1 三方平臺視頻在線鏈接解析3.2.2 三方平臺視頻詳…

LLM復雜記憶存儲-多會話隔離案例實戰

導讀:在多用戶并發的對話系統中,會話隔離問題往往成為開發者面臨的技術難題。當數千個用戶同時與AI助手交互時,如何確保每個用戶的對話歷史完全獨立,避免數據混淆和隱私泄露? 本文深入剖析了基于RunnableWithMessageHi…

【PX4-AutoPilot教程-TIPS】PX4系統命令行控制臺ConsolesShells常用命令(持續更新)

PX4系統命令行控制臺 Consoles & Shells 常用命令 查看每個應用程序的堆棧使用情況獲取所有可用命令和APP的列表應用程序啟動、停止和狀態查詢查看本地文件系統查看剩余的可用RAM查看工作隊列中正在運行的內容以及運行速率查看特定的uORB話題調試uORB話題進行模式切換和故障…

國內優秀wordpress主題推薦

在國內,WordPress 主題市場雖然不如國外那樣龐大,但依然有許多優秀且適合中國用戶需求的主題。以下是一些經過評估和推薦的國內優秀WordPress主題,涵蓋不同類型的網站需求,如博客、企業官網、資源站、社區論壇等。 WP漢主題 WP漢…

第 6 章:進階話題

第 6 章:進階話題 過擬合vs欠擬合:模型復雜度和泛化能力的關系 在前面的章節中,我們已經學習了神經網絡的基礎知識、常見架構和基本訓練流程。然而,在實際的深度學習項目中,僅僅掌握這些基礎知識是不夠的。我們還需要…

4.2_1樸素模式匹配算法

知識總覽: 什么是字符串的模式匹配: 主串:想從該串獲取結果的串 模式串:想搜索的內容,不一定在主串中能搜到,子串一定能在主串中搜到 字符串模式匹配:在主串找模式串并返回找到的第一個模式串…

華為云Flexus+DeepSeek征文|華為云ModelArts搭建Dify-LLM應用開發平臺(AI智能選股大模型)

前言 在當今數字化時代,人工智能(AI)技術在金融領域的應用愈發廣泛,其中 AI 智能選股大模型備受關注。為了構建高效且精準的 AI 智能選股大模型,選擇合適的開發平臺和工具至關重要。華為云 ModelArts 作為一款面向 AI …

C4.5算法深度解析:決策樹進化的里程碑

C4.5是機器學習史上最經典的算法之一,由ID3之父Ross Quinlan在1993年提出。作為ID3的革命性升級,它不僅解決了前代的核心缺陷,更開創了連續特征處理和剪枝技術的先河,成為現代決策樹的奠基之作。 本文由「大千AI助手」原創發布&am…

leetcode 65

#include <string> #include <vector> #include <unordered_map> using namespace std;class Solution { public:bool isNumber(string s) {// 定義狀態轉移表vector<unordered_map<char, int>> states {{{ , 0}, {s, 1}, {d, 2}, {., 4}}, // …