Java結構型模式---代理模式

代理模式基礎概念

代理模式是一種結構型設計模式,其核心思想是通過創建一個代理對象來控制對另一個真實對象的訪問。代理對象在客戶端和真實對象之間起到中介作用,允許在不改變真實對象的前提下,對其進行增強或控制。

代理模式的核心組件

  1. 主題接口 (Subject)?- 定義真實對象和代理對象的共同接口,客戶端通過該接口訪問真實對象
  2. 真實主題 (RealSubject)?- 實現主題接口,是實際要被代理的對象
  3. 代理 (Proxy)?- 實現主題接口,持有真實主題的引用,在調用真實主題方法前后可以添加額外邏輯

靜態代理實現

靜態代理是指在編譯時就已經確定代理類和被代理類的關系,代理類需要手動編寫。

// 主題接口
interface Image {void display();void resize();
}// 真實主題
class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadFromDisk(fileName);}@Overridepublic void display() {System.out.println("Displaying " + fileName);}@Overridepublic void resize() {System.out.println("Resizing " + fileName);}private void loadFromDisk(String fileName) {System.out.println("Loading " + fileName);}
}// 代理類
class ProxyImage implements Image {private RealImage realImage;private String fileName;public ProxyImage(String fileName) {this.fileName = fileName;}@Overridepublic void display() {// 延遲加載:在需要顯示時才創建真實對象if (realImage == null) {realImage = new RealImage(fileName);}// 可以在調用真實對象方法前后添加額外邏輯System.out.println("Before displaying");realImage.display();System.out.println("After displaying");}@Overridepublic void resize() {if (realImage == null) {realImage = new RealImage(fileName);}System.out.println("Before resizing");realImage.resize();System.out.println("After resizing");}
}// 客戶端代碼
public class StaticProxyClient {public static void main(String[] args) {Image image = new ProxyImage("test.jpg");// 第一次調用display,會加載圖片并顯示System.out.println("First call to display:");image.display();// 第二次調用display,不會重新加載圖片System.out.println("\nSecond call to display:");image.display();// 調用resize方法System.out.println("\nCall to resize:");image.resize();}
}

動態代理實現

動態代理是指在運行時通過反射機制動態生成代理類,無需手動編寫。Java 提供了java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler來實現動態代理。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 主題接口
interface UserService {void createUser(String username);void deleteUser(int userId);String getUser(int userId);
}// 真實主題
class UserServiceImpl implements UserService {@Overridepublic void createUser(String username) {System.out.println("Creating user: " + username);}@Overridepublic void deleteUser(int userId) {System.out.println("Deleting user with ID: " + userId);}@Overridepublic String getUser(int userId) {System.out.println("Getting user with ID: " + userId);return "User" + userId;}
}// 動態代理處理器
class LoggingHandler implements InvocationHandler {private final Object target; // 真實對象public LoggingHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 方法調用前的日志記錄System.out.println("Before method: " + method.getName());if (args != null) {for (int i = 0; i < args.length; i++) {System.out.println("  Arg " + (i + 1) + ": " + args[i]);}}// 調用真實對象的方法Object result = method.invoke(target, args);// 方法調用后的日志記錄System.out.println("After method: " + method.getName());return result;}
}// 客戶端代碼
public class DynamicProxyClient {public static void main(String[] args) {// 創建真實對象UserService userService = new UserServiceImpl();// 創建InvocationHandlerInvocationHandler handler = new LoggingHandler(userService);// 創建動態代理對象UserService proxyService = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),new Class<?>[]{UserService.class},handler);// 調用代理對象的方法proxyService.createUser("John Doe");System.out.println();String user = proxyService.getUser(123);System.out.println("Returned user: " + user);System.out.println();proxyService.deleteUser(123);}
}

CGLIB 代理實現

CGLIB 是一個強大的、高性能的代碼生成庫,可以在運行時擴展 Java 類與實現 Java 接口。當需要代理沒有實現接口的類時,可以使用 CGLIB 代理。

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;// 沒有實現接口的目標類
class CustomerService {public void saveCustomer(String name) {System.out.println("Saving customer: " + name);}public String getCustomer(int id) {System.out.println("Getting customer with ID: " + id);return "Customer" + id;}
}// CGLIB方法攔截器
class CustomerServiceInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method: " + method.getName());// 調用父類(即目標類)的方法Object result = proxy.invokeSuper(obj, args);System.out.println("After method: " + method.getName());return result;}
}// 客戶端代碼
public class CglibProxyClient {public static void main(String[] args) {// 創建Enhancer對象Enhancer enhancer = new Enhancer();// 設置要代理的目標類enhancer.setSuperclass(CustomerService.class);// 設置回調函數enhancer.setCallback(new CustomerServiceInterceptor());// 創建代理對象CustomerService proxy = (CustomerService) enhancer.create();// 調用代理對象的方法proxy.saveCustomer("Alice");System.out.println();String customer = proxy.getCustomer(456);System.out.println("Returned customer: " + customer);}
}

代理模式的應用場景

