文章目录
- 代理模式 (Proxy Pattern)
- 原理
- 分类
- 优点
- 缺点
- 示例代码
- 静态代理
- 1. 定义接口
- 2. 创建真实类
- 3. 创建代理类
- 4. 客户端代码
- 输出结果
- 动态代理(基于 JDK)
- 1. 定义接口和真实类
- 2. 创建动态代理类
- 3. 客户端代码
- 输出结果
- UML 类图
- 静态代理
- 动态代理
- 使用场景
- 小结
代理模式 (Proxy Pattern)
代理模式是一种 结构型设计模式,它为某个对象提供一个替代或占位符,用来控制对这个对象的访问。通过代理对象,可以在实际对象的前后加入额外的功能(如权限校验、日志记录等)。
原理
- 核心思想:
- 使用一个代理类代表实际对象,客户端通过代理类间接访问实际对象。
- 适用场景:
- 控制对实际对象的访问(如权限验证)。
- 增强功能(如日志记录、延迟加载)。
- 远程代理、虚拟代理等场景。
- 参与角色:
- Subject(抽象主题类):定义真实对象和代理对象的公共接口。
- RealSubject(真实主题类):实现抽象主题,表示被代理的真实对象。
- Proxy(代理类):实现抽象主题,内部持有真实主题的引用,用来控制访问和增强功能。
分类
- 静态代理:代理类在编译时生成,开发者需要手动编写代理类。
- 动态代理:代理类在运行时动态生成,无需手动编写。
- 基于 JDK 的动态代理(必须实现接口)。
- 基于 CGLIB 的动态代理(无需接口)。
优点
- 控制访问:可以对访问真实对象进行约束。
- 功能扩展:通过代理类,在真实对象前后加入增强功能。
缺点
- 增加复杂性:引入代理类后,代码复杂度增加。
- 性能开销:动态代理会带来一定的性能消耗。
示例代码
静态代理
场景:一个 Payment
接口,有具体的支付实现。通过代理类对支付操作进行日志记录。
1. 定义接口
// 抽象主题
public interface Payment {void pay(int amount);
}
2. 创建真实类
// 真实主题类
public class RealPayment implements Payment {@Overridepublic void pay(int amount) {System.out.println("Processing payment of $" + amount);}
}
3. 创建代理类
// 代理类
public class PaymentProxy implements Payment {private RealPayment realPayment;public PaymentProxy(RealPayment realPayment) {this.realPayment = realPayment;}@Overridepublic void pay(int amount) {System.out.println("Logging: Initiating payment...");realPayment.pay(amount); // 调用真实对象的方法System.out.println("Logging: Payment completed.");}
}
4. 客户端代码
public class StaticProxyExample {public static void main(String[] args) {RealPayment realPayment = new RealPayment(); // 创建真实对象Payment proxy = new PaymentProxy(realPayment); // 创建代理对象proxy.pay(100); // 使用代理对象}
}
输出结果
Logging: Initiating payment...
Processing payment of $100
Logging: Payment completed.
动态代理(基于 JDK)
场景:通过动态代理实现相同的功能,无需手动编写代理类。
1. 定义接口和真实类
// 抽象主题
public interface Payment {void pay(int amount);
}// 真实主题类
public class RealPayment implements Payment {@Overridepublic void pay(int amount) {System.out.println("Processing payment of $" + amount);}
}
2. 创建动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 动态代理类
public class DynamicProxyHandler implements InvocationHandler {private Object realObject;public DynamicProxyHandler(Object realObject) {this.realObject = realObject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Logging: Before method call...");Object result = method.invoke(realObject, args); // 调用真实对象的方法System.out.println("Logging: After method call...");return result;}// 获取代理实例public static Object getProxyInstance(Object realObject) {return Proxy.newProxyInstance(realObject.getClass().getClassLoader(),realObject.getClass().getInterfaces(),new DynamicProxyHandler(realObject));}
}
3. 客户端代码
public class DynamicProxyExample {public static void main(String[] args) {RealPayment realPayment = new RealPayment(); // 创建真实对象Payment proxy = (Payment) DynamicProxyHandler.getProxyInstance(realPayment); // 获取代理实例proxy.pay(200); // 使用代理对象}
}
输出结果
Logging: Before method call...
Processing payment of $200
Logging: After method call...
UML 类图
静态代理
+------------+ +-------------+| Payment |<------+ RealPayment |+------------+ +-------------+^ ^| |+-------------------------------+| PaymentProxy |+-------------------------------+
动态代理
+------------+ +-------------+| Payment |<------+ RealPayment |+------------+ +-------------+^|+-------------+| Proxy |+-------------+
使用场景
- 远程代理:为远程对象提供本地代理(如 RMI)。
- 虚拟代理:延迟加载资源,按需加载实际对象。
- 保护代理:对访问进行权限控制。
- 日志、性能监控:在方法调用前后增加日志或监控逻辑。
小结
- 静态代理:需要手动编写代理类,适用于代理逻辑较少且稳定的场景。
- 动态代理:无需手动编写代理类,灵活性强,适用于接口较多或逻辑频繁变化的场景。
- 代理模式解耦了客户端与实际对象,增强了系统的灵活性和扩展性。