JAVA代理模式和适配器模式
文章目录
Java 代理模式和适配器模式
代理模式(Proxy Pattern)
- 代理模式是一种结构型设计模式,它为对象提供一个代理对象,以控制对目标对象的访问。代理模式可以在不改变目标对象的前提下,向目标对象添加额外的功能(如权限控制、日志记录、懒加载等)。
- 特点
- 代理对象充当目标对象的替代品。
- 代理对象可以对目标对象的访问进行控制或增强。
- 常见场景:访问控制、性能优化(如懒加载)、日志记录、分布式调用(如 RPC)等。
适配器模式(Adapter Pattern)
- 适配器模式也是一种结构型设计模式,它用于解决两个接口不兼容的问题。适配器模式通过引入一个适配器类,使得一个类的接口能够兼容另一个类的接口,最终实现它们可以协同工作。
- 特点
- 适配器充当“中间翻译者”,解决接口不匹配的问题。
- 常见场景:兼容老系统(向后兼容)、集成第三方库,或者对接口的统一抽象。
代理模式和适配器模式的区别
对比点 | 代理模式 | 适配器模式 |
---|---|---|
主要目标 | 控制对目标对象的访问或增加功能 | 解决两个接口不兼容的问题 |
角色 | 代理对象、目标对象 | 目标对象、适配器、需要适配的接口 |
使用场景 | 访问控制、权限校验、日志记录、性能优化、分布式调用等 | 将现有的类或接口适配为目标接口,解决接口不兼容的问题 |
实现方式 | 通过代理类(静态代理或动态代理)实现对目标对象方法的增强 | 通过适配器类实现接口的转换 |
是否增强功能 | 代理模式可以对目标对象的功能进行增强 | 适配器不增强功能,只是转换接口 |
代理模式的使用举例
Java 中代理模式可以分为两种实现方式:
- 静态代理:代理类由手动编写,在编译时确定。
- 动态代理:代理类在运行时动态生成,常用的是 Java 自带的动态代理(基于
java.lang.reflect.Proxy
)和 CGLIB 动态代理。
静态代理实现:用代理模式记录方法调用日志
目标接口:
public interface Service {
void doTask();
}
public class RealService implements Service {
@Override
public void doTask() {
System.out.println("RealService: 执行任务");
}
}
静态代理类:
public class LoggingProxy implements Service {
private final Service realService;
public LoggingProxy(Service realService) {
this.realService = realService;
}
@Override
public void doTask() {
System.out.println("LoggingProxy: 开始执行任务...");
realService.doTask();
System.out.println("LoggingProxy: 任务执行完成");
}
}
测试代码:
public class StaticProxyExample {
public static void main(String[] args) {
Service realService = new RealService();
Service proxy = new LoggingProxy(realService);
proxy.doTask(); // 使用代理对象调用方法
}
}
- 输出
LoggingProxy: 开始执行任务...
RealService: 执行任务
LoggingProxy: 任务执行完成
动态代理实现:使用 Java 动态代理记录方法调用日志
- 动态代理更加灵活,适合在运行时为任意接口生成代理。
目标接口和实现:
public interface Service {
void doTask();
}
public class RealService implements Service {
@Override
public void doTask() {
System.out.println("RealService: 执行任务");
}
}
动态代理处理类:
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;
}
@Override
public 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;
}
}
测试代码:
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 执行完成
适配器模式使用举例
- 适配器模式通常用于解决接口不兼容的问题,例如当我们需要将一个老接口适配为新的接口,或者需要集成第三方库时。
示例:适配老版本接口
- 定义目标接口和老版本接口:
// 新接口
public interface NewInterface {
void newMethod();
}
// 老接口
public class OldClass {
public void oldMethod() {
System.out.println("OldClass: 调用旧方法");
}
}
- 适配器类:
public class Adapter implements NewInterface {
private final OldClass oldClass;
public Adapter(OldClass oldClass) {
this.oldClass = oldClass;
}
@Override
public void newMethod() {
// 在新方法中调用旧方法
oldClass.oldMethod();
}
}
- 测试代码:
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:需要对不同类的接口进行统一,提供一个一致的调用方法。
- 建议:
- 如果需要适配的类较多,可以考虑通过继承或组合方式实现适配器。
- 如果适配的接口或类较复杂,可以结合工厂模式,统一管理适配器的实例化。
总结
模式 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
代理模式 | 功能增强(日志、权限、远程调用等) | 灵活添加功能,解耦目标对象和功能实现 | 静态代理增加代码量,动态代理可能增加复杂度 |
适配器模式 | 接口不兼容(老接口适配新接口、第三方库整合等) | 解决接口兼容问题,增强代码复用性 | 若接口变化频繁,适配器可能需要频繁修改 |
原文地址:https://blog.csdn.net/yang2330648064/article/details/144778265
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!