JAVA代理模式和适配器模式

devtools/2024/12/28 20:17:45/

文章目录

Java 代理模式适配器模式

代理模式(Proxy Pattern)

  • 代理模式是一种结构型设计模式,它为对象提供一个代理对象,以控制对目标对象的访问。代理模式可以在不改变目标对象的前提下,向目标对象添加额外的功能(如权限控制、日志记录、懒加载等)。

  • 特点
  1. 代理对象充当目标对象的替代品。
  2. 代理对象可以对目标对象的访问进行控制或增强。
  3. 常见场景:访问控制、性能优化(如懒加载)、日志记录、分布式调用(如 RPC)等。

适配器模式(Adapter Pattern)

  • 适配器模式也是一种结构型设计模式,它用于解决两个接口不兼容的问题适配器模式通过引入一个适配器类,使得一个类的接口能够兼容另一个类的接口,最终实现它们可以协同工作。

  • 特点
  1. 适配器充当“中间翻译者”,解决接口不匹配的问题。
  2. 常见场景:兼容老系统(向后兼容)、集成第三方库,或者对接口的统一抽象。

代理模式适配器模式的区别

对比点代理模式适配器模式
主要目标控制对目标对象的访问或增加功能解决两个接口不兼容的问题
角色代理对象、目标对象目标对象、适配器、需要适配的接口
使用场景访问控制、权限校验、日志记录、性能优化、分布式调用等将现有的类或接口适配为目标接口,解决接口不兼容的问题
实现方式通过代理类(静态代理或动态代理)实现对目标对象方法的增强通过适配器类实现接口的转换
是否增强功能代理模式可以对目标对象的功能进行增强适配器不增强功能,只是转换接口

代理模式的使用举例

Java 中代理模式可以分为两种实现方式:

  1. 静态代理:代理类由手动编写,在编译时确定。
  2. 动态代理:代理类在运行时动态生成,常用的是 Java 自带的动态代理(基于 java.lang.reflect.Proxy)和 CGLIB 动态代理。

静态代理实现:用代理模式记录方法调用日志

目标接口:

java">public interface Service {void doTask();
}public class RealService implements Service {@Overridepublic void doTask() {System.out.println("RealService: 执行任务");}
}

静态代理类:

java">public class LoggingProxy implements Service {private final Service realService;public LoggingProxy(Service realService) {this.realService = realService;}@Overridepublic void doTask() {System.out.println("LoggingProxy: 开始执行任务...");realService.doTask();System.out.println("LoggingProxy: 任务执行完成");}
}

测试代码:

java">public class StaticProxyExample {public static void main(String[] args) {Service realService = new RealService();Service proxy = new LoggingProxy(realService);proxy.doTask(); // 使用代理对象调用方法}
}

  • 输出
LoggingProxy: 开始执行任务...
RealService: 执行任务
LoggingProxy: 任务执行完成

动态代理实现:使用 Java 动态代理记录方法调用日志

  • 动态代理更加灵活,适合在运行时为任意接口生成代理。

目标接口和实现:

java">public interface Service {void doTask();
}public class RealService implements Service {@Overridepublic void doTask() {System.out.println("RealService: 执行任务");}
}

动态代理处理类:

java">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public 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("LoggingHandler: 方法 " + method.getName() + " 开始执行");Object result = method.invoke(target, args);System.out.println("LoggingHandler: 方法 " + method.getName() + " 执行完成");return result;}
}

测试代码:

java">public class DynamicProxyExample {public static void main(String[] args) {Service realService = new RealService();// 创建动态代理Service proxy = (Service) Proxy.newProxyInstance(realService.getClass().getClassLoader(),realService.getClass().getInterfaces(),new LoggingHandler(realService));proxy.doTask(); // 使用动态代理调用方法}
}

  • 输出
LoggingHandler: 方法 doTask 开始执行
RealService: 执行任务
LoggingHandler: 方法 doTask 执行完成

适配器模式使用举例

  • 适配器模式通常用于解决接口不兼容的问题,例如当我们需要将一个老接口适配为新的接口,或者需要集成第三方库时。

示例:适配老版本接口

  • 定义目标接口和老版本接口:
java">// 新接口
public interface NewInterface {void newMethod();
}// 老接口
public class OldClass {public void oldMethod() {System.out.println("OldClass: 调用旧方法");}
}
  • 适配器类:
java">public class Adapter implements NewInterface {private final OldClass oldClass;public Adapter(OldClass oldClass) {this.oldClass = oldClass;}@Overridepublic void newMethod() {// 在新方法中调用旧方法oldClass.oldMethod();}
}
  • 测试代码:
