24. 代理模式

作者: Next_吴思成 | 来源:发表于2018-07-10 22:27 被阅读0次

    定义

    代理模式(Proxy Pattern):给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。

    通俗理解

    在好几年前,买火车票和飞机票总要在线下买。可以在火车站、机场买,当然并不是每一个人都在火车站、机场旁边,如果走很远的路就为了一张票,就太浪费时间了,所以随地可见的火车、飞机票代售点就成为大家买票的最佳选择。

    火车、飞机票代售点是火车站、机场的一个代理商,它可以完成火车票、飞机票的销售,同时,还可以在这上面添加自己的功能,例如可以卖一些保险、旅途中的附加服务等等。当然,这其中也有代售点不可以做的工作,其中重要的一点就是代售点不可以进行退票的工作,要退票,只能去火车站、机场。

    代理模式就是这样一个场景。如果一个接口很难进行访问,那么我们可以在这个接口上面封装一层代理类,用代理类去调取这个接口,然后我们的系统调取代理类。并且在代理类上面可以封装自己的方法,使得接口更符合我们系统,更加易用。

    示例

    以火车代售点作为实例。

    渣渣程序

    车站接口以及实现

    public interface IStation {
        void saleTicket();
    }
    public class StationImpl implements IStation {
        public void saleTicket() {
            System.out.println("火车站卖出一张车票");
        }
    }
    

    程序主入口

    public class Main {
        public static void main(String[] args) {
            IStation station = new StationImpl();
            station.saleTicket();//火车站卖出一张车票
        }
    }
    

    上面就是完全没有使用代理模式的代码,直接调用车站的代码,就相当于直接去车站买车票一样。当然不是不可以,但是像前面讲的一样,有时候我们去不了车站或者不想去车站的情况下,那么这种写法就不适合了。

    优化

    普通代理

    车站接口以及实现不变,添加StationProxy的类,实现对Station的代理,程序如下:

    public class StationProxy implements IStation {
        private IStation station;
        public void saleTicket() {
            if(station == null) {
                station = new StationImpl();
            }
            System.out.println("连接火车站系统连接");
            station.saleTicket();
            System.out.println("断开火车站系统连接");
        }
    }
    

    程序入口

    public class Main {
        public static void main(String[] args) {
            IStation station = new StationProxy();
            station.saleTicket();
            //连接火车站系统连接
            //火车站卖出一张车票
            //断开火车站系统连接
        }
    }
    

    这样就实现了对火车站的代理,并且在代理的方法上面添加了自己系统的方法。要注意的是,这里使用了懒加载的方式,只有在调用代理方法的时候才会初始化对象,这个过程叫懒加载,有利于改善系统性能。

    动态代理

    Java提供了反射的方式,可以动态加载类,这样绕过了编译,也让系统实现更加灵活。同时,在代理模式当中,也可以使用动态代理的方式。

    车站接口以及实现不变,创建动态代理的处理类。

    动态代理处理类

    public class StationHandler implements InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object obj = new StationImpl();
            System.out.println("代理类:" + proxy.getClass().getName()
                    + "调用:"+obj.getClass().getName()
                    + "代理方法:"+method.getName());
            Object invoke = method.invoke(obj, args);
            System.out.println("调用结束");
            return invoke;
        }
    }
    

    程序主入口

    public class Main {
        public static void main(String[] args) {
            IStation stationProxy = (IStation) Proxy.newProxyInstance(
                    Thread.currentThread().getContextClassLoader(),
                    new Class[]{IStation.class},
                    new StationHandler()
                    );
            stationProxy.saleTicket();
            //代理类:com.sun.proxy.$Proxy0调用:com.wusicheng.e24_proxy_pattern.nevv.dynamic.StationImpl代理方法:saleTicket
            //火车站卖出一张车票
            //调用结束
        }
    }
    

    动态代理是框架的基础,AOP就是这么实现的。如果跟踪源代码,可以看到大量的invoke,$proxy(),他们用的就是动态代理。这里不做深入,以后读源代码的时候再深入,现在知道,会写就可以了。

    优点

    1. 协调调用者和被调用者,降低系统的耦合度;
    2. 客户端可以对调用发进行编程,增加或者修改代理类的时候,不需要修改源代码就可以实现,符合“开闭原则”。

    缺点

    1. 封装了一层,系统可能会变慢;
    2. 实现代理需要额外的工作,有些的实现过程比较复杂。

    应用场景

    1. 对象载入时间长的,需要知道中间状态的;
    2. 在远程计算机上,访问困难时间长,需要鉴权的;
    3. 频繁查询和引用的;
    4. 多线程中使用保证安全的;
    5. 某对象被多个对象引用,其中的引用需要被改写的时候复制出来的;
    6. 对象的使用时需要自动做其他工作的。

    吐槽

    就是在原来的对象上面封装一层。

    程序

    e24_proxy_pattern

    https://www.jianshu.com/p/ab6d5853b24e

    相关文章

      网友评论

        本文标题:24. 代理模式

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