代理模式(Proxy Pattern、Surrogate Pattern 对象结构型模式)

来源:互联网 发布:org域名申请 编辑:程序博客网 时间:2024/05/21 14:48

定义

需要在创建
为其他对象提供一种代理以控制对这个对象的访问,一种中介作用,隐藏细节

适用性

在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式。下面是一些可以使用Proxy模式常见的情况:
1. 远程代理(Remote Proxy)为一个对象在不同的地址空间提供局部代表。
2. 虚拟代理(Virtual Proxy)根据需要创建开销很大的对象(需要时在创建)。
3. 保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
4. 智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。它的典型用途包括:
a.对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它
b.当第一次引用一个持久对象时,将它装入内存
c.在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。

结构

这里写图片描述

参与者

Proxy

  1. 保存一个引用使得代理可以访问实体。若RealSubject和Subject的接口相同,Proxy会引用Subject
  2. 提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体
  3. 控制对实体的存取,并可能负责创建和删除它
  4. 其他功能依赖于代理的类型:
    Remote Proxy负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求。
    Virtual Proxy 可以缓存实体的附加信息,以便延迟对它的访问。
    Protection Proxy检查调用者是否具有实现一个请求所必须的访问权限。

Subject

定义RealSubject和Proxy的公用接口,这样就在任何用RealSubject的地方都可以使用Proxy。

RealSubject

定义Proxy所代表的实体。

代码

简单实例

public interface Subject {    public void defaultMethod();}public class RealSubject implements Subject{    public void defaultMethod() {        System.out.println("RealSubject defaultMethod()");    }}public class Proxy implements Subject{    private Subject subject;    public Proxy(Subject subject){        this.subject = subject;    }    public void defaultMethod() {        anotherMethod("before");        subject.defaultMethod();        anotherMethod("after");    }    private void anotherMethod(String type){        System.out.println(type+"====Proxy===anotherMethod=");    }}public class Client {    public static void main(String[] args) {        Subject realSubject = new RealSubject();        Subject proxy = new Proxy(realSubject);        proxy.defaultMethod();    }}

Java内置Proxy

package com.sunld.rdp.core.aspect;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;/** * <p>动态代理基础类</p> * @author 孙辽东 * <p>createDate:2014年3月4日 下午12:15:43 </p> * @version V1.0 */public class BaseInvocationHandler implements InvocationHandler,AspectInterface{    private Object proxyObject;    public BaseInvocationHandler(Object proxyObject){        this.proxyObject = proxyObject;    }    public Object getProxyObject() {        return proxyObject;    }    public void setProxyObject(Object proxyObject) {        this.proxyObject = proxyObject;    }    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        LOGGER.info("记录日志信息--测试"+proxy.getClass().getName());        return method.invoke(proxyObject, args);    }}package com.sunld.rdp.core.factory;import java.lang.reflect.Proxy;import com.sunld.rdp.core.aspect.BaseInvocationHandler;/** * <p>动态代理工厂类</p> * @author 孙辽东 * <p>createDate:2014年6月3日 上午10:05:01</p>  * @version V1.0 */public final class InvocationHandlerFactory<T> implements FactoryInterface{    /**     * <p>代理某个类实现的接口,如果指定泛型参数,则返回特定的接口信息</p>     * @param obj 需要代理的对象     * @param handler 自定义的InvocationHandler {@link BaseInvocationHandler}     * @return T     * <p>createDate:2014年6月3日 上午10:05:35</p>     */    @SuppressWarnings("unchecked")    public T getProxyObjectAllInterfaces(final Object obj,BaseInvocationHandler handler){        ClassLoader cl = obj.getClass().getClassLoader();        Class<?>[] interfaces = obj.getClass().getInterfaces();        return (T)Proxy.newProxyInstance(cl, interfaces, handler);    }}

Java中的实现

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
创建某一接口 Foo 的代理:
InvocationHandler handler = new MyInvocationHandler(…);
Class proxyClass = Proxy.getProxyClass(
Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
或使用以下更简单的方法:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);

协作

代理根据其种类,在适当的时候想RealSubject转发请求。

效果

Proxy模式在访问对象时引入了一定程度的间接性。根据代理的类型,附加的间接性有多种途径。
1. Remote Proxy可以隐藏一个对象存在于不同地址空间的事实
2. Virtual Proxy可以进行最优化,例如根据要求创建对象
3. Protection Proxies和Smart Reference都允许在访问一个对象时有一些附加的内务处理(Housekeeping task)

Copy-on-write

Prory模式还可以对用户隐藏另一种称为copy-on-write的优化方式,该优化与根据需要创建对象有关。拷贝一个庞大而复杂的对象是一种开销很大的操作,如果这个拷贝根本没有被修改,那么这些开销就没有必要。用代理延迟这一拷贝过程,我们可以保证只有当这个对象被修改的时候才对它进行拷贝。
在实现copy-on-write时必须对实体进行引用计数。拷贝代理仅会增加引用计数。只有当用户请求一个修改参数的操作时,代理才会真正的拷贝它。在这种情况下,代理还必须减少实体的引用计数。当引用的数据为0时,这个实体将被删除。
Copy-on-write可以大幅度的降低拷贝庞大实体时的开销。

优点

向客户端隐藏了访问某个对象的细节及复杂性;可以动态地调用一个对象中的方法,且无需实现固定的接口,代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度降低系统的耦合度

缺点

由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 实现代理模式需要额外的工作,有些代理模式的实现非常复杂

经典例子

代练、Spring AOP的核心实现方式、代购、延迟加载监视状态变化

相关模式

Adapter Pattern

适配器Adapter为它所适配的对象提供了一个不同的接口。相反,代理提供了与它的实体相同的接口。然而,用于访问保护的代理可能会拒绝执行实体会执行的操作,因此,它的接口实际上可能只是实体接口的一个子集。Adapter Pattern的功能是连接两个相异接口的对象,而Proxy Pattern中的代理主题角色和真实主题角色被没有不一样。

Decorator Pattern

Decorator Pattern跟proxy pattern的实现很相似,但是目的不同,Decorator Pattern的目的是为了增加其他功能,而Proxy Pattern则比较重视在代替本人进行作业,以减少对本人的存取操作,新增功能反倒不重要(代理模式能够协调调用者和被调用者)。
代理的实现与decorator的实现类似,但是在相似的程度上有所区别。Protection Proxy的实现可能与decorator的实现差不多。另一方面,Remote Proxy不包含对实体的直接引用,而只是一个间接引用,如“主机ID,主机上的局部地址”。Virtual Proxy开始的时候使用一个间接引用,例如一个文件名,但是总将获取并使用一个直接引用。

敬请期待“装饰模式(Decorator Pattern、Wrapper Pattern,对象结构型模式)”

0 0