设计模式精讲 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.tpcf.cn/pingmian/86314.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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}}, // …