设计模式之代理模式

代理模式,为其他对象提供一种代理来控制这个对象的访问。生活中有很多这样子的例子。如果你喜欢购物,相信你对代购不会陌生。那么你去找到代购,代购为你买回来商品这样行为方式就 是一种代理模式。如果你喜欢玩游戏你又不想自己亲手或者技术有限,你去找到代练,让他们为你上分,升级,这样的行为方式也是一种代理模式。在代理模式下涉及到的角色模型:

  • 抽象行为模型:通常使用接口实现。由代理类跟代理角色共同实现,定义了代理的目的行为。
  • 代理模型:需要实现抽象行为。充当代理角色,控制真实实施角色,对抽象行为增加额外补充,不执行抽象行为。
  • 具体模型:实现抽象行为。被代理角色,是真正的抽象行为执行者。

以找代购购买iPhone手机为一个小例子。首先是抽象行为,就是去买iPhone:

public interface Subject {

    //目的
    void buyIphoneX();
}

具体模型:

public class RealSubject implements Subject {
    @Override
    public void buyIphoneX() {
        Log.d("ProxySubject", "buyIphoneX: 我去买iPhone了");
    }
}

具体模型的内容很简单,就是执行具体的抽象行为,它就只有这一个目的。代理类:

public class ProxySubject implements Subject {
    private Subject subject;

    public ProxySubject() {
        subject = new RealSubject();
    }

    @Override
    public void buyIphoneX() {
        this.goToAmerica();
        subject.buyIphoneX();
        this.goBack();
    }

    private void goToAmerica() {
        Log.d("ProxySubject", "goToAmerica: 去美国");
    }

    private void bargain() {
        Log.d("ProxySubject", "bargain: 讲价");
    }

    private void goBack() {
        Log.d("ProxySubject", "goBack: 返程");
    }
}

可以看到代理类除了控制被代理角色去执行抽象行为外,还有其他的处理,像去到哪个地方买,怎么个买法,买完后怎么样。这些都是一些额外的处理。这些抽象行为额外的操作是根据具体情况增加的。使用场景:

Subject subject = new ProxySubject();
subject.buyIphoneX();

输出结果:

D/ProxySubject: goToAmerica: 去美国
D/ProxySubject: buyIphoneX: 我去买iPhone了
D/ProxySubject: goBack: 返程

OK,代理模式简单的例子就是这样了。这种方式一般称为静态代理模式,就是每个代理都是由具体类对象直接调用;而还有一种动态代理模式,则是通过反射间接的调用代理方法。动态代理角色模型跟静态代理差不多,只是代理模型发生了变化,它不是实现抽象行为模型接口了,而是实现InvocationHandler 这个专属接口。

public class DynamicProxy implements InvocationHandler {
    //代理类
    private Object target;

    public DynamicProxy(Object target) {
        this.target = target;
    }

    /**
     * @param proxy  
     * @param method 代理方法
     * @param args   代理参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(target, args);
    }
}

 它的使用:

RealSubject r = new RealSubject();
DynamicProxy d = new DynamicProxy(r);
ClassLoader classLoader = r.getClass().getClassLoader();
Subject s = (Subject) Proxy.newProxyInstance(classLoader, r.getClass().getInterfaces(), d);
s.buyIphoneX();

跟静态模式看起来好像都没有什么不一样,但是静态代理模式里一个真实对象就要对应一个代理类,而真实代理往往会有很多的,不可能全部对应创建代理类。而使用动态代理就方便很多了。稍微改写:

/**
 * 代理方法
 * @param r 真实代理对象
 */
private void proxy(Subject r) {
     DynamicProxy d = new DynamicProxy(r);
     //获取classloader
     ClassLoader classLoader = r.getClass().getClassLoader();
     //获取代理对象
     Subject s = (Subject) Proxy.newProxyInstance(classLoader, r.getClass().getInterfaces(), d);
     s.buyIphoneX();
    }

 然后调用:

 RealSubject r1 = new RealSubject();
 RealSubject2 r2 = new RealSubject2();
 RealSubject3 r3 = new RealSubject3();
 proxy(r1);
 proxy(r2);
 proxy(r3);

这样即使有再多的真实代理,也只需要一个代理类就可以了。简单方便。

代理模式的分类

按照使用目的可以分为以下类别:

  • 远程代理:为一个位于不同地址的空间对象提供一个局部代表对象。这个不同空间的地址可以是同一台机器或者不同机器                         上。
  • 虚拟代理:当需要创建一些消耗资源较多的对象时,可以首先创建代理对象,将真实对象的创建延迟。例如加载大图片。
  • 保护代理:控制对一个对象的访问。
  • 缓存代理:为一个目标操作的结果提供临时的存储空间。
  • 同步代理:使多个用户能够使用同一个对象而且没有冲突。
  • 智能引用代理:当一个对象被引用时,提供一些额外的操作。

上述分类中远程代理,虚拟代理,保护代理跟智能引用代理是使用较多的分类。

最后代理模式的优劣

优点

  • 真实代理与调用对象之前存在代理类,各个角色职责清晰,降低程序耦合度;
  • 代理类在运行时才加载真实代理,一定程度上减少资源开销,提升效率;

缺点:

  • 刚刚说过,真实代理与调用对象之前存在代理类,在降低耦合度的同时也会增加结构的复杂度;
  • 相比跨过代理类直接泛起请求,代理模式处理速度会变慢;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值