设计模式之代理模式

1,362 阅读3分钟
原文链接: huanxi.pub

代理对于我们并不陌生,在 QQ 群,微信群中,时不时会出现一两个人招代理,XX 代理,XX 代理,对于我们编程中其实也有代理,将原本属于自己的任务委托给别人去执行。我们来一探究竟。

定义:

为其他对象提供一种代理,以控制对这个对象的访问。

代理模式的通用类图:

common_proxy

  • Subject 抽象主题角色:
    抽象主题类可以是抽象类或者接口
  • RealSubject 具体主题角色
    被代理的角色。
  • Proxy 代理主题角色
    代理类。

优点:

  • 职责清晰
    例如例子中的 RealSubject 只关心具体的业务逻辑,而像 before()after() 等逻辑就不需要它来操心。
  • 高扩展性

应用场景

例如 Spring AOP,Struts 表单对象映射等。也像生活中的游戏代练,找律师打官司,微商代理等。

简单代理

简单代理通用代码:

Subject.java

public interface Subject {
    void request();
}

RealSubject.java

public class RealSubject implements Subject {
    public void request() {
        System.out.println("someone request...");
    }
}

Proxy.java

public class Proxy implements Subject {
    private Subject subject;
    public Proxy(Subject subject) {
        this.subject = subject;
    }
    public void request() {
        this.subject.request();
    }
}

客户端调用:
Client.java

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

这是最简单的一个代理。

如果我们想要在调用 request() 之前或之后增加其他方法,那只要改写 Proxy 中的 request() 方法即可,如:

public class Proxy implements Subject {
    private Subject subject;
    public Proxy(Subject subject) {
        this.subject = subject;
    }
    public void request() {
        before(); 
        this.subject.request();
        after(); 
    }
}

动态代理

动态代理运用到反射机制。

动态代理在实现阶段并不关心代理谁,而在运行阶段才指定代理的是哪一个对象。

面向切面编程(AOP)的核心就是动态代理。

我们将上面的简单代理改为动态代理:

DynamicProxyIH.java

public class DynamicProxyIH implements InvocationHandler {
    Object obj = null;
    public DynamicProxyIH(Object obj) {
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(this.obj, args);
    }
}

实现 JDK 内置的 InvocationHandler 接口。该接口的 invoke 方法会完成对真实方法的调用。也就是说给定一个接口,动态代理会宣城已经实现了该接口的所有方法了。

更改后的客户端代码:

Client.java

public class Client {
    public static void main(String[] args) {
        Subject subject = new RealSubject();
        Proxy proxy = new Proxy(subject);
        proxy.request();
        dynamicProxy();
    }
    public static void dynamicProxy() {
        Subject subject = new RealSubject();
        ClassLoader classLoader = subject.getClass().getClassLoader();
        InvocationHandler dynamicProxyIH = new DynamicProxyIH(subject);
        Subject dynamicSubject = (Subject) java.lang.reflect.Proxy.newProxyInstance(classLoader, new Class[]{Subject.class}, dynamicProxyIH);
        dynamicSubject.request();
    }
}

动态代理通用类图:
dynamic_common

我们可以把上部分 Client 中的动态获取实例的代码抽出来,叫做 SubjectDynamicProxy,让它继承 DynamicProxy

DynamicProxy.java

public class DynamicProxy {
    public static  T getInstance(ClassLoader classLoader, Class[] interfaces, InvocationHandler invocationHandler) {
        return (T) java.lang.reflect.Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

SubjectDynamicProxy.java

public class SubjectDynamicProxy extends DynamicProxy {
    public static  T newInstance(Subject subject) {
        ClassLoader classLoader = subject.getClass().getClassLoader();
        Class[] classes = subject.getClass().getInterfaces();
        InvocationHandler invocationHandler = new MyInvocationHandler(subject);
        return getInstance(classLoader, classes, invocationHandler);
    }
}

MyInvocationHandler.java

public class MyInvocationHandler implements InvocationHandler {
    private Object object;
    public MyInvocationHandler(Object object) {
        this.object = object;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(object, args);
    }
}

Client.java 增加方法

public static void commonDynamicProxy() {
    Subject subject = new RealSubject();
    Subject proxy = SubjectDynamicProxy.newInstance(subject);
    proxy.request();
}

如上就是通用的动态代理方法。我们可以在 MyInvocationHandler 实现我们自己的逻辑处理。实现 AOP

本文参考: 设计模式之禅

来个两毛钱砸死我啊,我也不想这么棒棒的啊! 赏 yuhuanxi WeChat Pay

微信打赏

yuhuanxi Alipay

支付宝打赏