代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它通过引入代理对象来控制对某个对象的访问。代理对象和实际对象实现相同的接口,因此可以在不改变实际对象的情况下,对访问进行控制。代理模式主要有以下几种类型:
- 虚代理(Virtual Proxy):用于延迟初始化对象的创建。虚代理会在实际对象被真正需要时才创建它,从而节省资源。例如,大型图像或视频文件可以在用户查看之前不进行加载。
- 保护代理(Protection Proxy):用于控制对对象的访问权限。保护代理可以在实际对象之前增加访问控制,确保只有授权的用户可以访问对象的功能。例如,某些操作可能只对管理员用户开放。
- 远程代理(Remote Proxy):用于表示一个位于不同地址空间的对象。远程代理处理网络通信,将远程对象的请求转发到实际的远程对象。例如,分布式系统中的对象访问。
- 缓存代理(Cache Proxy):用于缓存对象的结果,减少对实际对象的访问次数,提高效率。例如,缓存计算结果或数据库查询结果,以便后续请求能更快地响应。
主要组成部分
- Subject(主题接口):
- 定义了代理和实际对象的共同接口。客户端通过这个接口与实际对象进行交互,代理对象和实际对象都实现这个接口。
- RealSubject(实际对象):
- 实际实现了主题接口的类。它是代理模式中真正需要控制访问的对象。
- Proxy(代理对象):
- 实现了主题接口,并持有对实际对象的引用。代理对象通过调用实际对象的方法来实现控制和管理功能。根据不同的类型,代理可以在实际对象访问之前或之后执行附加的操作。
示例
接口 Service
public interface Service {
void add();
void del();
}
定义了服务接口,声明了两个方法 add
和 del
。
实际服务类 RealService
public class RealService implements Service {
@Override
public void add() {
System.out.println("成功添加");
}
@Override
public void del() {
System.out.println("成功删除");
}
}
实现了 Service
接口,提供了实际的业务逻辑。
代理服务类 ProxyService
public class ProxyService implements Service {
private RealService realService;
@Override
public void add() {
if (realService == null) {
realService = new RealService();
}
realService.add();
System.out.println("在代理中,记录日志,添加成功");
}
@Override
public void del() {
if (realService == null) {
realService = new RealService();
}
realService.del();
System.out.println("在代理中,记录日志,删除成功");
}
}
优点:
- 简单直观:
- 实现简单:静态代理的实现较为直接,你可以在编译时创建代理类,代码结构清晰,易于理解和维护。
- 性能较高:由于代理类在编译时已经创建,调用方法时直接调用实际对象的实现,性能相对较高。
- 明确的代理行为:
- 控制逻辑明确:由于代理类的代码是手动编写的,代理的行为和逻辑在代码中明确,便于调试和测试。
缺点:
- 代码重复:
- 代理类多:每种服务或每种业务逻辑都需要一个代理类,代码量大且重复。如果接口或方法增加,需手动创建新的代理类。
- 灵活性差:
- 扩展困难:如果业务逻辑变化或增加新的功能,需要修改每个代理类的代码。扩展和修改较为繁琐。
- 维护成本高:
- 修改困难:每当接口或业务逻辑发生变化,都需要重新编译和修改所有相关的代理类,增加了维护成本。
动态代理
public interface Service {
void add();
void del();
}
public class RealService implements Service {
@Override
public void add() {
System.out.println("成功添加");
}
@Override
public void del() {
System.out.println("成功删除");
}
}
public class DynamicProxyHandler implements InvocationHandler {
private Object realService;
public DynamicProxyHandler(Object realService) {
this.realService = realService;
}
/*
newProxyInstance,方法有三个参数:
loader: 用哪个类加载器去加载代理对象
interfaces:动态代理类需要实现的接口
h:动态代理方法在执行时,会调用h里面的invoke方法去执行
*/
public Object getRealService(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), realService.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(realService, args);
// 让service调用方法,方法返回值
System.out.println(proxy.getClass().getName() + "代理类执行" +realService.getClass().getName()+"内部"+ method.getName() + "方法,返回" + result + ",记录日志!");
return result;
}
}
package StructuralPattern.ProxyPattern;
import StructuralPattern.ProxyPattern.DynamicProxy.DynamicProxyHandler;
import StructuralPattern.ProxyPattern.DynamicProxy.RealService;
import StructuralPattern.ProxyPattern.DynamicProxy.Service;
//import StructuralModel.ProxyPattern.StaticProxy.ProxyService;
public class TestProxyPattern {
public static void main(String[] args) {
//静态代理
// Service proxyService=new ProxyService();
// proxyService.add();
// System.out.println();
// proxyService.del();
//动态代理
Service service = new RealService();
Service serviceProxy = (Service) new DynamicProxyHandler(service).getRealService();
serviceProxy.add();
System.out.println();
serviceProxy.del();
}
}
优点:
- 高灵活性:
- 动态创建:代理类在运行时创建,不需要为每种服务手动编写代理类。可以处理不同的实际对象和方法调用。
- 通用性:通过
InvocationHandler
可以动态定义代理行为,适用于接口方法增加或变化的情况。
- 减少重复代码:
- 代码简洁:只需编写一个通用的
InvocationHandler
实现类,减少了重复的代码和维护工作。
- 代码简洁:只需编写一个通用的
- 易于扩展:
- 修改方便:修改代理逻辑只需调整
InvocationHandler
中的代码,不需要改变业务类或创建新的代理类。
- 修改方便:修改代理逻辑只需调整
缺点:
- 性能开销:
- 反射开销:动态代理依赖于反射机制,这可能会引入一定的性能开销。在性能要求较高的场景中可能不够高效。
- 调试难度:
- 难以跟踪:由于代理类在运行时创建,调试和排错可能更加困难。代理行为是通过反射实现的,可能不如静态代理直观。
- 复杂性增加:
- 理解难度:动态代理的实现相对复杂,需要理解反射机制和代理模式的工作原理。对初学者来说,可能有一定的学习曲线。
总结
- 静态代理适合接口较少、变化不频繁的场景,优点在于实现简单、性能较高,但缺点是代码重复、灵活性差、维护成本高。
- 动态代理适合接口较多、业务逻辑复杂、需要灵活控制代理行为的场景,优点在于高灵活性、减少重复代码、易于扩展,但缺点是性能开销、调试难度和复杂性增加。
参考
https://blog.csdn.net/m0_51380306/article/details/119912574
代理模式的主要优点是能够控制对实际对象的访问,增加灵活性,同时不需要修改实际对象的代码。
标签:Service,对象,接口,代理,realService,模式,public From: https://www.cnblogs.com/20lxj666/p/18389076