代理模式的定义:为对象提供一种代理用来控制这个对象的访问。
代理模式的主要构成有三部分:
1、抽象对象
该对象是目标对象以及代理对象的共同接口,这样一来,在使用的地方目标对象都可以使用代理对象。
2、目标对象
定义了代理对象所代表的真实实体。
3、代理对象
代理对象内部持有目标对象的引用,提供一个与目标对象一样的接口,便于后面的替换。
以取快递为例子,主角卡农在网上买了一个一加手机,卖家准备好货之后,由仓库发货,快递会在离你填写地址的合适范围内的一个寄存点。寄存点会对所有的快递整理好,再针对每一个快递上面的电话号码,来通知对应的买家来领取快递。也即是当卡农被通知要取快递的时候,就会到某个地方拿到快递,美滋滋的卡农就会拿到自己心爱的手机。
这里买家卡农买一加手机,他并没有直接从卖家手里得到手机这个对象,而是经过代理了手机发货的快递的寄存点,最终才拿到快递。卡农为目标对象,寄存点为代理对象,快递为抽象对象。实现如下:
抽象对象
package proxy;
/**
* Created by canon on 2018/11/17.
* 快递
*/
public interface Express {
1.String getExpress();//取快递
}
目标对象
package proxy;
/**
* Created by canon on 2018/11/17.
*/
public class CanonExpress implements Express{
@Override
public String getExpress() {
return "这是卡农的快递!!!";
}
}
代理对象
package proxy;
/**
* Created by canon on 2018/11/17.
*/
public class ExpressProxy implements Express {
private Express express;
public ExpressProxy(Express express) {
this.express = express;
}
@Override
public String getExpress() {
System.out.println("叮叮叮,京东快递寄存点,这是卡农的快递!!!");
System.out.println("经过处理,电话或者短信通知卡农");
return express.getExpress();
}
}
客户端调用
package controller;
import proxy.CanonExpress;
import proxy.Express;
import proxy.ExpressProxy;
/**
* Created by canon on 2018/11/17.
*/
public class ProxyDesignPattern {
public static void main(String[] args) {
Express canonExpress = new CanonExpress();
ExpressProxy proxy = new ExpressProxy(canonExpress);
System.out.println(proxy.getExpress());
}
}
输出如下
叮叮叮,京东快递寄存点,这是卡农的快递!!!
经过处理,电话或者短信通知卡农
经过处理,电话或者短信通知卡农
这是卡农的快递!!!
Process finished with exit code 0
上面的代理模式属于静态代理模式,静态代理的特点是静态代理的代理类是程序员创建的,在程序运行之前静态代理的.class文件已经存在了。
从静态代理模式的代码来看,静态代理模式确实有一个代理对象来控制实际对象的引用,并通过代理对象来使用实际对象。这种模式在代理量较小的时候还可以,但是代理量一大起来,就存在着两个比较大的缺点:
1、 静态代理的内容无法复用
2、抽象对象接口里面如果新增了一个方法,实际对象实现了这个方法,代理对象也必须新增方法
由于静态代理的局限也就有了动态代理的到来。这里以jdk中代理模式举例子。
代理Handler
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Created by canon on 2018/11/17.
*/
public class ExpressProxyInvocationHandler implements InvocationHandler {
private Object object;
public ExpressProxyInvocationHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("叮叮叮,京东快递寄存点,这是卡农的快递!!!");
System.out.println("经过处理,电话或者短信通知卡农");
return method.invoke(object,args);
}
}
客户端
import proxy.CanonExpress;
import proxy.Express;
import proxy.ExpressProxy;
import proxy.ExpressProxyInvocationHandler;
import java.lang.reflect.Proxy;
/**
* Created by canon on 2018/11/17.
*/
public class ProxyDesignPattern {
public static void main(String[] args) {
// Express canonExpress = new CanonExpress();
// ExpressProxy proxy = new ExpressProxy(canonExpress);
// System.out.println(proxy.getExpress());
Express canonExpress = new CanonExpress();
ExpressProxyInvocationHandler expressProxyInvocationHandler = new ExpressProxyInvocationHandler(canonExpress);
Express express = (Express) Proxy.newProxyInstance(canonExpress.getClass().getClassLoader(),canonExpress.getClass().getInterfaces(),expressProxyInvocationHandler);
System.out.println(express.getExpress());
}
}
输出
叮叮叮,京东快递寄存点,这是卡农的快递!!!
经过处理,电话或者短信通知卡农
这是卡农的快递!!!
Process finished with exit code 0
动态代理的优点
代理内容InvocationHandler接口的实现类可以复用。可以在不改动原来代码逻辑的基础上增加功能,更有利于系统拓展,更加灵活。