什么是代理模式?
代理模式通俗的讲就是用一个类去代理另一个类,那么我们为什么需要代理另一个类呢?通常我们在处理业务逻辑的过程中,可能会有一些附加动作需要做,例如记录操作记录等,这些内容本身并不是我们重要的业务流程,但又是不可缺少的,这个时候代理模式就派上了用场,这个就类似于我们spring中的aop。
代理模式的关键是什么?
代理模式的关键是实现类与代理类的组合,如下图就是一个静态代理的结构:
静态代理实例分析
我们可以考虑这么一个卖票的场景,假设一个人准备过年回家,需要买票,因此就需要有人卖票,下面我们定义一个卖票的接口:
/**
* 售票处
*/
public interface TicketOffice {
public void sellTicket();
}
我们的火车站售票处作为合法的售票处,负责向乘客售票,因此我们实现一个火车票售票处:
/**
* 火车站售票大厅
*/
public class RailwayStationTicketOffice implements TicketOffice {
@Override
public void sellTicket() {
System.out.println("sell railway ticket by railway station");
}
}
这样就可以解决乘客买票的问题了,但是由于每年到了春运,买票回家的人太多了,火车站的容量有限,不可能接纳那么多乘客同事来买票,因此火车站想到了一个方案,在城市各个地方找一些自己的代理,让他们来替自己卖票,因此有了我们看到的火车票代售,在这里我们假设他们是通过先向火车站买入再卖出的模式,因此我们有了代理类:
/**
* 火车票代理
*/
public class RailwayTicketProxy implements TicketOffice {
private RailwayStationTicketOffice office = new RailwayStationTicketOffice();
public void sellTicket() {
System.out.println("buy railway ticket from railway station");
office.sellTicket();
System.out.println("sell railway ticket from proxy");
}
}
有了这些代理之后,乘客就不需要再去火车站排长队等待买票,而是在火车票代理就可以实现买火车票,然后我们实现client如下:
/**
* 静态代理客户端
*/
public class StaticProxyClient {
/**
* 用户只关心买到票,对于火车票是如何买到的本身并不关心
*/
public static void main(String[] args) {
RailwayTicketProxy proxy = new RailwayTicketProxy();
proxy.sellTicket();
}
}
我们的用户可以在代理那里同样买到火车票,而且根本不用关心这个火车票是怎么来的。运行结果如下:
buy railway ticket from railway station
sell railway ticket by railway station
sell railway ticket from proxy
这种模式看样子很好,类似于此我们可以剥离开我们核心业务流程中的非核心操作,但是问题来了,如果有这么多类,我们就要搞这么多代理,对我们来说岂不是工作量加倍?而且对于记录操作记录,这些完全是同样的操作,我们是否能对他进行统一的配置呢?这就是动态代理的好处了。
动态代理实例分析
同样是买票的场景,假设有人比较犹豫,我要买火车票呢?还是买飞机票呢?如果按照静态代理的模式,火车站找到了自己的代理,机场遇到了同样的情况,也找到了自己的代理,那么用户就不得不先去火车票代理询问火车票的价格,再去机场代理询问机票的价格,等问完决定回来买火车票的时候,发现火车票已经卖完了。用户花了时间、精力最后什么都没得到一定非常恼火,那么为什么我们不搞一个总的代理呢,在这里既可以询问火车票,也可以询问机票呢。因此我们动态代理实现如下:
/**
* 总代理
*/
public class ProxyHandler implements InvocationHandler {
//需要被代理的对象,火车票售票处?机票售票处?
private Object target;
//为我们的目标类生成动态代理
public Object newProxyInstance(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("buy ticket from " + target.getClass().getName());
Object result = method.invoke(target, args);
System.out.println("sell ticket from proxy");
return result;
}
}
如上所示我们生成了一个总的代理,可以由用户决定,我是要代理火车票售票处呢?还是代理机票售票处,最终决定如何买什么票。我们来看看动态代理的client端:
/**
* 动态代理客户端
*/
public class DynamicProxyClient {
public static void main(String[] args) {
RailwayStationTicketOffice railwayOffice = new RailwayStationTicketOffice();
ProxyHandler handler = new ProxyHandler();
TicketOffice railwayOfficeProxy = (TicketOffice) handler.newProxyInstance(railwayOffice);
railwayOfficeProxy.sellTicket();
}
}
最终用户决定我买火车票,因此我们通过代理火车票售票处,完成对用户售票。运行结果如下
buy ticket from DesignPattern.proxy.RailwayStationTicketOffice
sell railway ticket by railway station
sell ticket from proxy