代理模式 (Proxy Pattern)

ops/2024/11/27 10:54:39/

文章目录

      • 代理模式 (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 {@Overridepublic 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;}@Overridepublic 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 {@Overridepublic 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;}@Overridepublic 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. 日志、性能监控:在方法调用前后增加日志或监控逻辑。

小结

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

http://www.ppmy.cn/ops/137058.html

相关文章

css:转换

转换 移动 /* transform: translate(100px, 200px); */transform: translateX(100px);transform: translateY(100px); /*一个意思*/ 如果后面跟百分数的意思是移动盒子自身x/y方向长度的百分比&#xff0c;可以用作子绝父相控制盒子水平居中垂直居中 translate里的xy值是相对…

Perforce SAST专家详解:自动驾驶汽车的安全与技术挑战,Klocwork、Helix QAC等静态代码分析成必备合规性工具

自动驾驶汽车安全吗&#xff1f;现代汽车的软件包含1亿多行代码&#xff0c;支持许多不同的功能&#xff0c;如巡航控制、速度辅助和泊车摄像头。而且&#xff0c;这些嵌入式系统中的代码只会越来越复杂。 随着未来汽车的互联程度越来越高&#xff0c;这一趋势还将继续。汽车越…

AdaPipe:动态规划解决显存和GPU在LLM计算中出现气泡问题

目录 AdaPipe:动态规划解决显存和GPU在LLM计算中出现气泡问题 0-5表示不同数据 大的方块表示:管道,便于理解了想成GPU 黄色方块表示显存 Stage表示Attention和FFN layer(Projection和MLP) 重计算和分区策略:细化了Attention和FFN layer Transformer中的管道 AdaPi…

鸿蒙动画开发07——粒子动画

1、概 述 粒子动画是在一定范围内随机生成的大量粒子产生运动而组成的动画。 动画元素是一个个粒子&#xff0c;这些粒子可以是圆点、图片。我们可以通过对粒子在颜色、透明度、大小、速度、加速度、自旋角度等维度变化做动画&#xff0c;来营造一种氛围感&#xff0c;比如下…

【算法】欧几里得与拓展欧几里得算法

目录 一、欧几里得算法 二、拓展欧几里得算法 2.1 裴蜀定理 2.2 拓展欧几里得算法 2.3 例题 三、线性同余方程 3.1 概念 3.2 例题 一、欧几里得算法 欧几里得算法又称辗转相除法&#xff0c;可用于求解两个数的最大公约数 其思路&#xff1a; gcd(a, b) gcd(b, a%b…

241126学习日志——[CSDIY] [ByteDance] 后端训练营 [19]

CSDIY&#xff1a;这是一个非科班学生的努力之路&#xff0c;从今天开始这个系列会长期更新&#xff0c;&#xff08;最好做到日更&#xff09;&#xff0c;我会慢慢把自己目前对CS的努力逐一上传&#xff0c;帮助那些和我一样有着梦想的玩家取得胜利&#xff01;&#xff01;&…

Deepnote、JupyterLab、Google Colab、Amazon SageMaker、VS Code对比

功能比较 平台语言支持扩展性数据连接可视化能力DeepnotePython、R、SQL中等&#xff0c;依赖云端支持主要云平台&#xff08;BigQuery、Snowflake等&#xff09;内置仪表盘与交互图表JupyterLab多种语言&#xff0c;插件支持广泛极高&#xff0c;完全可自定义使用库&#xff…

【C++】list模拟实现(完结)

1.普通迭代器&#xff08;补充&#xff09; 1.1 后置和后置-- 我们迭代器里面实现了前置和前置--&#xff0c;还需要实现后置和后置--。 在list.h文件的list_iterator类里面实现。 //后置/-- Self& operator(int) {Self tem(*this);//保存原来的值_node _node->_nex…