首页 > 代码库 > 代理模式

代理模式

宁愿做过了后悔,也不要错过了后悔。趁现在还有精力与时间来追求梦想,那就勇敢一些,走出舒适圈,你会看到更美的风景。

今天我们来将一下代理模式(Proxy Pattern),在讲代理模式之前,我们得先知道什么是代理,什么是代理呢,比如你在北京租房子,但是怕被骗,所以你找到了链家,我爱我家这些中介公司帮你找房子,那么链家,我爱我家就是个代理,代理帮你找到合适的房子,再比如,你女朋友今天不在家,但是她的快递来了,所以她就让你帮她取一下,那么你就是你女朋友的代理,其实代理在生活中无处不在,说到这里,你应该对代理有种感觉了吧。

我们学习代理之前,老样子,先得知道它的定义,作用,好处,那么我们才愿意学习它,不然谁会学习它呢?

  1. 定义
    就是为其他对象提供一种代理来控制对你所访问对象。其实看了概念会有些模糊,没关系,往下看。
  2. 使用场景
    当你无法或不想直接访问摸个对象,或者访问某个对象的权限不允许的情况下,可以通过一个代理来访问。说道这里,也许有的同学已经看懵逼了,但是定义总归是这样,继续往下看。
  3. 代理模式代码实现
    我们今天来实现一个代理的列子。
    比如在生活中,你的家里家务都是老婆大人来干的,洗碗,拖地,做饭,但是女生嘛,每个月都有那么几天,所以再不好的男人在这几天都要帮老婆大人来干完这些活,所以,你就是老婆大人的代理。那么我们今天用代码来完成一下吧!

首先如果你帮你老婆大人干这么些事情,那么老婆大人和你实现的功能是不是一样的?那么该怎么开头呢?对了,委托人(老婆大人)和代理人(你)要实现相同的功能接口。
那么现在我们先来定义一个功能接口:

public interface HouseWork {

    public void doheDishes();//洗碗
    public void mopFloor();//拖地
    public void cook();//做饭
}

OK!,那么以前这些事情都是老婆大人来完成的,那么我们写出老婆大人完成的过程。

public class Wife implements HouseWork {


    @Override
    public void doheDishes() {
        System.out.println("碗洗完了");
    }

    @Override
    public void mopFloor() {
        System.out.println("地拖完了");
    }

    @Override
    public void cook() {
        System.out.println("饭做好了");
    }
}

不好了,这几天老婆大人那几天来了,那么这些任务都是你的了,小伙子。不是,老婆大人不赖也应该帮老婆大人完成一下这些工作啊!!!

public class Husband implements HouseWork {

    private Wife wife;

    public Husband() {
    }

    public Husband(Wife wife) {
        this.wife = wife;
    }

    @Override
    public void doheDishes() {
        wife.doheDishes();
    }

    @Override
    public void mopFloor() {
        wife.mopFloor();
    }

    @Override
    public void cook() {
        wife.cook();
    }
}

我们在看下运行代码:

public class Main {
    public static void main(String[] args){
        Wife wife = new Wife();
        Husband husband = new Husband(wife);
        husband.doheDishes();
        husband.mopFloor();
        husband.cook();
    }
}

运行结果:

碗洗完了
地拖完了
饭做好了

哈哈,有没有觉得代理模式很简单啊!那么现在有人要问了,你老公做家务的方法体里面不是都是老婆在做吗?大兄弟别钻牛角尖儿, 学java最大的好处是什么?对,是面向对象,现在做事儿的对象是你,不是你老婆大人,所以,做完这些事儿的人就是你。

说到这里,如果是这样,那么如果张三老婆那几天来了,就得找个代理,李四老婆来了就得请个代理,代码实现起来这得有多少代理呢?那么我找个保姆公司,让保姆公司来做,那么不是就能省去不少的代码了吗??我只能说小伙子,你真厉害,看到了重点。

