代理模式的定义
为其他对象提供一种代理,以控制对这个对象的访问;
代理对象起到中介的作用,可去掉功能服务或者增加额外的服务;
比如:买火车票,可以去火车票代售处购买而不用非得去到火车站,火车票代售处就是火车站的代理,
火车票代售处和火车站的功能的比较:
功能服务 | 火车站 | 火车票代售处 |
---|---|---|
火车票的销售功能 | 有 | 有 |
提供额外的服务(电话预约) | 没有 | 有 |
提供额外的服务(收取手续费) | 没有 | 有 |
提供退票服务 | 有 | 没有 |
火车票代售处就是火车站的代理,可去掉功能服务或者增加额外的服务;
代理模式两种静态代理和动态代理
静态代理
比如一辆汽车有行驶功能,现在要代理一下汽车行驶,额外增加时间记录功能;
1,相同接口或抽象类
public interface Moveable {
void move();//公共的行驶
}
//原始的小汽车 实现了Moveable
public class Car implements Moveable {
@Override
public void move() {
System.out.println("汽车行驶过程中。。。。。");
}
}
通过继承来实现代理
现在的代理小汽车实现了 Moveable (Car本身也是实现了Moveable)
//通过继承的方式来实现代理
public class CarProxy1 extends Car {
@Override
public void move() {
System.out.println("汽车开始时间。。。。。");//额外增加时间统计
super.move();
System.out.println("汽车结束时间。。。。。");
}
}
通过聚合来实现代理
现在的代理小汽车实现了 Moveable
public class CarProxy2 implements Moveable {
public Moveable m;
public CarProxy2(Car m) {
this.m = m;
}
@Override
public void move() {
System.out.println("汽车开始时间。。。。。");//额外增加时间统计
m.move();
System.out.println("汽车结束时间。。。。。");
}
}
继承的方式相比于聚合来讲不灵活;
现在我们添加一个代理日志打印的功能;使用继承的方式会增加下面四中代理类,每个代理类的都是特定的功能如下;
1,统计时间的代理类;
2,统计日志的代理类;
3,先统计时间后统计日志的代理类;
4,先统计日志后统计时间的代理类;
如果使用组合的话,只需要两个类就可以了;看代码
1,统计时间代理类
//代理时间打印的代理
public class CarTimeProxy implements Moveable {
public Moveable m;
public CarTimeProxy(Moveable m) {
this.m = m;
}
@Override
public void move() {
System.out.println("汽车开始时间。。。。。");//额外增加时间统计
m.move();
System.out.println("汽车结束时间。。。。。");
}
}
统计时间代理类
Car car = new Car();
CarTimeProxy carTimeProxy = new CarTimeProxy(car);
carTimeProxy.move();
2,统计日志代理类
//代理日志打印功能的代理
public class CarLogProxy implements Moveable {
public Moveable m;
public CarLogProxy(Moveable m) {
this.m = m;
}
@Override
public void move() {
System.out.println("汽车开始日志。。。。。");//额外增加日志打印统计
m.move();
System.out.println("汽车结束日志。。。。。");
}
}
统计日志打印代理类
Car car = new Car();
CarLogProxy carLogProxy = new CarLogProxy(car);
carLogProxy.move();
3,先统计时间后统计日志的代理
Car car = new Car();
CarTimeProxy carTimeProxy = new CarTimeProxy(car);
CarLogProxy carLogProxy = new CarLogProxy(carTimeProxy);
carLogProxy.move();
4,先统计日志后统计时间的代理
Car car = new Car();
CarLogProxy carLogProxy = new CarLogProxy(car);
CarTimeProxy carTimeProxy = new CarTimeProxy(carLogProxy);
carTimeProxy.move();
从上面看使用组合方式只需要使用2个类就ok了;
动态代理
上面的小汽车需要做时间上的代理,那么自行车,火车,也需要时间上的代理,其它失误也需要时间上的代理,如下图所示,有一百个事物就需要做100个事物对象的时间代理;
那样会造成代理类膨胀;那么有没有一种方式 实现对不同类,不同方法的代理这产生里动态代理,
上面的事例中不同的想要代理时间的对象都是动态产生,这就属于动态代理;
动态代理就是在代理对象和被代理对象之间添加了一个事物处理器;如下图代理的关键两个类:
Proxy:
InVocationHandler:
具体代码实现:
//这个Car类,现在要对它做一个时间代理(使用动态代理)
final Car car = new Car();
//实现一个InvocationHandler接口
InvocationHandler invocationHandler = new InvocationHandler() {
/**
* @param proxy 代理类Proxy,它是JDK内部的类
* @param method 被代理类的方法
* @param args 被代理类方法的参数
* @return 被代理类的方法返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("汽车行驶开始时间。。。。。");
method.invoke(car, args);
System.out.println("汽车行驶结束时间。。。。。");
return null;
}
};
ClassLoader classLoader = Car.class.getClassLoader();
Class<?>[] interfaces = Car.class.getInterfaces();
//产生一个代理对象
final Moveable m = (Moveable) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
//调用方法,就会调用InvocationHandler的invoke方法,整个代理过程都在这个方法里面执行
m.move();
总结动态代理:这个鬼东西真的很玄幻啊,我刚开始是很晕晕的,
使用一个伪代码解释一下,
public class CarProxy implements Moveable{
InvocationHandler invocationHandler;
@Override
public void move() {
invocationHandler.invoke()
}
}
1,Proxy.newProxyInstance生成的代理类class是在运行时生成,
Proxy.newProxyInstance()生成的就是一个类似上面的代理类CarProxy,里面含有InvocationHandler属性
2,Proxy.newProxyInstance生成的代理类class需要实现一组接口
这里这个代理类CarProxy也是实现了Moveable接口
3,必须实现InvocationHandler,具体代理类业务是在invoke方法里面实现;
当代理类CarProxy调用自己的方法比如move()时候,相当于这个时候InvocationHandler调用自己的invoke方法来执行的;