代理模式--你说我来做,反射帮大忙(结构型模式06)

来源:互联网 发布:在线管理远程mysql 编辑:程序博客网 时间:2024/05/02 04:31

什么是代理模式
为对象提供一种代理以控制这个对象的访问。
代理模式(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();    }}

结果与静态调用一样:

获取到了卖家的地址和我的地址获取到了包裹单号获取到了包裹信息

总结:
我们可以看到,静态调用和动态调用都可以实现预期目的,区别就是静态代理与代理者都要实现共同接口,耦合度大,动态接口不必,减小耦合度。实现原理是,动态是根据代理者的反射机制来获取代理的内容等操作,静态是直接实现接口。相比之下,动态实现更为灵活。动态可以代理各式各样的代理者,而静态受限于接口下的代理。如果扩展需求要不同的代理,那么就要重新定义,若接口过多的话,实在是一种麻烦。不会偷懒的程序员不是好的程序员,反射机制很有用也很好用。动态代理和静态代理的选择,要根据实况而来,存在必合理,也没有那个绝对好哈。

0 0