代理模式
顾名思义,代理模式提供了一个“代理人”对象,当“本人”太忙时,有些工作可以交给代理人。
好比如一个手机工厂,一开始它负责生产手机和卖手机,后来为了把人力充分利用到生产手机上,找了代理商来向客户卖手机。
几大roles
- Subject (目标接口/抽象类)
- RealSubject (“本人”)
- Proxy (“代理人”)
- Client (用户或主程序)
UML图看清关系:
好处
- 能够在目标对象实现的基础上,扩展功能;
- 能实现业务的分工,可以将公共的操作交给代理人,减少代码冗余性。
- 在真正需要“本人”才能做的“重活时”再生成“本人”实例,使用代理人来提升速度。
有主要三大形式
- 静态代理
- 动态代理 (JDK代理)
- Cglib代理 (属于动态代理)
静态代理
可以按照上面的UML图写出一个例子程序,这里就不展示了。
该种方式的缺点是:
一个真实对象就会产生一个代理对象,代码量会翻倍,开发效率会变低。
JDK代理
本质是反射机制。
JDK实现代理只需要使用newProxyInstance方法。
我们可以通过一开始举的手机商家的例子,代码实现:
//目标接口
public interface SellPhone {
public void sell();
public void produce();
}
//本人实现了两个功能
public class Real implements SellPhone{
@Override
public void sell() {
System.out.println("直接卖手机");
}
@Override
public void produce() {
System.out.println("生产手机");
}
}
//生产代理类的对象,就像是代理类工厂
public class ProxyInvocationHandler implements InvocationHandler {
private SellPhone sellPhone;
public void setSellPhone(SellPhone sellPhone){
this.sellPhone = sellPhone;
}
//通过该方法反射得到代理对象
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),sellPhone.getClass().getInterfaces(),this);
}
//代理类来卖手机
public void sell(){
System.out.println("卖手机");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(sellPhone, args);
//加入卖手机方法
sell();
return result;
}
}
public class Client {
public static void main(String[] args) {
SellPhone real = new Real();
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setSellPhone(real);
SellPhone proxy = (SellPhone) pih.getProxy();
proxy.produce();
}
}结果:
从结果可以看出:
我们卖手机调用的是代理类的方法,而不是本人的方法。
JDK这个ProxyInvocationHandler 也可以实现其他类的代理,只要把加载器,接口和当前对象传入Proxy.newProxyInstanc方法即可。
Cglib代理
静态代理和JDK代理模式都要求目标对象是实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候可使用目标对象子类来实现代理-这就是Cglib代理。
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP,实现方法拦截。
使用Cglib代理,需要导入cglib.jar。
代理模式的变体
- HTTP代理
它是位于Web服务器和HTTP客户端之间,为Web页面提供高速缓存等功能的软件,我们可以认为它是一种代理模式。 - 远程代理
可以让我们不用在意“本人”是否在远程网络上,相当于在本地建立了一个代理对象。 - Access代理
在调用RealSubject对象的功能时设置访问权限。

京公网安备 11010502036488号