【重温设计模式】代理模式
前言
代理模式最典型的应用就是AOP,本文结合主要讲解了代理模式的几种实现方式:静态代理和动态代理,这里动态代理又可以分为jdk代理和Cglib代理。
代理,顾名思义,即代替被请求者来处理相关事务。代理对象一般会全权代理被请求者的全部只能,客户访问代理对象就像在访问被请求者一样,虽然代理对象最终还是可能会访问被请求者,但是其可以在请求之前或者请求之后进行一些额外的工作,或者说客户的请求不合法,直接拒绝客户的请求。如下图所示为代理模式的一份简图:
image代理模式的角色:
- ISubject:代理者与被代理者共同实现的接口,可以理解为需要代理的行为;
- SubjectImpl:被代理者,其为具有某种特定行为的实现者;
- SubjectProxy:代理者,其会全权代理SubjectImpl所具有的功能,在实现其功能的基础上做一些额外的工作;
- Client:客户端,客户端访问代理者与访问被代理者具有类似的效果,其无法区分访问的是代理者还是被代理者。
1. 静态代理
静态代理模式也即上图中描述的这种模式,从图中可以看出,SubjectProxy保存一个ISubject实例,当客户端调用SubjectProxy的request()方法时,其除了做额外的工作之外,还会调用ISubject实例的request()方法。如下是这三个类的一个简单实现:
public interface ISubject {
void request();
}
public class SubjectImpl implements ISubject {
@Override
public void request() {
System.out.println("request SubjectImpl.");
}
}
public class SubjectProxy implements ISubject {
private ISubject target;
public SubjectProxy(ISubject target) {
this.target = target;
}
@Override
public void request() {
System.out.println("before safety check.");
target.request();
System.out.println("after safety check.");
}
}
可以看到,代理对象在调用被代理对象的方法之前和之后都打印了相关的语句。如下是客户端请求示例:
public class Client {
@Test
public void testStaticProxy() {
ISubject subject = new SubjectImpl();
ISubject proxy = new SubjectProxy(subject);
proxy.request();
}
}
运行上述用例,可得到如下结果:
before safety check.
request SubjectImpl.
after safety check.
优点:
从客户端访问方式可以看出,客户端获取的是一个实现ISubject接口的实例,其在调用的request()方法实际上是代理对象的request()方法。这种代理方式称为静态代理,并且这种代理方式也是效率最高的一种方式,因为所有的类都是已经编写完成的,客户端只需要取得代理对象并且执行即可。
缺点:
静态代理虽然效率较高,但其也有不可避免的缺陷。可以看到,客户端在调用代理对象时,使用的是代理对象和被代理对象都实现的一个接口,我们可以将该接口理解为定义了某一种业务需求的实现规范。如果有另外一份业务需求(如进行数据修改),其与当前需求并行的,没有交集的,但是其在进行正常业务之外所做的安全验证工作与当前需求是一致的。那我们要实现相同的对象代理功能(安全验证),静态代理方式需要为每个接口实现一个代理类,而这些代理类中的代码几乎是一致的。这在大型系统中将会产生很大的维护问题。
2. 动态代理
可以查看我的另一篇文章:
JDK动态代理和CGLIB动态代理:https://www.jianshu.com/p/085170b0228f