【设计模式-代理】
定义
代理模式是一种结构型设计模式,它提供了对象的替代者或占位符,用来控制对这个对象的访问。通过代理模式,一个类可以代表另一个类来执行某些操作。这种模式常用于增强对象的功能或控制对对象的访问。
特点
控制访问:代理模式可以控制对目标对象的访问,甚至可以在访问前后进行某些操作。
增强功能:代理可以在不修改目标对象的前提下,增强目标对象的功能。
延迟加载:代理模式可以实现对象的延迟加载,只有在真正需要的时候才创建对象。
分类
- 静态代理(Static Proxy):代理类在编译时已经确定,通常由开发者手动编写。
- 动态代理(Dynamic Proxy):代理类在运行时动态生成,通常通过反射机制实现。
- 虚拟代理(Virtual Proxy):用于延迟加载对象,只有在需要时才创建对象。
- 保护代理(Protection Proxy):控制对对象的访问权限。
- 远程代理(Remote Proxy):用于控制对远程对象的访
组成
-
抽象主题角色:定义了被代理角色和代理角色的共同接口或者抽象类。
-
被代理角色:实现或者继承抽象主题角色,定义实现具体业务逻辑的实现。
-
代理角色:实现或者继承抽象主题角色,持有被代理角色的引用,控制和限制被代理角色的实现,并且拥有自己的处理方法(预处理和善后)
代码
静态代理
// 抽象接口
public interface Subject {
void request();
}
// 真实对象,实现具体的业务逻辑
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 代理类,控制对 RealSubject 的访问
public class Proxy implements Subject {
private RealSubject realSubject;
@Override
public void request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
System.out.println("Proxy: Performing additional actions before forwarding request to RealSubject.");
realSubject.request();
System.out.println("Proxy: Performing additional actions after forwarding request to RealSubject.");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request();
}
}
动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 真实对象,实现具体的业务逻辑
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 动态代理处理器
class ProxyInvocationHandler implements InvocationHandler {
private final Object realSubject;
public ProxyInvocationHandler(Object realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Proxy: Performing actions before invoking real subject.");
Object result = method.invoke(realSubject, args);
System.out.println("Proxy: Performing actions after invoking real subject.");
return result;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
// 创建代理对象
Subject proxyInstance = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new ProxyInvocationHandler(realSubject)
);
// 调用代理对象的方法
proxyInstance.request();
}
}
优点
- 职责分离:通过代理模式,可以将真实对象的实现与控制访问的逻辑分离,符合单一职责原则。
- 增强功能:在不修改真实对象的情况下,通过代理类可以增加额外的功能,如日志记录、性能统计、安全控制等。
- 灵活性:代理模式使得在不改变客户端代码的情况下,能够动态地更换不同的代理对象。
缺点
- 增加复杂性:引入代理模式会增加系统的复杂性,尤其是在使用动态代理时,可能会让代码变得难以理解和调试。
- 性能开销:代理模式在某些情况下会增加系统的开销,特别是在频繁调用的情况下,代理对象的创建和方法调用的间接性可能会影响性能。
场景
- 远程代理:需要通过代理对象来控制对远程对象的访问。
- 虚拟代理:需要延迟创建资源消耗大的对象,或者只在需要时创建对象。
- 保护代理:需要控制对对象的访问权限,如在应用程序中根据用户的权限控制对某些功能的访问。
- 缓存代理:需要对访问频繁的对象或结果进行缓存,以减少资源消耗或提高性能。
总结
代理模式通过引入代理对象控制对目标对象的访问,适用于需要增强功能、延迟加载、权限控制、远程访问等场景。静态代理通过手动编写代理类来控制对象访问,而动态代理则通过运行时生成代理类提供了更灵活的解决方案。虽然代理模式增加了系统的复杂性,但它在特定场景下能带来更好的代码结构和更高的灵活性。