设计模式-代理模式(Proxy)

来源:互联网 发布:释放443端口 仍被占用 编辑:程序博客网 时间:2024/04/27 15:46

代理模式的作用:为其他对象提供一种代理以控制堆这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标之间起到中介的作用。

代理模式角色:

  • 抽象角色:声明真实对象和和代理对象的共同接口
  • 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装
  • 真实角色:代理角色所代理的真实对象,是我们最终要引用的对象

静态代理和动态代理的实现:

静态代理

抽象角色:

public interface Subject {    void request();}

真实角色:

public class RealSubject implements Subject {    @Override    public void request() {        System.out.println("From real Subject");    }}

代理角色:

public class ProxySubject implements Subject {    private RealSubject realSubject;    @Override    public void request() {        this.preRequest();        if (null == realSubject) {            realSubject = new RealSubject();        }        realSubject.request();        this.postRequest();    }    private void preRequest() {        System.out.println("pre request");    }    private void postRequest() {        System.out.println("post request");    }}

测试代码:

public class Client {    public static void main(String[] args) {        Subject subject = new ProxySubject();        subject.request();    }}

如果按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外如果事先并不知道真实角色,该如何使用代理呢?这个问题我们可以通过java的动态代理类来解决

动态代理

所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当做这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你做实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

通过这种方式,被代理的对象(RealSubject)可以在运行时改变,控制的方式(DynamicSubject)也可以动态改变,从而实现了非常灵活的动态代理关系。

public interface Subject {  void request();}
public interface Subject1 {  void request1();}
public interface Subject2 {  void request2(int param1, String param2);}
public class RealSubject implements Subject, Subject1, Subject2 {  @Override  public void request() {    System.out.println("From real subject!");  }  @Override  public void request1() {    System.out.println("From real subject1!");  }  @Override  public void request2(int param1, String param2) {    System.out.println("From real subject2! param1: " + param1 + ",param2:" + param2);  }}
public class DynamicSubject implements InvocationHandler {  private Object sub;  public DynamicSubject(Object sub) {    this.sub = sub;  }  @Override  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    System.out.println("before calling: " + method);    if (args != null) {      Arrays.stream(args).forEach(System.out::println);      args[0] = (int) args[0] + 1;      args[1] = args[1].toString() + " append";    }    method.invoke(sub, args);    System.out.println("after calling: " + method);    return null;  }}
public class Client {  public static void main(String[] args) {    RealSubject realSubject = new RealSubject();    InvocationHandler handler = new DynamicSubject(realSubject);    Class<?> classType = handler.getClass();    Subject subject = (Subject) Proxy        .newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(),            handler);    subject.request();    System.out.println();    Subject1 subject1 = (Subject1) Proxy        .newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(),            handler);    subject1.request1();    System.out.println();    Subject2 subject2 = (Subject2) Proxy        .newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(),            handler);    subject2.request2(1,"string");    System.out.println(subject2.getClass());  }}

执行结果:

before calling: public abstract void com.huigod.dynamicproxy.Subject.request()From real subject!after calling: public abstract void com.huigod.dynamicproxy.Subject.request()before calling: public abstract void com.huigod.dynamicproxy.Subject1.request1()From real subject1!after calling: public abstract void com.huigod.dynamicproxy.Subject1.request1()before calling: public abstract void com.huigod.dynamicproxy.Subject2.request2(int,java.lang.String)1stringFrom real subject2! param1: 2,param2:string appendafter calling: public abstract void com.huigod.dynamicproxy.Subject2.request2(int,java.lang.String)class com.sun.proxy.$Proxy0

动态代理生成的class是最后打印的$Proxy0类,由于被代理的真实对象实现了不同的接口,所以代理类生成的对象可以由多态性转为每个接口,这个过程需要用到反射的机制。当执行代理类生成的对象任意方法的时候一定会执行代理对象中的invoke方法。