其实在代码中实现代理的方式分为两种,一种是静态代理,一种是动态代理。

  1. 静态代理
    静态代理如上的例子一样,代理者的代码有程序员或者通过一些自动化工具来完成,也就是我们的代码在执行前,代理类的class文件就已经存在了。
  2. 动态代理
    而动态代理则相反,通过反射机制动态生成代理者的对象,也就是在写代码的时候根本不用关系代理谁,代理谁我们将会在执行阶段决定。java中为我们提供了一个Proxy类,只要我们实现InvocationHandler来实现该接口即可,该方法要重写一下invoke方法。说到这里,也许又有人懵逼了,耐心点,我们先休息一下,看张美图缓解一下视觉疲劳。
    技术分享

好了,接下来我们用代码实现一下我们的动态代理:
上面我们说了有个保姆公司可以全部把这些事情都做完,那么我们就来写这么一个例子

首先,我们看一下java中Proxy这个类提供创建动态代理的方法

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
ClassLoader:委托对象的classLoader对象,就是我们的wife对象的classLoader对象
interfaces:功能接口的Class对象
h:我们实现的InvocationHandler
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

Ok,话不多说,我们看一下我们自己写的万能InvocationHandler,怎么能变成一个动态代理的关键,我们创建一个保姆公司的万能代理

public class HelpCompany implements InvocationHandler{

    private Object object;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       Object o = method.invoke(object,args);
        return o;
    }


}

好了,这时候就写好了,我们写两个委托对象,张三的老婆大人和李四的老婆大人,同样是做那么几件事

public class LisiWife implements HouseWork {


    @Override
    public void doheDishes() {
        System.out.println("LisiWife碗洗完了");
    }

    @Override
    public void mopFloor() {
        System.out.println("LisiWife地拖完了");
    }

    @Override
    public void cook() {
        System.out.println("lisiWife饭做好了");
    }
}
public class LisiWife implements HouseWork {


    @Override
    public void doheDishes() {
        System.out.println("LisiWife碗洗完了");
    }

    @Override
    public void mopFloor() {
        System.out.println("LisiWife地拖完了");
    }

    @Override
    public void cook() {
        System.out.println("lisiWife饭做好了");
    }
}

接下来,我们看看我们运行的主工程中怎么能动态的代理这两位老婆大人完成她们的工作

public class CompanyMain {
    public static void main(String[] args){
        ZhangsanWife zhangsanWife = new ZhangsanWife();
        ClassLoader zhangsanClassLoader = zhangsanWife.getClass().getClassLoader();
        HelpCompany helpCompany = new HelpCompany(zhangsanWife);
        HouseWork houseWork = (HouseWork) Proxy.newProxyInstance(zhangsanClassLoader, new Class[]{HouseWork.class}, helpCompany);
        houseWork.doheDishes();
        houseWork.mopFloor();
        houseWork.cook();


        LisiWife lisiWife = new LisiWife();
        ClassLoader lisiClassLoader = lisiWife.getClass().getClassLoader();
        HelpCompany helpCompany_ = new HelpCompany(lisiWife);
        HouseWork houseWork_ = (HouseWork) Proxy.newProxyInstance(lisiClassLoader,new Class[]{HouseWork.class},helpCompany_);
        houseWork_.doheDishes();
        houseWork_.mopFloor();
        houseWork_.cook();

    }
}

代码很简单

我们来看下运行结果:

ZhangsanWife碗洗完了
ZhangsanWife地拖完了
ZhangsanWife饭做好了
LisiWife碗洗完了
LisiWife地拖完了
lisiWife饭做好了

代理模式到现在我们就讲完了,有没有感觉特别强大!
好了,我们扯点别的,现在Android中有种技术叫做插件话,通过hook技术来将源码中的部分代码用代理执行,在代理中修改自己想定制的内容,但是不会影响整个系统的运行,屌不屌,也许你现在看完这篇文章还不了解,那么就多看几次,看第二遍的想法和看第一遍的想法肯定不一样,相信我哦!源码在底部,学了这么多了,来张美图缓解一下继续我们接下来的学习吧!
技术分享
源码请用IntelJ打开
源码地址:https://github.com/xingege662/ProxyPattern

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    代理模式