  1. 遠程代理?- 為一個位于不同地址空間的對象提供本地代理
  2. 虛擬代理?- 延遲創建開銷大的對象,如圖片懶加載
  3. 保護代理?- 控制對原始對象的訪問,用于權限管理
  4. 緩存代理?- 緩存對資源的訪問結果,提高性能
  5. 智能引用代理?- 在訪問對象時附加額外操作,如引用計數

靜態代理與動態代理的對比

特性靜態代理動態代理
代理類創建時間編譯時運行時
代碼復雜度高,需手動編寫每個代理類低,通過反射動態生成
可維護性低,接口修改時需同步修改代理類高,自動適配接口變化
靈活性低,只能代理特定接口或類高,可以代理任意實現接口的類
性能稍高,無需反射稍低,依賴反射調用
適用場景簡單場景,代理類數量少復雜場景,需要靈活的代理機制

代理模式的優缺點

優點

  • 降低耦合度 - 客戶端與真實對象解耦
  • 增強擴展性 - 可以在不修改真實對象的情況下增強功能
  • 控制訪問 - 可以對真實對象的訪問進行控制
  • 提高性能 - 通過緩存等機制提升性能

缺點

  • 增加系統復雜度 - 引入代理對象,可能使系統變得復雜
  • 性能開銷 - 動態代理使用反射,可能帶來性能損失
  • 調試困難 - 代理邏輯可能分散在多個地方,增加調試難度

使用代理模式的注意事項

