美文网首页设计模式
设计模式(四)——搞懂什么是代理模式

设计模式(四)——搞懂什么是代理模式

作者: xiaosen一L | 来源:发表于2019-07-08 10:43 被阅读5次

    代理模式

    定义:为其他对象提供一种代理以控制对这个对象的访问

    代理模式的通用类图

    上图中,Subject是一个抽象类或者接口,RealSubject是实现方法类,具体的业务执行,Proxy则是RealSubject的代理,直接和client接触的。

    代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

    代理模式优点

    • 职责清晰
    • 高扩展,只要实现了接口,都可以用代理。
    • 智能化,动态代理。

    分类

    代码:GitHub

    1、静态代理

    以租房为例,我们一般用租房软件、找中介或者找房东。这里的中介就是代理者。

    首先定义一个提供了租房方法的接口。

    public interface IRentHose {
        void rentHose();
    }
    

    定义租房的实现类

    public class RentHose implements IRentHose {
        @Override
        public void rentHose() {
            System.out.println("租了一间房子。。。");
        }
    }
    

    我要租房,房源都在中介手中,所以找中介

    public class IntermediaryProxy implements IRentHose {
    
        private IRentHose rentHose;
    
        public IntermediaryProxy(IRentHose irentHose){
            rentHose = irentHose;
        }
    
        @Override
        public void rentHose() {
            System.out.println("交中介费");
            rentHose.rentHose();
            System.out.println("中介负责维修管理");
        }
    }
    

    这里中介也实现了租房的接口。

    再main方法中测试

    public class Main {
    
        public static void main(String[] args){
            //定义租房
            IRentHose rentHose = new RentHose();
            //定义中介
            IRentHose intermediary = new IntermediaryProxy(rentHose);
            //中介租房
            intermediary.rentHose();
        }
    }
    

    返回信息

    交中介费
    租了一间房子。。。
    中介负责维修管理
    

    这就是静态代理,因为中介这个代理类已经事先写好了,只负责代理租房业务

    2、强制代理

    如果我们直接找房东要租房,房东会说我把房子委托给中介了,你找中介去租吧。这样我们就又要交一部分中介费了,真坑。

    来看代码如何实现,定义一个租房接口,增加一个方法。

    public interface IRentHose {
        void rentHose();
        IRentHose getProxy();
    }
    

    这时中介的方法也稍微做一下修改

    public class IntermediaryProxy implements IRentHose {
    
        private IRentHose rentHose;
    
        public IntermediaryProxy(IRentHose irentHose){
            rentHose = irentHose;
        }
    
        @Override
        public void rentHose() {
            rentHose.rentHose();
        }
    
        @Override
        public IRentHose getProxy() {
            return this;
        }
    }
    

    其中的getProxy()方法返回中介的代理类对象

    我们再来看房东是如何实现租房:

    public class LandLord implements IRentHose {
    
        private IRentHose iRentHose = null;
    
        @Override
        public void rentHose() {
            if (isProxy()){
                System.out.println("租了一间房子。。。");
            }else {
                System.out.println("请找中介");
            }
        }
    
        @Override
        public IRentHose getProxy() {
            iRentHose = new IntermediaryProxy(this);
            return iRentHose;
        }
    
        /**
         * 校验是否是代理访问
         * @return
         */
        private boolean isProxy(){
            if(this.iRentHose == null){
                return false;
            }else{
                return true;
            }
        }
    }
    

    房东的getProxy方法返回的是代理类,然后判断租房方法的调用者是否是中介,不是中介就不租房。

    main方法测试:

        public static void main(String[] args){
    
            IRentHose iRentHose = new LandLord();
            //租客找房东租房
            iRentHose.rentHose();
            //找中介租房
            IRentHose rentHose = iRentHose.getProxy();
            rentHose.rentHose();
    
    
        }
    
    }
    
    请找中介
    租了一间房子。。。
    

    看,这样就是强制你使用代理,如果不是代理就没法访问。

    3、动态代理

    我们知道现在的中介不仅仅是有租房业务,同时还有卖房、家政、维修等得业务,只是我们就不能对每一个业务都增加一个代理,就要提供通用的代理方法,这就要通过动态代理来实现了。

    中介的代理方法做了一下修改

    public class IntermediaryProxy implements InvocationHandler {
    
    
        private Object obj;
    
        public IntermediaryProxy(Object object){
            obj = object;
        }
    
        /**
         * 调用被代理的方法
         * @param proxy
         * @param method
         * @param args
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = method.invoke(this.obj, args);
            return result;
        }
    
    }
    

    在这里实现InvocationHandler接口,此接口是JDK提供的动态代理接口,对被代理的方法提供代理。其中invoke方法是接口InvocationHandler定义必须实现的, 它完成对真实方法的调用。动态代理是根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理就会实现接口下所有的方法。通过 InvocationHandler接口, 所有方法都由该Handler来进行处理, 即所有被代理的方法都由 InvocationHandler接管实际的处理任务。

    这里增加一个卖房的业务,代码和租房代码类似。

    main方法测试:

    public static void main(String[] args){
    
        IRentHose rentHose = new RentHose();
        //定义一个handler
        InvocationHandler handler = new IntermediaryProxy(rentHose);
        //获得类的class loader
        ClassLoader cl = rentHose.getClass().getClassLoader();
        //动态产生一个代理者
        IRentHose proxy = (IRentHose) Proxy.newProxyInstance(cl, new Class[]{IRentHose.class}, handler);
        proxy.rentHose();
    
        ISellHose sellHose = new SellHose();
        InvocationHandler handler1 = new IntermediaryProxy(sellHose);
        ClassLoader classLoader = sellHose.getClass().getClassLoader();
        ISellHose proxy1 = (ISellHose) Proxy.newProxyInstance(classLoader, new Class[]{ISellHose.class}, handler1);
        proxy1.sellHose();
    
    }
    
    租了一间房子。。。
    买了一间房子。。。
    

    在main方法中我们用到了Proxy这个类的方法,

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
    

    loder:类加载器,interfaces:代码要用来代理的接口, h:一个 InvocationHandler 对象 。

    InvocationHandler 是一个接口,每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。

    public interface InvocationHandler {
    
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }
    

    InvocationHandler 内部只是一个 invoke() 方法,正是这个方法决定了怎么样处理代理传递过来的方法调用。

    因为,Proxy 动态产生的代理会调用 InvocationHandler 实现类,所以 InvocationHandler 是实际执行者。

    总结

    1. 静态代理,代理类需要自己编写代码写成。
    2. 动态代理,代理类通过 Proxy.newInstance() 方法生成。
    3. JDK实现的代理中不管是静态代理还是动态代理,代理与被代理者都要实现两样接口,它们的实质是面向接口编程。CGLib可以不需要接口。
    4. 动态代理通过 Proxy 动态生成 proxy class,但是它也指定了一个 InvocationHandler 的实现类。

    欢迎关注公众号:


    公众号微信

    相关文章

      网友评论

        本文标题:设计模式(四)——搞懂什么是代理模式

        本文链接:https://www.haomeiwen.com/subject/syonhctx.html