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