设计模式之代理模式(上) 静态代理与JDK动态代理

代理模式

  • 给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

静态代理

静态代理是由咱们编写好的类,在程序运行以前就已经编译好的的类,此时就叫静态代理。 说理论仍是比较懵逼的,直接上代码:java

抽象主题,能够想象成咱们的业务接口。设计模式

/**
 * 抽象主题。
 * @author wushuaiping
 * @date 2018/3/13 下午10:13
 */
public interface ISubject {

    /**
     *  好比如今有个业务功能,须要开启某项校验。
     */
    void enableCheck();
}

真实主题,能够想象成咱们对业务接口的实现类。学习

/**
 *  真实主题
 * @author wushuaiping
 * @date 2018/3/13 下午10:21
 */
public class RealSubject implements ISubject {

    public void enableCheck() {
        System.out.println("我开启了某项校验~~");
    }
}

可是有一天,我忽然想加个日志记录,可是我不想去改动原有的方法。那么咱们就可使用这种方式:测试

/**
 *  代理类
 * @author wushuaiping
 * @date 2018/3/13 下午10:23
 */
public class ProxySubject implements ISubject{

    private ISubject subject;

    public ProxySubject(ISubject subject){
        super();
        this.subject = subject;
    }

    // 对被代理对象的方法进行加强
    public void enableCheck() {
        before();
        subject.enableCheck();
        after();
    }

    private void before(){
        System.out.println("我记录一下启动校验前的相关日志。");
    }

    private void after(){
        System.out.println("我记录一下启动校验后的相关日志。");
    }
}

咱们使用静态代理后,来试试看这种方式能不能行?测试代码:this

public class Main{
    public static void main(String[] args) throws ApiException {
        ProxySubject proxy = new ProxySubject(new RealSubject());
        proxy.enableCheck();
    }
}

运行结果:设计

我记录一下启动校验前的相关日志
我开启了某项校验~~
我记录一下启动校验后的相关日志。

静态代理模式相对比较简单,可是缺点确定也是有的:代理

  1. 一个代理对象只能服务于一个类。若是有不少类须要记录日志的话,你的一个一个去实现。。累不死你。。日志

  2. 代理对象必须实现接口,如上。一个字:仍是累。code

动态代理

这里动态代理使用的是JDK的动态代理实现的,JDK的动态代理必须是目标对象实现接口才能够。也就是至关于咱们上面的业务实现类(RealSubject)。使用CGLIB就不用实现接口也可完成动态代理,可是今天时间很少了,明天还得搬砖,因此先把JDK动态代理学了,明天再学学CGLIB的动态代理。 代码以下:对象

要实现动态代理;须要先去实现InvocationHandler接口,这个接口提供了invoke方法,该方法相信用过反射或者AOP的同窗应该都比较熟悉,我这里就很少讲了。实现了这个后咱们能够调用目标方法了,可是咱们须要代理的对象还不知道从何而来,因此咱们还须要使用JDK提供的Proxy.newProxyInstance方法,第一个参数是目标代理类的类加载器,第二个参数是目标代理类实现的接口,第三个参数的话是目标代理类的调用处理程序就是InvokeHandler啦。用该方法能够生产代理对象。

/**
 *  使用Java的动态代理实现
 * @author wushuaiping
 * @date 2018/3/13 下午10:43
 */
public class DynamicProxy implements InvocationHandler {

    private Object target;

    public Object getProxyInstance(Object target){
        this.target = target;
        // 使用Java的获取代理实例方法来获取代理实例。。好绕啊。。反正就是获取代理实例-_-
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);

    }
    // 加强, 调用目标方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        // 由于咱们须要被加强的方法enableCheck是没有返回参数的,因此不须要返回值。
        // 若是有返回值 Object res = method.invoke(proxy, args); return res;就能够了
        method.invoke(target, args);
        after();
        return null;
    }

    private void before(){
        System.out.println("操做以前的日志记录~~");
    }

    private void after(){
        System.out.println("操做以后的日志记录~~");
    }
}

Test case

public static void main(String[] args) throws ApiException {
        DynamicProxy proxy = new DynamicProxy();
        ISubject subject = (ISubject)proxy.getProxyInstance(new RealSubject());
        subject.enableCheck();
    }

运行结果:

操做以前的日志记录~~
我开启了某项校验~~
操做以后的日志记录~~

今天的设计模式算是学完啦,抽象工厂模式感受我可能思惟不够抽象,因此到如今还没能理解抽象工厂模式到底能干吗?实际中有何用处?本文用于我的学习记录,有写的很差的地方,还请各位大佬指点一二!

good night!

相关文章
相关标签/搜索