代理模式

1.定义

代理(Proxy)模式: 为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.

1.1 代理模式的功能

代理模式是通过创建一个代理对象,用这个代理对象去代表真实的对象,客户端得到这个代理对象过后,对客户端没有什么影响,就跟得到了真实对象一样来使用.

当客户端操作这个代理对象时,实际上功能最终还是会由真实的对象来完成,只不过是通过代理操作的,也就是客户端操作代理,代理操作真正的对象.

正是因为有代理对象夹在客户端和被代理的真实对象中间,相当于一个中转,那么在中转的时候就有很多花招可以玩,比如: 判断一下权限,如果没有足够的权限那就不给你中转了,等等.

1.2 代理的分类

  • 虚代理--根据需要来创建开销很大的对象,该对象只有在需要的时候才会被真正的创建
  • 远程代理--用来在不同的地址空间上代表同一个对象,这个不同的地址空间可以是在本机,也可以在其它机器上,在java里面最典型的就是RMI技术
  • copy-on-write代理--在客户端操作的时候,只有对象确实改变了,才会真的拷贝(或克隆)一个目标对象,算是虚代理的一个分支
  • 保护代理--控制对原始对象的访问,如果有需要,可以给不同的用户提供不同的访问权限,以控制他们对原始对象的访问.
  • Cache代理--为那些昂贵的操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果
  • 防火墙代理--保护对象不被恶意用户访问和操作
  • 同步代理--使多个用户能够同时访问目标对象而没有冲突
  • 智能指引--在访问对象时执行一些附加操作,比如: 对指向实际对象的引用技术,第一次引用一个持久对象时,将它装入内存等

最常见的是: 虚代理、保护代理、远程代理和只能指引这几种.在开发中使用频率最高的是: 虚代理和保护代理

2.实现

代理模式

  • 抽象主题(Subject)角色: 声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以使用代理主题.该类的实现中保存一个引用使得代理可以访问实体.提供一个与实体接口相同的代理接口,这样代理就可以用来替代实体来控制对实体的存取,并可能负责创建和删除实体
  • 代理主题(Proxy)角色: 代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主体;控制对真实主题的引用,负责在需要的时候创建真实主题对象(和删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或者之后,都要执行某个操作,而不是单纯地将调用传递给真实主题的对象.
  • 真实主题(Real Subject)角色: 定义了代理角色所代表的真实对象,包含实体具体实现代码.
public abstract class AbstractObject {
    protected abstract void operation();
}

public class RealObject extends AbstractObject{

    @Override
    protected void operation() {
        System.out.println("do operation...");
    }
}

public class ProxyObject extends AbstractObject {

    /** 对目标类的引用 */
    private RealObject realObject;

    public ProxyObject(RealObject realObject) {
        this.realObject = realObject;
    }

    @Override
    protected void operation() {
        System.out.println("do something before real peration...");
        if (realObject == null) {
            realObject = new RealObject();
        }

        realObject.operation();
        System.out.println("do something after real operation...");
    }
}

3.java中的代理

JDK中有专门设计实现了Proxy设计模式.只不过它叫动态代理,因为它的代理类变成了InvocationHandler了,执行的方法是invoke了,从而变得更加灵活了.

Proxy模式由 java.lang.reflect.Proxy 类、java.lang.reflect.InvocationHandler类等组成.Proxy类拥有一个 protected 的 InvocationHandler 类型的成员变量.它只能代理 Interface.

java.lang.reflect.Proxy提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类.动态代理类是一个实现在创建类时在运行时指定的接口列表的类.

InvocationHandler是代理实例的调用处理程序实现的接口,也可以说是代理类实现的一个接口.. 代理实例是代理类的一个实例.每个代理实例都有一个关联的调用处理程序对象,它可以实现接口 InvocationHandler.通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组.调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回.

由此可以看出,必须让 Proxy 对象拥有一个正确的 InvocationHandler 的实现.Proxy 对象由 Proxy 的静态成员函数newProxyInstance 来创建,该函数的最后一个参数为 InvocationHandler 类型.动态生成的代理类实现的所有接口方法都被委托给 InvocationHandler 接口的 invoke 方法.

4.总结

优缺点 代理模式在客户和被客户访问的对象之间,引入了一定程度的间接性,客户是直接使用代理,让代理来与被访问的对象进行交互.不同的代理类型,这种附加的间接性有不同的用途,也就是有不同的特点:

  • 远程代理: 隐藏了一个对象存在于不同的地址空间的事实,也即是客户通过远程代理去访问一个对象,根本就不关心这个对象在哪里,也不关心如何通过网络去访问到这个对象,从客户的角度来讲,它只是在使用代理对象而已.
  • 虚代理: 可以根据需要来创建“大”对象,只有到必须创建对象的时候,虚代理才会创建对象,从而大大加快程序运行速度,并节省资源.通过虚代理可以对系统进行优化.
  • 保护代理: 可以在访问一个对象的前后,执行很多附加的操作,除了进行权限控制之外,还可以进行很多跟业务相关的处理,而不需要修改被代理的对象.也就是说,可以通过代理来给目标对象增加功能.
  • 智能指引: 跟保护代理类似,也是允许在访问一个对象的前后,执行很多附加的操作,这样一来就可以做很多额外的事情,比如: 引用计数等.

何时选用

  • 需要为一个对象在不同的地址空间提供局部代表的时候,可以使用远程代理
  • 需要按照需要创建开销很大的对象的时候,可以使用虚代理
  • 需要控制对原始对象的访问的时候,可以使用保护代理
  • 需要在访问对象的时候执行一些附加操作的时候,可以使用智能指引代理

results matching ""

    No results matching ""