简述-代理模式

介绍

代理代理,就是找个中间人来做代理处理某件事。不过读了书后感觉挺坑的,说好的代理,只是暴露相对客户端来说,实际执行的,还是直接人,泪奔。不过它的目的不是帮你执行,而是代理控制对象的访问。这个模式是个编程好帮手,使用时候多多的,Android源码中,我们一直都有接触到到AMS的使用就用到了代理模式

UML

简述-代理模式_第1张图片

使用场景

  • 如果无法或者不想直接访问某个对象

事例

爸爸要通知孩子做家务,和玩耍,但是对于爸爸不想直接叫动孩子,想通过妈妈来叫孩子做家务和玩耍,那么妈妈就是中间的代理对象,孩子就是被代理对象。

  • 先看看静态代理方式
  1. 先定义任务接口
public interface DoHomeWork {

    /**
     * 做家务
     */
    void doHomeWork();

    /**
     * 玩耍
     *
     * @param time 时间
     */
    void play(int time);
}
  1. 代理对象与被代理对象需要实现相同的接口,定义妈妈和孩子
public class Child implements DoHomeWork {
    @Override
    public void doHomeWork() {
        System.out.println("做家务了");
    }

    /**
     * 玩耍
     */
    @Override
    public void play(int time) {
        System.out.println("玩耍"+time+"小时");
    }
}

public class Mather implements DoHomeWork {

    private DoHomeWork child;

    public Mather(DoHomeWork child) {
        this.child = child;
    }

    @Override
    public void doHomeWork() {
        child.doHomeWork();
    }

    @Override
    public void play(int time) {
        child.play(time);
    }
}

  1. 爸爸作为客户端来进行调用做家务
/*
         * 静态代理
         * 孩子要做家务。但是不像自己来操作,交由妈妈来代理操作,则妈妈持有孩子对象
         */
        DoHomeWork child = new Child();
        DoHomeWork mather = new Mather(child);
        mather.doHomeWork();

最后的结果就是,爸爸通过妈妈让孩子做了家务

这种静态代理方式比较简单,而且需要将代理对象也给申明出来。

除了静态代理,另外还有一种为动态代理,因为执行的最后都是被代理对象来执行,就是也可以不需要显示的申明代理对象,动态创建代理对象方式,那么一起看看。

  • 动态代理方式
  1. 创建实现了InvocationHandler的动态代理类,jdk里的动态代理类需要实现它
public class DynamicProxy implements InvocationHandler {

    /**
     * 被代理类的引用,就是这个引用,后续调用的就是它的方法
     */
    private Object object;

    public DynamicProxy(Object object) {
        this.object = object;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行前");
        System.out.println("执行的方法:method" + method+",参数:");
        Object invoke = method.invoke(object, args);
        System.out.println("执行后");
        return invoke;
    }
}
  1. 爸爸重新使用动态方式来叫孩子做家务和玩耍
        /*
         * 动态代理
         */
        //创造被代理对象
        DoHomeWork childDo = new Child();
        //创造代理对象
        InvocationHandler dynamicProxy = new DynamicProxy(childDo);
        //获取被代理对象的classLoader
        ClassLoader classLoader = dynamicProxy.getClass().getClassLoader();
        //通常使用的是这种方式创建,jdk3之后就有的代理方式
        /*
         * 第一个参数 getClassLoader() ,这里使用dynamicProxy这个类的ClassLoader对象来加载我们的代理对象
         * 第二个参数interfaces,真实对象实现的接口,这样我就能调用这组接口中的方法了
         * 第三个参数handler, 我们这里将这个代理对象关联到了上方的InvocationHandler这个对象上,后面执行就是靠它的invoke了
         */
        DoHomeWork dynamic = (DoHomeWork) java.lang.reflect.Proxy.newProxyInstance(classLoader,
                new Class[]{DoHomeWork.class}, dynamicProxy);
        dynamic.doHomeWork();
        dynamic.play(3);

输出:

执行前
执行的方法:methodpublic abstract void pattern.proxy.DoHomeWork.doHomeWork(),参数:
做家务了
执行后
执行前
执行的方法:methodpublic abstract void pattern.proxy.DoHomeWork.play(int),参数:
玩耍3小时
执行后

咱们使用的是newProxyInstance出来的代理对象去调用执行,这里可以看到执行的方法和参数与执行结果,这就是动态代理。

ps:Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,这里转成了成DoHomeWork,仅仅是因为生成的对象也实现了这个接口,看看第二个参数是传入接口组,也可以转换为其中实现了的任何一个接口。

总结:代理模式也是经常使用的结构型模式之一。它的思想似乎就是,不直接叫执行者去干,中间增加一个代理人,在这个代理人上就可以再做文章了,比如AOP也是基于动态代理来实现的,我们在编码过程中或多或少都会接触到它。

你可能感兴趣的:(设计模式)