代理模式

落花浮王杯 提交于 2020-01-25 05:13:51

理解

    用演员和经纪人来形容代理模式最恰当不过,一个演员每天要拍电影,拍广告,拍电视剧有很多事情要做,但是每天有很多人来找他谈合作,以及各种行程需要合理安排,如果这些全都要演员自己来弄肯定忙不过来,容易出错,所以就有了经纪人(代理人),这些代理人帮演员打理行程,应对合作商,演员只需要专心于演戏就好了。演员和经纪人之间其实就是代理模式。

作用

    在我们写程序的时候也经常遇到,我们的业务代码负责业务流程的控制,但是除了业务流程有时候还有一些其他的事情,比如事务的管理,对象的创建之类的,这时就需要有一个代理类能帮业务代码处理这些工作,让业务代码专心于业务流程的处理,所以就需要代理模式了。

实现

    代理模式分为静态代理和动态代理之分,静态代理指的是代理类通过硬编码来创建,比较简单,而动态代理指代理类在jvm运行过程中自动创建出来,需要使用java的代理包。

静态代理

定义接口:

public interface Work {

    public void handWork(int giveMoney);
}

构建被代理者:

public class Worker implements  Work {

    @Override
    public void handWork(int giveMoney) {
        System.out.println("hard working");
    }
}

构建代理人:


public class WorkerProxy implements Work {


    private Worker worker;

    public WorkerProxy() {
        worker = new Worker();
    }


    @Override
    public void handWork(int giveMoney) {
        if (isAccept(giveMoney)) {
            worker.handWork(giveMoney);
            acceptMoney(giveMoney);
        }
    }


    private void acceptMoney(int giveMoney) {
        System.out.println("accept money:" + giveMoney);
    }

    private boolean isAccept(int giveMoney) {
        if (giveMoney < 200) {
            System.out.println("money is not enough");
            return false;
        }
        return true;
    }
}

测试:


    public static void main(String[] args) {
        Work work = new WorkerProxy();
        work.handWork(100);
        work.handWork(500);
    }

输出结果:

money is not enough
hard working
accept money:500

    被代理者只要专注于努力工作就好了,代理者来判断是否要做这件工作,以及做完工作之后收款。

动态代理

    动态代理更为灵活,在spring的AOP,各类rpc框架中都有使用,动态代理不在需要硬编码构建方法代理类,所以前面静态代理中只需要保留接口类,和被代理类即可:

定义接口:

public interface Work {

    public void handWork(int giveMoney);
}

构建被代理者:

public class Worker implements  Work {

    @Override
    public void handWork(int giveMoney) {
        System.out.println("hard working");
    }
}

之后利用java的动态代理方法:java.lang.reflect.Proxy#newProxyInstance构架代理类:

    public static void main(String[] args) {
        Work work = new Worker();
        Work proxy1 =(Work) Proxy.newProxyInstance(work.getClass().getClassLoader(),work.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if(isAccept((int)args[0])){
                    method.invoke(work,args);
                    acceptMoney((int)args[0]);
                }
                return null;
            }


            private boolean isAccept(int giveMoney) {
                if (giveMoney < 200) {
                    System.out.println("money is not enough");
                    return false;
                }
                return true;
            }


            private void acceptMoney(int giveMoney) {
                System.out.println("accept money:" + giveMoney);
            }
        });
        proxy1.handWork(1);
        proxy1.handWork(300);
    }

执行结果:

money is not enough
hard working
accept money:300

和静态代理完全一样,其中核心代码是这一样:

        Work proxy1 =(Work) Proxy.newProxyInstance(work.getClass().getClassLoader(),work.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                return null;
            }
        });

newProxyInstance传入的三个参数分别为被代理者的类加载器,被代理者实现的接口,以及即将创建出来的代理者的工作接口InvocationHandler,而InvocationHandler接口中的invoke方法三个参数proxy为被创造出来的代理对象,method为代理了的那个方法,args为外部调用该方法时传入的参数。
    如果只看上面的这个案例,我们可能感觉动态代理其实也没有什么优越性,无非就是把提前写好的静态类放到了需要执行时来动态创建,该写的代码一行也没少。但是正是这一特性成就了Spring的AOP,因为Spring框架是事先无法知道各种业务场景下需要什么样的代理类的的,所以无法通过提前编写静态类放到spring包中供大家使用,只有大家开发业务的时候,根据具体情况才知道到底需要什么样的代理类。
    另一种情况就是当各种代理其实做的工作都一样时,动态代理就有了优越性,比如我们的事务处理,比如我们的rpc请求,其实各种代理做的事情都是一样的,但是如果在静态代理模式下,就算再简单你也必须对每一个接口写一个静态代理类,而动态代理就不需要了。
    上面说到rpc中的静态代理,其实rpc的客户端根本就没有被代理对象,他们只有一个接口,在这种情况下,其实上面的代码就变成了如下:

    public static void main(String[] args) {
        Work proxy =(Work) Proxy.newProxyInstance(Work.class.getClassLoader(), new Class[]{Work.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("try to demand remote work to work hard……");
                return null;
            }
        });
        proxy.handWork(11);
    }

可以看到代理类如果不需要最终去执行被代理者的方法的话,完全不需要有被代理者,自己就是一个被动态创造出来的工作类,这一特性成就了java的rpc框架。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!