一、代理模式介绍
代理设计模式(Proxy Pattern)是面向对象软件设计中的一种常用模式,它属于结构型设计模式。代理设计模式的主要目的是为其他对象提供一种代理以控制对这个对象的访问。以下是对代理设计模式的详细介绍:
1、定义与概念
代理设计模式通过为其他对象提供一个代理对象,来控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接被引用,或者为了某种简洁方便,代理对象可以在客户端和目标对象之间起到中介的作用。这种设计模式在生活中有很多实例,如抢票软件、各种中介服务、代理服务器等。
2、结构组成
代理模式类图:
代理设计模式通常包含以下几个角色:
-
抽象角色(Subject):通过接口或抽象类声明真实角色实现的业务方法。这是代理模式的基础,它定义了代理和真实对象都应该遵循的公共接口或抽象类。
-
代理角色(Proxy):实现抽象角色,是真实角色的代理。它持有真实角色的实例,并在调用真实角色的业务逻辑方法前后添加一些额外的操作,如日志记录、权限校验、事务管理等。
-
真实角色(RealSubject):实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。这是实际执行具体业务逻辑的对象。
3、分类
代理设计模式可以分为多种类型,每种类型都有其特定的用途:
-
远程代理(Remote Proxy):负责代表位于远程位置的对象,封装了远程通信的细节。
-
虚拟代理(Virtual Proxy):根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象的引用。
-
保护代理(Protection Proxy):控制对原始对象的访问,保护目标对象不被恶意访问。
-
缓存代理(Cache Proxy):为一些开销大的运算结果提供暂时的存储空间,以便在下次使用时能够快速返回结果。
-
智能代理(Smart Proxy):在访问对象时执行一些附加操作,如访问统计、懒加载、权限校验等。
4、优缺点
优点:
-
控制访问:代理模式能够将代理对象与真实被调用的目标对象分离,控制对目标对象的访问。
-
增强功能:可以在不修改目标对象的情况下,增加额外的功能。
-
降低耦合:一定程度上降低了系统的耦合度,提高了系统的扩展性。
-
保护目标对象:代理对象可以作为目标对象的保护屏障,隔离外部的直接访问。
缺点:
-
增加复杂度:在客户端和目标对象之间增加一个代理对象,会增加系统的复杂度和理解难度。
-
请求处理速度变慢:由于增加了代理层,可能会导致请求处理速度变慢。
-
类的数量增加:代理模式会造成系统设计中类的数量增加。
5、应用场景
代理设计模式在软件开发中有广泛的应用场景,如:
-
远程方法调用:通过代理类处理远程方法调用。
-
权限控制:在访问敏感资源时,通过代理类进行权限校验。
-
日志记录:在方法调用前后记录日志信息。
-
延迟加载:对于大对象或资源密集型对象的加载,采用代理模式实现延迟加载,提高系统性能。
-
缓存管理:通过代理模式实现缓存管理,减少重复计算或数据库查询。
6、实现方式
代理设计模式的实现方式主要有两种:静态代理和动态代理。
-
静态代理:代理类在程序运行前就已经存在,由程序员手动创建。当接口增加或减少方法时,代理类也需要相应地进行修改。
-
动态代理:代理类的源码是在程序运行时动态生成的,通常借助JDK的反射机制实现。动态代理能够避免静态代理中代理类接口过多的问题,使得代码更加灵活和可扩展。
综上所述,代理设计模式是一种非常有用的设计模式,它可以在不修改原始对象的情况下,为其添加额外的功能或控制其访问。然而,在使用时也需要注意其可能带来的复杂性和性能问题。
二、实现例子
代理模式(Proxy Pattern)在Java中通常有两种实现方式:静态代理和动态代理。下面,我将分别给出这两种实现方式的例子。
1、静态代理
首先,定义一个接口(Subject)和它的实现类(RealSubject),然后创建一个代理类(Proxy)来实现同样的接口,并在代理类中持有一个实现类对象的引用。
// 接口
public interface Subject {
void request();
}
// 真实对象
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 代理对象
public class Proxy implements Subject {
private RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("Proxy: Checking access before forwarding the request.");
realSubject.request();
System.out.println("Proxy: Logging the time of request.");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Proxy proxy = new Proxy(realSubject);
proxy.request();
}
}
2、动态代理
动态代理通常使用Java的反射机制来动态地创建代理对象。java.lang.reflect.Proxy
类和 java.lang.reflect.InvocationHandler
接口是实现动态代理的关键。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 动态代理的处理器
public class DynamicProxyHandler implements InvocationHandler {
private Object subject;
public DynamicProxyHandler(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before invoking " + method);
Object result = method.invoke(subject, args);
System.out.println("After invoking " + method);
return result;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
InvocationHandler handler = new DynamicProxyHandler(realSubject);
Subject proxyInstance = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler);
proxyInstance.request();
}
}
在动态代理的例子中,我们没有手动创建一个代理类,而是使用了Proxy.newProxyInstance
方法来动态地创建一个代理对象。这个代理对象会在调用任何方法之前和之后执行一些额外的操作,这些操作是在DynamicProxyHandler
类中定义的。
三、与装饰者模式的区别与联系
1.区别
1、使用场景区别
代理模式侧重于对对象行为的特殊控制,不同的代理对象实现对被代理对象行为的不同的控制,并且这些代理的行为控制很少有组合的可能性。
装饰者模式侧重于对被装饰对象属性的扩展,不同的装饰者对象会为被装饰者对象添加不同的属性,并且这些属性可以任意嵌套组合。
2、模式实现区别
装饰者模式需要提供装饰对象为参数的构造函数,而代理对象则无该项要求,主要原因是装饰者模式需要支持嵌套组合属性。
二、联系
两者都是通过实现真实对象接口,并内置一个真实对象,通过操作该真实对象来实现接口。
结束语:如果这个设计模式对你有用,请点赞加收藏~