代理模式 (Proxy Pattern)

文章目录

      • 代理模式 (Proxy Pattern)
      • 原理
      • 分类
      • 优点
      • 缺点
      • 示例代码
        • 静态代理
          • 1. 定义接口
          • 2. 创建真实类
          • 3. 创建代理类
          • 4. 客户端代码
          • 输出结果
        • 动态代理(基于 JDK)
          • 1. 定义接口和真实类
          • 2. 创建动态代理类
          • 3. 客户端代码
          • 输出结果
      • UML 类图
        • 静态代理
        • 动态代理
      • 使用场景
      • 小结

代理模式 (Proxy Pattern)

代理模式是一种 结构型设计模式,它为某个对象提供一个替代或占位符,用来控制对这个对象的访问。通过代理对象,可以在实际对象的前后加入额外的功能(如权限校验、日志记录等)。


原理

  1. 核心思想
    • 使用一个代理类代表实际对象,客户端通过代理类间接访问实际对象。
  2. 适用场景
    • 控制对实际对象的访问(如权限验证)。
    • 增强功能(如日志记录、延迟加载)。
    • 远程代理、虚拟代理等场景。
  3. 参与角色
    • Subject(抽象主题类):定义真实对象和代理对象的公共接口。
    • RealSubject(真实主题类):实现抽象主题,表示被代理的真实对象。
    • Proxy(代理类):实现抽象主题,内部持有真实主题的引用,用来控制访问和增强功能。

分类

  1. 静态代理:代理类在编译时生成,开发者需要手动编写代理类。
  2. 动态代理:代理类在运行时动态生成,无需手动编写。
    • 基于 JDK 的动态代理(必须实现接口)。
    • 基于 CGLIB 的动态代理(无需接口)。

优点

  1. 控制访问:可以对访问真实对象进行约束。
  2. 功能扩展:通过代理类,在真实对象前后加入增强功能。

缺点

  1. 增加复杂性:引入代理类后,代码复杂度增加。
  2. 性能开销:动态代理会带来一定的性能消耗。

示例代码

静态代理

场景:一个 Payment 接口,有具体的支付实现。通过代理类对支付操作进行日志记录。


1. 定义接口
// 抽象主题
public interface Payment {
    void pay(int amount);
}

2. 创建真实类
// 真实主题类
public class RealPayment implements Payment {
    @Override
    public void pay(int amount) {
        System.out.println("Processing payment of $" + amount);
    }
}

3. 创建代理类
// 代理类
public class PaymentProxy implements Payment {
    private RealPayment realPayment;

    public PaymentProxy(RealPayment realPayment) {
        this.realPayment = realPayment;
    }

    @Override
    public void pay(int amount) {
        System.out.println("Logging: Initiating payment...");
        realPayment.pay(amount); // 调用真实对象的方法
        System.out.println("Logging: Payment completed.");
    }
}

4. 客户端代码
public class StaticProxyExample {
    public static void main(String[] args) {
        RealPayment realPayment = new RealPayment(); // 创建真实对象
        Payment proxy = new PaymentProxy(realPayment); // 创建代理对象

        proxy.pay(100); // 使用代理对象
    }
}

输出结果
Logging: Initiating payment...
Processing payment of $100
Logging: Payment completed.

动态代理(基于 JDK)

场景:通过动态代理实现相同的功能,无需手动编写代理类。


1. 定义接口和真实类
// 抽象主题
public interface Payment {
    void pay(int amount);
}

// 真实主题类
public class RealPayment implements Payment {
    @Override
    public void pay(int amount) {
        System.out.println("Processing payment of $" + amount);
    }
}

2. 创建动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 动态代理类
public class DynamicProxyHandler implements InvocationHandler {
    private Object realObject;

    public DynamicProxyHandler(Object realObject) {
        this.realObject = realObject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Logging: Before method call...");
        Object result = method.invoke(realObject, args); // 调用真实对象的方法
        System.out.println("Logging: After method call...");
        return result;
    }

    // 获取代理实例
    public static Object getProxyInstance(Object realObject) {
        return Proxy.newProxyInstance(
                realObject.getClass().getClassLoader(),
                realObject.getClass().getInterfaces(),
                new DynamicProxyHandler(realObject)
        );
    }
}

3. 客户端代码
public class DynamicProxyExample {
    public static void main(String[] args) {
        RealPayment realPayment = new RealPayment(); // 创建真实对象
        Payment proxy = (Payment) DynamicProxyHandler.getProxyInstance(realPayment); // 获取代理实例

        proxy.pay(200); // 使用代理对象
    }
}

