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

定义

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

适用性

在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用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,对象结构型模式)”

转载于:https://my.oschina.net/sld880311/blog/1485968

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值