  1. 合理選擇代理類型?- 根據需求選擇靜態代理、動態代理或 CGLIB 代理
  2. 接口設計?- 設計良好的主題接口,確保代理和真實對象行為一致
  3. 代理鏈?- 可以組合多個代理形成代理鏈,實現更復雜的功能
  4. 性能考慮?- 對于性能敏感的應用,需謹慎使用動態代理
  5. 兼容性?- CGLIB 代理不能用于 final 類或方法,因為無法被繼承

代理模式是一種非常實用的設計模式,它通過引入代理對象來控制對真實對象的訪問,提供了增強功能、控制訪問和提高性能的能力。在實際開發中,動態代理和 CGLIB 代理更為常用,它們提供了更靈活的代理機制。

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

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

相關文章

MySQL流程控制函數全解析

MySQL 中的流程控制函數&#xff08;也稱為條件函數&#xff09;允許你在 SQL 語句中進行邏輯判斷&#xff0c;根據不同的條件返回不同的值或執行不同的操作。它們極大地增強了 SQL 的靈活性和表達能力&#xff0c;尤其在進行數據轉換、結果格式化、條件聚合和復雜業務邏輯實現…

【7】PostgreSQL 事務

【7】PostgreSQL 事務前言使用事務事務內錯誤處理事務保存點DDL 事務前言 在 PostgreSQL 中&#xff0c;每一個操作都是一個事務。即使一個簡單的查詢(select)&#xff0c;這也是一個事務。 例如&#xff1a; postgres# select now();now --------------------…

Linux:多線程---深入互斥淺談同步

文章目錄1. 互斥1.1 為什么需要互斥1.2 互斥鎖1.3 初談互斥與同步1.4 鎖的原理1.5 可重入VS線程安全1.6 死鎖1.7 避免死鎖的算法&#xff08;擴展&#xff09;序&#xff1a;在上一章中我們知道了線程控制的三個角度&#xff1a;線程創建、線程等待和線程終止&#xff0c;分別從…

適用于 vue2、vue3 的自定義指定:v-int(正整數)

在項目中&#xff0c;我們經常會遇到輸入框只允許輸入數字的情況&#xff0c;下面是一段自定義指定 代碼&#xff0c;復制到項目中&#xff0c;注冊指定即可使用用法如下&#xff1a; 創建一個IntInput.js 文件&#xff0c;將下面代碼復制到文件中保存在項目中的 main.js 文件中…

學習基于springboot秒殺系統-環境配置(接口封裝,mybatis,mysql,redis(Linux))

文章目錄前言創建springboot項目封裝controller層輸入輸出rest api 的json輸出返回頁面集成mybatis集成redis下載虛擬機和centos下載redis.tar.gz上傳redis.tar.gz 到虛擬機前言 今天開始記錄學習秒殺系統-課程是基于慕課上的搜索秒殺系統的課程&#xff0c;老師講解非常好。這…

stm32達到什么程度叫精通?

STM32達到什么程度叫精通&#xff1f;一個十年老兵的深度反思 前言&#xff1a;精通二字&#xff0c;重如泰山 每次有人問我"STM32達到什么程度叫精通"這個問題&#xff0c;我都會沉默很久。 不是因為這個問題難回答&#xff0c;而是因為"精通"這兩個字太重…

微軟上線Deep Research:OpenAI同款智能體,o3+必應雙王炸

今天凌晨&#xff0c;微軟在官網宣布&#xff0c;Azure AI Foundry中上線Deep Research公開預覽版。這是支持API和SDK的OpenAI 高級智能體研究能力產品&#xff0c;并且Azure 的企業級智能體平臺完全集成。Deep Research是OpenAI在今年4月25日發布的最新產品&#xff0c;能夠像…

Spring Batch終極指南:原理、實戰與性能優化

&#x1f31f; Spring Batch終極指南&#xff1a;原理、實戰與性能優化單機日處理10億數據&#xff1f;揭秘企業級批處理架構的核心引擎&#xff01;一、Spring Batch 究竟是什么&#xff1f;Spring batch是用于創建批處理應用程序&#xff08;執行一系列作業&#xff09;的開源…

【Part 3 Unity VR眼鏡端播放器開發與優化】第四節|高分辨率VR全景視頻播放性能優化

文章目錄《VR 360全景視頻開發》專欄Part 3&#xff5c;Unity VR眼鏡端播放器開發與優化第一節&#xff5c;基于Unity的360全景視頻播放實現方案第二節&#xff5c;VR眼鏡端的開發適配與交互設計第三節&#xff5c;Unity?VR手勢交互開發與深度優化第四節&#xff5c;高分辨率V…

TCP/IP協議基礎

TCPIP協議基礎 網絡模型 -OSI參考模型 -OSI參考模型各層功能 -TCP/IP網絡模型 -TCP/IP協議棧OSI參考模型 – 為了解決網絡設備之間的兼容性問題&#xff0c;國際標準化組織ISO于1984年提出了OSI RM&#xff08;開放系統互連參考模型&#xff09;。 OSI參考模型一共有七層&#…

【Nginx】Nginx代理WebSocket

1.websocketWebSocket 是一種網絡通信協議&#xff0c;它提供了在單個 TCP 連接上進行全雙工&#xff08;雙向&#xff09;通信的能力假設需求&#xff1a;把 ws://192.168.0.1:8088/ws-api/websocket/pushData代理到ws://192.168.0.156:8888/websocket/pushData&#xff1b;同…

Spring AI Alibaba Graph使用案例人類反饋

1、Spring AI Alibaba Graph 是社區核心實現之一&#xff0c;也是整個框架在設計理念上區別于 Spring AI 只做底層原子抽象的地方&#xff0c;Spring AI Alibaba 期望幫助開發者更容易的構建智能體應用。基于 Graph 開發者可以構建工作流、多智能體應用。Spring AI Alibaba Gra…

本地部署jenkins持續集成

一、準備環境&#xff08;jdk版本跟Tomcat版本要匹配&#xff09; java jdk 環境(版本是11.0.21) jenkins war包(版本是2.440.3) Tomcat (版本是 9.0.84) 二、安裝步驟 1、安裝jdk環境 1&#xff09;先安裝java環境&#xff0c;安裝完成后配置環境變量&#xff0c;參考上…

基于Java+Maven+Testng+Selenium+Log4j+Allure+Jenkins搭建一個WebUI自動化框架(1)搭建框架基本雛形

本次框架使用Maven作為代碼構建管理&#xff0c;引用了PO模式&#xff0c;將整體的代碼分成了頁面層、用例層、業務邏輯層。框架搭建流程&#xff1a;1、在pom.xml中引入依賴&#xff1a;<!-- https://mvnrepository.com/artifact/io.appium/java-client --> <depende…

從零構建MCP服務器:FastMCP實戰指南

引言&#xff1a;MCP協議與FastMCP框架 Model Context Protocol&#xff08;MCP&#xff09;是連接AI模型與外部服務的標準化協議&#xff0c;允許LLM&#xff08;如Claude、Gemini&#xff09;調用工具、訪問數據。然而&#xff0c;直接實現MCP協議需要處理JSON-RPC、會話管理…

基于FPGA的智能小車設計(包含代碼)/ 全棧FPGA智能小車:Verilog實現藍牙/語音/多傳感器融合的移動平臺

首先先聲明一下&#xff0c;本項目已經歷多輪測試&#xff0c;可以放心根據我的設計進行二次開發和直接套用&#xff01;&#xff01;&#xff01; 代碼有詳細的注釋&#xff0c;方便同學進行學習&#xff01;&#xff01; 制作不易&#xff0c;記得三連哦&#xff0c;給我動…

Object.defineProperties 詳解

Object.defineProperties 詳解 Object.defineProperties 是 JavaScript 中用于在一個對象上定義或修改多個屬性的方法。它是 Object.defineProperty 的復數版本&#xff0c;允許你一次性定義多個屬性。 基本語法 Object.defineProperties(obj, props)obj&#xff1a;要在其上定…

MyBatis-Plus:深入探索與最佳實踐

MyBatis-Plus作為MyBatis的增強版&#xff0c;已經在Java開發中得到了廣泛應用。它不僅繼承了MyBatis的所有功能&#xff0c;還提供了許多強大的擴展功能&#xff0c;幫助開發者提升開發效率和代碼質量。本文將深入探討MyBatis-Plus的高級特性及其在實際項目中的最佳實踐。一、…

勞斯萊斯數字孿生技術:重構航空發動機運維的綠色革命

在航空工業邁向智能化的浪潮中&#xff0c;勞斯萊斯以數字孿生技術為核心&#xff0c;構建了發動機全生命周期管理的創新范式。這項技術不僅重新定義了航空發動機的維護策略&#xff0c;更通過數據驅動的決策體系&#xff0c;實現了運營效率與生態效益的雙重突破。本文將從技術…