设计模式:代理模式

代理模式

代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

介绍

意图:为其他对象提供一种代理以控制对这个对象的访问。

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

何时使用:想在访问一个类时做一些控制。

如何解决:增加中间层。

关键代码:实现与被代理类组合。

优点: 1、职责清晰。 2、高扩展性。 3、智能化。

缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

使用场景:Spring-AOP

注意事项:

  • 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
  • 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

实现

image-20240404195034972

静态模式

image-20240404194630768

动态模式

作用: 与静态代理一样,但动态代理解决了 静态代理中 1个静态代理,只代理1种类型的目标对象 的问题

1. JDK动态代理

在 JDK 动态代理中涉及如下角色:

  • 目标类的接口 Interface
  • 目标类 target
  • 处理模版 Handler
  • 在内存中生成的动态代理类
  • java.lang.reflect.Proxy

image-20240404200723259

动态代理类实现了目标类的接口,并实现了接口中的方法,该方法的实现逻辑是, 调用父类 —— Proxy 的 h 的 invoke()方法

其中h 是 在创建动态代理实例时 newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) 传入的第3个参数InvocationHandler对象

在 InvocationHandler.invoke()中通过反射,调用目标对象。

特点: 不需要显式实现与目标类相同的接口,而是将这种实现推迟到程序调用时由 JVM来实现,

  • 即:在使用时再创建动态代理类 和 实例
  • 静态代理则是在代理类实现时就指定与目标相同的接口

优点:一个代理类就可以代理多个目标类,避免重复、多余代码

缺点

  • 相比与静态代理,效率低。 静态代理是直接调用目标对象方法,而动态代理则需要先生成类和对象,在通过Java反射机制间接调用目标对象的方法
  • 应用场景局限, 由于每个代理类都继承了 java.lang.reflect.Proxy 类,而Java又只能支持单继承,导致不能针对类 创建代理类,只能针对接口 创建 代理类。即,动态代理只能代理实现了接口的类。

应用场景

  • 需要代理的对象数量较多的情况下。数量较少时,推荐直接使用静态代理
  • 面向切面编程时

2. cglib动态代理

image-20240404202401008

代理类必须要和目标类是同一个类型!

这里的“同一个类型”指的是

  • 要么,代理类目标类都实现了同一个接口,他们都属于同一种类型,即都是该接口的子类。
  • 要么,代理类继承自目标类,这也是属于同一种类型,前提是目标类没有被 final 关键字修饰

3. CGLib的动态代理 与java动态代理的区别

image-20240404203513475

  • Java动态代理生成的代理类和目标类是 “兄弟”关系
  • cglib动态代理生成的代理类和目标类是 “父子”关系

局限性

  • Java动态代理依赖于目标类有实现接口
  • cglib动态代依赖于目标类没有被final关键字修饰

设计模式:代理模式
https://xsinxcos.github.io/2024/04/03/设计模式:代理模式/
作者
xsinxcos(涿)
发布于
2024年4月3日
许可协议