java">public class AdapterExample {public static void main(String[] args) {OldClass oldClass = new OldClass();NewInterface adapter = new Adapter(oldClass);adapter.newMethod(); // 调用新接口的方法,但实际调用的是旧接口的方法}
}

  • 输出
OldClass: 调用旧方法

适配器模式扩展:对象适配 vs 类适配

  • 对象适配器:通过组合(如上述示例中,适配器持有一个 OldClass 对象)。
  • 类适配器:通过继承来实现适配,适配器继承旧类并实现目标接口(要求旧类不能是 final,且适配器只能适配一个类)。

代理与适配器模式使用建议

使用代理模式的时机

  • 场景 1:需要为对象添加额外功能,而又不想直接修改目标对象的代码(如访问控制、日志记录等)。
  • 场景 2:需要延迟加载目标对象,或者在访问目标对象时添加缓存机制。

  • 推荐使用动态代理
    • 如果需要代理多个类或接口,动态代理更灵活且代码量更少。
    • 如果只针对一个类或接口,可以直接使用静态代理。

使用适配器模式时机

  • 场景 1:需要整合现有的旧系统或第三方库,而它们的接口与当前系统的接口不兼容。
  • 场景 2:需要对不同类的接口进行统一,提供一个一致的调用方法。

  • 建议:
    • 如果需要适配的类较多,可以考虑通过继承或组合方式实现适配器。
    • 如果适配的接口或类较复杂,可以结合工厂模式,统一管理适配器的实例化。

总结

模式适用场景优点缺点
代理模式功能增强(日志、权限、远程调用等)灵活添加功能,解耦目标对象和功能实现静态代理增加代码量,动态代理可能增加复杂度
适配器模式接口不兼容(老接口适配新接口、第三方库整合等)解决接口兼容问题,增强代码复用性若接口变化频繁,适配器可能需要频繁修改

http://www.ppmy.cn/devtools/146194.html

相关文章

LabVIEW软件项目设计方案如何制定

制定LabVIEW软件项目设计方案需要综合考虑需求分析、架构设计、功能模块划分和时间预算等多个方面,确保项目开发过程高效、可控且最终满足目标要求。以下是一个详细的制定流程: ​ 1. 需求分析 目标定义:明确项目的目标,例如数据采…

计算属性 简写和 完整写法

计算属性渲染不加上括号 methods方法和computed属性区别: computed只计算一次,然后缓存,后续直接拿出来使用,而methods每次使用每次计算,不会缓存 计算属性完整写法: 既获取又设置 slice 截取 成绩案例 …

Binoculars——分析证实大语言模型生成文本的检测和引用量按学科和国家明确显示了使用偏差的多样性和对内容类型的影响

摘要 论文地址:https://www.biorxiv.org/content/10.1101/2024.03.25.586710v2.full.pdf 人工智能技术的进步正在改变数字内容生产和消费的格局。尤其值得注意的是生成式人工智能的快速发展,包括大规模语言模型,如 ChatGPT,它出现…

Qt Designer与常用组件

目录 一、Qt Designer使用入门与进阶 二、布局Layout详解 三、QWidget及其常用属性 四、界面文件与C代码的完美结合 五、QLabel与图片资源管理 六、QAbstractButton及其子类的应用 七、QLineEdit与用户输入交互 八、ComboBox与选项管理 九、数字相关组件的综合应用 摘…

5_SparkGraphX讲解

SparkGraphX讲解 1、为何使用SparkGraphiX图处理? 许多大数据以大规模图或网络的形式呈现,尤其是许多的非图结构的大数据,常会被转换为图模型进行分析。 图数据结构能够很好地表达数据之间的关联性。 2、图——基本术语认知 概念&#xf…

《操作系统真象还原》第十章(二)—— 键盘驱动程序的编写与输入系统

章节任务介绍 在上一节中,我们介绍了操作系统的同步机制互斥锁的内容,并手动实现了互斥锁,同时实现了线程安全的屏幕打印。 至此,我们算是基本完成了操作系统的“输出”功能,但目前为止我们的输入仍旧依赖于程序&…

Bash 脚本教程

注:本文为 “Bash 脚本编写” 相关文章合辑。 BASH 脚本编写教程 as good as well于 2017-08-04 22:04:28 发布 这里有个老 American 写的 BASH 脚本编写教程,非常不错,至少没接触过 BASH 的也能看懂! 建立一个脚本 Linux 中有…

面试知识点汇总_03

解释一下同步电路和异步电路 同步电路和异步电路是指同步时序电路和异步时序电路。由于存储电路中触发器的动作特点不同,因此可以把时序电路分为同步时序电路和异步时序电路两种。同步时序电路所有的触发器状态的变化都是在同一时钟信号操作下同时发生的;而在异步时序电路中…