小明要买房了
小明的公司的新项目应接不暇,这不,小明拿之前做项目积累的积蓄准备买房了,但是万事开头难,小明不知道该怎么如手,作为他在工作和生活上导师的主管说,我们来写一个程序你就明白该怎么做了。
小明很诧异,这和程序需有什么关系啊,主管说,当然有,我们来实现一下你买房的场景:
public interface IHouse{
public String getInfo();
}
一套具体的房子:
public class House implements IHouse{
String info;
public House(String info){
this.info = info;
}
public String getInfo(){
return info;
}
}
因为消息不对称,你并不知道这套房子在出售,那么你要找一个知道的人,然后找他了解情况,这个人就是代理:
public class HouseProxy implements IHouse{
IHouse house;
public HouseProxy(IHouse house){
this.house = house;
}
public String getInfo(){
return house.info;
}
}
所以,对于你来说,你只需要找到代理即可,而代理是你很容易接触到的,这就是代理模式:
public class XiaoMing {
public static void main(String[] args) {
IHouse houseProxy = new HouseProxy(new House("三环的房子"));
houseProxy.getInfo();
}
}
小明很快就明白该怎么做了,但是小明觉得这个模式在程序中没有存在的价值啊,我们不需要借用一个类去访问另一个类啊,因为在程序中不像我们现实中,程序中有多少类我们应该都是知道的。主管说,别着急,我们慢慢看,首先我们来看看代理模式的定义。
定义
为另一个对象提供一个替身或者占位符以控制对这个对象的访问
角色
- 抽象角色
- 代理角色
- 真实角色
代理模式的用法
代理模式的定义我们已经很清楚了,但是它到底有什么用处呢,还是它是一个没有多大用处的模式呢,恰巧相反,代理模式的用法非常非常多,所以我们来一个一个详细的了解
静态代理
代理类和被代理类的关系在运行前就确定了,也就是一个代理类对应一个被代理的真实角色,正如我们上面的列子,就是一个静态代理,他只是控制了对真实角色的直接访问,他有一个缺点,就是一个代理类代理一个真实角色,这样如果需要代理的角色很多,会造成代理类大量增加。那么有什么方式解决吗?接下来我们要说的代理模式的另一种形式就可以解决这个问题
动态代理
动态代理相比前面的静态代理,动态代理具有更强的灵活性,因为它不用在我们设计实现的时候就指定某一个代理类来代理哪一个被代理对象,我们可以把这种指定延迟到程序运行时由JVM来实现。我们知道,所谓代理,就是需要代理类和被代理类有相同的对外接口,所以代理类一般都必须实现了所有被代理类已实现的接口,因为接口就是制定了一系列对外服务的标准。正因为动态代理有这样灵活的特性,所以我们在设计动态代理类(DynamicProxy)时不用显式地让它实现与真实角色相同的接口,而是把这种实现推迟到运行时。我们把上面的例子用动态代理实现
抽象角色和真实角色不变:
public interface IHouse{
public String getInfo();
}
一套具体的房子:
public class House implements IHouse{
String info;
public House(String info){
this.info = info;
}
public String getInfo(){
return info;
}
}
变化的使我们的代理类:
public class DynamicProxyHouse implements InvocationHandler {
Object obj = null;
public DynamicProxyHouse(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//do something
Object result = method.invoke(this.obj, args);
return result;
}
}
它并没有实现我们的抽象角色,而是实现JDK中的InvocationHandler,先看新的代理的的使用:
public class XiaoMing {
public static void main(String[] args) {
IHouse realHouse = new House("二环的房子");
ClassLoader loader = realHouse.getClass().getClassLoader();
Class<?>[] interfaces = realHouse.getClass().getInterfaces();
InvocationHandler handler = new DynamicProxyHouse(realHouse);
IHouse houseProxy = (IHouse) Proxy.newProxyInstance(loader, interfaces, handler);
houseProxy.getInfo();
}
}
我们可以看到,新的代理可以代理任何需要被代理的对象,而不需要像静态代理那样为每个需要代理的类定义一个代理类。当调用被代理类的方法时,是由InvocationHandler的invoke去调用,所以我们可以在invoke方法中增加我们要做的事,接下来我们看一下动态代理的过程:
动态代理用了Java中的反射,同时它也是一种AOP的体现,大家可以自行去深入了解一下反射和AOP。
远程代理
远程代理就是通过代理去调用远程对象的方法,这个对象存在于不同的地址空间。Java RMI就是远程代理的一个实际运用,另外Android中的AIDL也是通过代理模式实现的不同进程间通讯很好的例子,只是它们各自的实现原理不一样
虚拟代理
虚拟代理主要是被代理的对象实例化的开销很大,通过代理,可以管理被代理对象的加载。比如,在加载图片时,未加载出图片时,先显示一串提示文字,代理类作为被代理类的替身
安全代理
安全代理很简单,就是用来控制对真实对象的访问
智能代理
代理类在代理时,会在调用真实类方法时,在前面或者后面增加一些操作。如上面的房产代理,除了卖房(其实是房屋所有者卖房)还会收取佣金