一、简述

代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。
其实代理模式无论是在日常开发还是设计模式中,基本随处可见,中介者模式中的中介者对象也是代理模式的应用,其他的对象的交互都是交给了中介者对象处理的。而在生活中就更多类似代理模式的例子,例如:抢票插件、科学上网等等。
11 代理模式 - 图1

  1. /**抽象主题*/
  2. public interface Subject {
  3. public void visit();
  4. }
  1. /**被代理主题*/
  2. public class RealSubject implements Subject {
  3. @Override
  4. public void visit() {
  5. System.out.print("this is real subject");
  6. }
  7. }
  1. /**代理主题*/
  2. public class ProxySubject implements Subject {
  3. //真实主题
  4. private Subject realSubject;
  5. public ProxySubject(@NotNull Subject subject){
  6. realSubject = subject;
  7. }
  8. @Override
  9. public void visit() {
  10. System.out.print("proxy start");
  11. realSubject.visit();
  12. System.out.print("proxy end");
  13. }
  14. }
  1. /**客户类*/
  2. public class Client {
  3. public static void main(String[] args){
  4. //创建被代理对象
  5. RealSubject realSubject = new RealSubject();
  6. //创建代理对象
  7. ProxySubject proxySubject = new ProxySubject(realSubject);
  8. //调用方法
  9. proxySubject.visit();
  10. }
  11. }
  1. 输出结果:
  2. proxy start
  3. this is real subject
  4. proxy end

二、动态代理

上一部分中所讲述的,其实是静态代理,也就是在代码的编译阶段生成代理类来完成代理对象的一系列操作。而动态代理则是在运行时动态生成代理类对象。代理对象的生成是利用JDK中java.lang.reflect.Proxy类,使用newProxyInstance方法可以创建一个我们所需要的代理对象

  1. public static Object newProxyInstance(ClassLoader loader,
  2. Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
  3. //代码省略...
  4. }

newProxyInstance方法是Proxy的一个静态方法,并且接收三个参数
其中InvocationHandler的invoke方法如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;`
返回值则是代理对象调用方法时所返回的值
依然使用Subject作为例子,看看简单的代码实现(代码没有封装)

  1. //创建被代理对象
  2. Subject realSubject = new RealSubject();
  3. //创建代理对象
  4. Subject subject = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
  5. new Class[]{Subject.class},
  6. new InvocationHandler() {
  7. @Override
  8. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  9. return method.invoke(realSubject, args);
  10. }
  11. });
  12. subject.visit();

从代码上来看,比之前的静态代理要简单很多,没有那么多的类和对象;但是相对的在代码性能上有所牺牲,而且对于不太熟悉反射相关的知识的开发者并不是太友好。
通过反射类Proxy和InvocationHandler回调接口实现的JDK动态代理,要求被代理类必须实现一个接口,但事实上并不是所有类都有接口,对于没有实现接口的类,便无法使用该方方式实现动态代理。

三、其他代理分类

静态代理和动态代理是代码方面来区分的代理模式,也可以从适用范围来区分不同类型的代理实现
这里要注意的是,静态和动态代理都可以应用于上述4种情形,两者是各自独立的变化。

四、总结

代理模式使用非常广泛,基本在其他的设计模式中也能看到代理模式的影子,但是使用时针对性较强,而且模式本身并没有什么突出的优缺点,基本上可以放心使用