输出结果
Logging: Before method call...
Processing payment of $200
Logging: After method call...

UML 类图

静态代理
    +------------+       +-------------+
    |  Payment   |<------+ RealPayment |
    +------------+       +-------------+
         ^                     ^
         |                     |
    +-------------------------------+
    |         PaymentProxy          |
    +-------------------------------+
动态代理
    +------------+       +-------------+
    |  Payment   |<------+ RealPayment |
    +------------+       +-------------+
         ^
         |
    +-------------+
    | Proxy       |
    +-------------+

使用场景

  1. 远程代理:为远程对象提供本地代理(如 RMI)。
  2. 虚拟代理:延迟加载资源,按需加载实际对象。
  3. 保护代理:对访问进行权限控制。
  4. 日志、性能监控:在方法调用前后增加日志或监控逻辑。

小结

  • 静态代理:需要手动编写代理类,适用于代理逻辑较少且稳定的场景。
  • 动态代理:无需手动编写代理类,灵活性强,适用于接口较多或逻辑频繁变化的场景。
  • 代理模式解耦了客户端与实际对象,增强了系统的灵活性和扩展性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924241.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue实现滚动条滑动到底部分页调取后端接口加载数据

一、案例效果 二、前提条件 接口返回数据 三、案例代码 子组件 const $emit defineEmits([cloneItem, updateList]);const props defineProps({rightList: {type: Array,},chartTableData: {type: Array as () > ChartListType[],},deleteChartInfo: {type: Object,}…

redis 底层数据结构

概述 Redis 6 和 Redis 7 之间对比&#xff1a; Redis6 和 Redis7 最大的区别就在于 Redis7 已经用 listpack 替代了 ziplist. 以下是基于 Redis 7基础分析。 RedisObject Redis是⼀个<k,v>型的数据库&#xff0c;其中key通常都是string类型的字符串对象&#xff0c;⽽…

arm rk3588 onnx转rknn

一、环境部署&#xff1a; https://github.com/airockchip/rknn_model_zoo/tree/main/examples/yolo11 从该网址下载yolo11的模型。支持80种类型检测 二、下载模型 进入examples/yolo11/model文件夹&#xff0c;执行 ./download_model.sh 如图&#xff1a; 三、模型转换…

Flutter 3.24.5安装配置——2024年11月26日

目录 1️⃣前置安装使用环境配置步骤安装Flutter SDK安装Android SDK修改文件默认安装位置&#xff08;.gradle, AVD&#xff09;开始项目 2️⃣执行结果&#x1fab2;Bug找不到**.jar文件 &#x1f517;参考链接 1️⃣前置安装 使用环境 Windows 11IDEA 2024.2.3Flutter 3.2…

Pytest-Bdd-Playwright 系列教程(13):钩子(hooks)

Pytest-Bdd-Playwright 系列教程&#xff08;13&#xff09;&#xff1a;钩子&#xff08;hooks&#xff09; 前言一、什么是钩子&#xff1f;二、Pytest-Bdd 提供的钩子一览三、钩子用法详解1. pytest_bdd_before_scenario2. pytest_bdd_after_scenario3. pytest_bdd_before_s…

23种设计模式-生成器(Builder)设计模式

文章目录 一.什么是生成器设计模式&#xff1f;二.生成器模式的特点三.生成器模式的结构四.生成器模式的优缺点五.生成器模式的 C 实现六.生成器模式的 Java 实现七.代码解析八. 总结 类图&#xff1a; 生成器设计模式类图 一.什么是生成器设计模式&#xff1f; 生成器模式&am…

HCIP——堆叠技术实验配置

目录 一、堆叠的理论知识 二、堆叠技术实验配置 三、总结 一、堆叠的理论知识 1.1堆叠概述&#xff1a; 是指将两台交换机通过堆叠线缆连接在一起&#xff0c;从逻辑上变成一台交换设备&#xff0c;作为一个整体参与数据的转发。 1.2堆叠的基本概念 堆叠系统中所有的单台…

Python - 函数(四)

函数&#xff1a;在编写程序的过程中&#xff0c;有某一功能代码块出现多次&#xff0c; 但是为了提高编写的效率以及代码的重用&#xff0c;所以把具有独立功能的代码块组织为一个小模块&#xff0c;这就是函数 ‌Python中的函数‌是一组被命名的可执行代码&#xff0c;用于完…

豆包MarsCode算法题:三数之和问题

问题描述 思路分析 1. 排序数组 目的: 将数组 arr 按升序排序&#xff0c;这样可以方便地使用双指针找到满足条件的三元组&#xff0c;同时避免重复的三元组被重复计算。优势: 数组有序后&#xff0c;处理两个数和 target - arr[i] 的问题可以通过双指针快速找到所有可能的组…

使用guzzlehttp异步多进程实现爬虫业务

Python和PHP核心技术共享平台 背景 小哥近来在通过动态代理池爬取一些公司需要的大文件pdf规格书的处理。遇到的难点&#xff0c;如何保证服务器CPU、连接数等正常情况下&#xff0c;多进程、异步快速处理这些业务并且保证准确。下面小哥就给看官唠嗑一下&#xff0c;我使用gu…

Chrome和edge浏览器如何为任何网站强制暗模式

前言 因为我的编辑器是黑色&#xff0c;可能是看的时间长了比较喜欢这种颜色了&#xff0c;感觉白色有些刺眼。尤其是看文章时&#xff0c;两边的空白纯白色&#xff0c;所以强迫症搜素设置了谷歌浏览器和edge如何设置成黑色。 Chrome和edge浏览器如何为任何网站强制暗模式 前…

STM32-- keil使用 -设备选择

keil-arm 在project--》manager--》pack installer&#xff0c;更新芯片包&#xff0c; 有些这里不全面&#xff0c;可以在官网下载包进行安装。 比如stm8系列在这里是没有的&#xff0c;因为他的内核是哈弗架构。还有51单片机要在keil c51里面找 keil5中找不到或没有对应的…

K8s内存溢出问题剖析:排查与解决方案

文章目录 一、背景二、排查方案&#xff1a;1. 可能是数据量超出了限制的大小&#xff0c;检查数据目录大小2. 查看是否是内存溢出2.1 排查数据量&#xff08;查看数据目录大小是否超过limit限制&#xff09;2.2 查看pod详情发现问题 三、解决过程 一、背景 做redis压测过程中…

在 Mac ARM 架构(例如 M1 或 M2 芯片)上安装 Node.js

文章目录 方法一&#xff1a;使用 Homebrew 安装 Node.js方法二&#xff1a;使用 Node Version Manager (NVM) 安装 Node.js方法三&#xff1a;从 Node.js 官方网站下载安装包注意事项 在 Mac ARM 架构&#xff08;例如 M1 或 M2 芯片&#xff09;上安装 Node.js 可以通过几种不…

pycharm2021.1汉化失败 “chinese (simplified) language pack“ was not installed

汉化报错&#xff1a;pycharm plugin “chinese (simplified) language pack” was not installed : Invalid filename returned by a server 翻译&#xff1a;pycharm 插件“中文&#xff08;简体&#xff09;语言包”未安装&#xff1a;服务器返回的文件名无效 解决&#…

Java基于 SpringBoot+Vue的口腔管理平台(附源码+lw+部署)

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

图书系统小案例

目前就实现了分页查询&#xff0c;修改&#xff0c;删除功能 这个小案例练习到了很多技能&#xff0c;比如前后端交互、异步请求、三层架构思想、后端连接数据库、配置文件、基础业务crud等等 感兴趣的小伙伴可以去做一个试试 准备工作 1、使用maven构建一个web工程 打开i…

延时系统建模,整数延时与分数延时,连续传函与离散传函,Pade近似与Thiran近似,Matlab实现

连续传递函数 严格建模&#xff1a;指数形式 根据拉普拉斯变换的性质&#xff0c; [ f ( t ) ↔ F ( s ) ] ⇔ [ f ( t − t 0 ) ↔ e − s t 0 F ( s ) ] \left[ {f\left( t \right) \leftrightarrow F\left( s \right)} \right] \Leftrightarrow \left[ {f\left( {t - {t_0…

3.14MayBeSomeStack

栈指针是sp 静态数据在内存中位置不改变 码距就是相邻两个合法的数据之间的差距&#xff0c;如果为2的话&#xff0c;相邻两个合法的数据之间存在一个冗余的数据&#xff0c;这个数据肯定是出错的&#xff0c;但是无法判断是哪个合法的数产生的&#xff1b; 如果码距是3的话&…

NLP 2、机器学习简介

人生的苦难不过伏尔加河上的纤夫 —— 24.11.27 一、机器学习起源 机器学习的本质 —— 找规律 通过一定量的训练样本找到这些数据样本中所蕴含的规律 规律愈发复杂&#xff0c;机器学习就是在其中找到这些的规律&#xff0c;挖掘规律建立一个公式&#xff0c;导致对陌生的数…