设计模式简讲程序员

24. 代理模式

2018-07-10  本文已影响0人  Next_吴思成

定义

代理模式(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

上一篇下一篇

猜你喜欢

热点阅读