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

什么是代理模式
为对象提供一种代理以控制这个对象的访问。
代理模式(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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值