什么是代理模式
为对象提供一种代理以控制这个对象的访问。
代理模式(Proxy Pattern)也称为委托模式。地位举足轻重,也比较简单。就像他的名字一样,代理是他的精华所在,我们生活中各种各样的代理服务,比如快递实质上也是帮你去卖家那里取东西。平时吃饭不想动,让室友帮你带一份(无偿劳动力-_-!),代理就是委托中间人帮你办一件事,毕竟大家都在瞎忙….
代理模式的适用场景
当无法或直接访问某个对象,或者访问存在阻碍时。
代理模式中的角色
Subject:抽象主题类
RealSubject:真是主题类
ProxySubject:代理类
Client:客户类
代理模式比较重要,分为静态代理和动态代理。
静态代理模式用例
淘宝购物发物流的例子吧。我们付款后,卖家发货,本来是应该我们去卖家那里取货的,但是我们使用了代理(快递),付好了快递费,通知好地址等信息,只要等快递送上门来就好了。
UML类图
IParcel接口类:
public interface IParcel {
public void getAddress();
public void getOrderNumber();
public void getParcel();
}
邮递员Postman实现类:
public class Postman implements IParcel {
private IParcel mParcel;
public Postman(IParcel mParcel){
this.mParcel = mParcel;
}
@Override
public void getAddress() {
mParcel.getAddress();
}
@Override
public void getOrderNumber() {
mParcel.getOrderNumber();
}
@Override
public void getParcel() {
mParcel.getParcel();
}
}
客户Myself实现类
public class Myself implements IParcel {
@Override
public void getAddress() {
System.out.println("获取到了卖家的地址和我的地址");
}
@Override
public void getOrderNumber() {
System.out.println("获取到了包裹单号");
}
@Override
public void getParcel() {
System.out.println("获取到了包裹信息");
}
}
主类调用
public class Test {
public static void main(String[] args) {
IParcel mPostman = new Postman(new Myself());
mPostman.getAddress();
mPostman.getOrderNumber();
mPostman.getParcel();
}
}
结果:
获取到了卖家的地址和我的地址
获取到了包裹单号
获取到了包裹信息
以上是静态代理模式,一个快递员不可能只接我一个人的生意吧。静态代理代码由程序员写好运行前class文件以编译好等运行就是,代理指定好了就是上边的快递。而动态代理与之恰恰性反,动态运用java的反射机制动态生成代理对象代码阶段我们就不知道代理是谁,运行时我们才知道是谁。
动态代理需要实现java提供的动态代理接口InvocationHandler实现其下的invoke方法。
动态代理类图:
IParcel接口类:
public interface IParcel {
public void getAddress();
public void getOrderNumber();
public void getParcel();
}
客户Myself实现类
public class Myself implements IParcel {
@Override
public void getAddress() {
System.out.println("获取到了卖家的地址和我的地址");
}
@Override
public void getOrderNumber() {
System.out.println("获取到了包裹单号");
}
@Override
public void getParcel() {
System.out.println("获取到了包裹信息");
}
}
动态实现DynamicProxy类
public class DynamicProxy implements InvocationHandler{
private Object obj;//被代理类
public DynamicProxy(Object obj){
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(obj, args);
return result;
}
}
主类调用
public class Test2 {
public static void main(String[] args) {
IParcel me = new Myself();
//构造动态代理
DynamicProxy dp = new DynamicProxy(me);
//获取被代理类的ClassLoader
ClassLoader loader = me.getClass().getClassLoader();
//动态构造一个邮递员
IParcel mPostman = (IParcel) Proxy.newProxyInstance(loader, new Class[]{IParcel.class}, dp);
mPostman.getAddress();
mPostman.getOrderNumber();
mPostman.getParcel();
}
}
结果与静态调用一样:
获取到了卖家的地址和我的地址
获取到了包裹单号
获取到了包裹信息
总结:
我们可以看到,静态调用和动态调用都可以实现预期目的,区别就是静态代理与代理者都要实现共同接口,耦合度大,动态接口不必,减小耦合度。实现原理是,动态是根据代理者的反射机制来获取代理的内容等操作,静态是直接实现接口。相比之下,动态实现更为灵活。动态可以代理各式各样的代理者,而静态受限于接口下的代理。如果扩展需求要不同的代理,那么就要重新定义,若接口过多的话,实在是一种麻烦。不会偷懒的程序员不是好的程序员,反射机制很有用也很好用。动态代理和静态代理的选择,要根据实况而来,存在必合理,也没有那个绝对好哈。