设计模式——代理模式
目录
- 设计模式——代理模式
- 介绍
- 基本结构
- 实现
- 静态代理
- 动态代理
- 应用场景
- 代理模式的优缺点
- 总结
介绍
代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过代理对象来控制对某个对象的访问。代理模式主要用于在不改变原对象的情况下,控制对其的访问,或在访问时添加一些附加功能。
基本结构
在代理模式中,有三个主要角色:
- Subject(主题):定义了一个接口,这个接口可以是真实主题类和代理类都可以实现的接口。通常,它是代理和实际对象都必须实现的共同接口。
- RealSubject(真实主题):实现了 Subject 接口,通常是真正的业务对象,包含了代理模式所需要代理的具体操作。
- Proxy(代理类):代理类也实现了 Subject 接口,它通常会持有一个 RealSubject 的引用,并且可以在请求到达 RealSubject 之前或之后,执行一些额外的操作,如权限验证、延迟加载、日志记录等。
实现
静态代理
静态代理是在编译时就确定了代理类和真实类的关系,通常代理类和真实类有相同的接口。静态代理的代理类在运行时直接委托给真实对象实现具体操作。
示例代码:
-
Subject(主题)
// Subject 接口 public interface Subject {void request(); }
-
RealSubject(真实主题)
// RealSubject 类 public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject request");} }
-
Proxy(代理类)
// Proxy 类 public class Proxy implements Subject {private RealSubject realSubject;public Proxy(RealSubject realSubject) {this.realSubject = realSubject;}@Overridepublic void request() {System.out.println("Proxy request before");realSubject.request();System.out.println("Proxy request after");} }
-
测试代码(客户端)
// 客户端代码 public class Client {public static void main(String[] args) {RealSubject realSubject = new RealSubject();Proxy proxy = new Proxy(realSubject);proxy.request();} }
以上述为例,我们可以清楚看到,通过代理,轻松实现在调用具体目标方法前后补充内容。具体补充的内容由业务决定(权限校验,日志记录等等),只需要在
Proxy
中修改request()
方法中的逻辑即可
动态代理
动态代理是在运行时由代理类自动生成的,常常利用 Java 反射机制和 Proxy
类来创建代理对象。动态代理在开发中更加灵活,通常不需要在编译时明确指定代理类。这里注意:Java中提供了一个动态代理类Proxy
,Proxy
并不是我们上述所说的代理对象的类,而是提供了一个创建代理对象的静态方法(newProxyInstance方法)来获取代理对象。
示例代码:
-
Subject(主题)
//卖票接口 public interface SellTickets {void sell(); }
-
RealSubject(真实主题)
//火车站 火车站具有卖票功能,所以需要实现SellTickets接口 public class TrainStation implements SellTickets {public void sell() {System.out.println("火车站卖票");} }
-
动态代理类(重点理解)
//代理工厂,用来创建代理对象 public class ProxyFactory {private TrainStation station = new TrainStation();// 获取代理对象public SellTickets getProxyObject() {//使用Proxy获取代理对象/*newProxyInstance()方法参数说明:ClassLoader loader : 类加载器,用于加载代理类,使用真实对象的类加载器即可Class<?>[] interfaces : 真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口InvocationHandler h : 代理对象的调用处理程序*/SellTickets sellTickets = (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(),station.getClass().getInterfaces(),new InvocationHandler() {/*InvocationHandler中invoke方法参数说明:proxy : 代理对象method : 对应于在代理对象上调用的接口方法的 Method 实例args : 代理对象调用接口方法时传递的实际参数*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理点收取一些服务费用(JDK动态代理方式)");// 执行真实对象// 这里执行的是真实主题中的sell()方法// 第一个参数就是真实主题对象,第二个是真是主题中对应方法的参数Object result = method.invoke(station, args);return result;}});return sellTickets;} }
-
测试代码(客户端)
//测试类 public class Client {public static void main(String[] args) {//获取代理对象ProxyFactory factory = new ProxyFactory();SellTickets proxyObject = factory.getProxyObject();proxyObject.sell();} }
通过动态代理,我们也可以轻松实现对某些方法的加强,不过可能会对技术要求高些。(由于需要结合大量代码进行解释,我就只能在代码中以注释的形式进行解释,这里就不再多说了)
应用场景
代理模式的应用场景
- 延迟加载(Lazy Loading): 代理模式可以用于延迟加载对象,只有在需要时才创建真实对象。例如,图像加载、数据库连接等。
- 权限控制: 在一些场景下,代理可以控制对某些资源的访问。代理可以在请求到达真实对象之前,检查客户端是否有访问权限。
- 日志记录: 代理模式可以在实际方法执行之前或之后进行日志记录。这对于监控、调试或审计应用程序行为很有帮助。
- 远程代理: 在分布式系统中,代理模式常用来表示一个远程对象,通过代理对远程对象的调用进行透明处理,隐藏了远程通信的细节。
- 虚拟代理: 用于管理占用大量资源的对象的创建过程,比如加载图像、视频等。通过代理来推迟资源的加载,直到需要时才加载。
代理模式的优缺点
优点:
- 可以控制访问:通过代理可以在访问真实对象前后加入额外的控制逻辑,如权限验证、日志记录等。
- 提高性能:代理可以延迟加载资源,避免在不必要时加载或执行耗时操作。
- 扩展功能:可以在不修改真实对象的情况下,扩展其功能(例如,添加缓存、日志等)。
缺点:
- 增加复杂性:代理模式引入了额外的代理对象和复杂的类结构,可能使代码更复杂。
- 性能开销:代理模式可能会引入额外的开销,因为每次对真实对象的操作都需要通过代理对象来转发。
总结
代理模式是一种通过代理对象控制对实际对象的访问的设计模式,它非常灵活,可以在许多场景中提高代码的可维护性和扩展性。代理可以用于日志记录、延迟加载、权限控制、性能优化等场景。