三十八:代理模式

一:什么是代理
代理模式给某一个对象提供一个代理对象,并由代理对象控制原对象的引用.
中国人是一个含蓄的民族,讲求微妙和间接的交流方式,对象间的间接通信也同样是面向对象的设计中一条重要的"审美观"。间接性的通信可以给出较低的耦合关系,较强的合作关系,以及微妙的结构和易于复用的设计架构。
代理模式的英文叫做Proxy,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动,在一些情况下,一个客户不想或者不能直接引用一个对象,而代理对象可以在客户和目标之间起到中介的作用.
比如说Window的快捷方式(Shortcut)就是一个代理的例子,如果原对象被删除,则快捷方式虽然可以存在,但是在调用时会给出错误.

二:代理的种类
如果按使用的目的来划分,代理有以下几种:
(A)远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象,这个不同的地址空间可以是在本机器中,也可是在另一台机器中,远程代理又叫大使.
(B)虚拟(Virtual)代理:根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建.
(C)保护(Protect)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限.
(D)智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来.
.....上面是最常用的代理,还有其他的种类,在此不作介绍.

三:代理模式的角色
(A)抽象主题角色:声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以使用代理主题。
(B)代理主题(Proxy)角色:代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作真实主题对象:代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主体,控制对真实主题的引用,负责在需要的时候创建真实主题对象(和删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或者之后,都要执行某个操作,而不是单纯地将调用传递给真实主题对象.
(C)真实主题角色:定义了代理角色所代理的真实对象.
下面是示意性的源码:

package cai.milenfan.basic.test; 
//抽象主题角色
abstract public class Subject {
//申明一个抽象的请求方法
abstract public void request();
}


package cai.milenfan.basic.test; 
//具体主题角色
public class RealSubject extends Subject{
public void request() {
System.out.println("request from RealSubject........");
}
}



package cai.milenfan.basic.test; 

public class ProxySubject extends Subject{
private RealSubject realSubject;
//请求前的操作
private void preRequest(){
//do something you want before the request...
}
public void request() {
preRequest();
if(realSubject==null){
realSubject = new RealSubject();
}
realSubject.request();
postRequest();
}
private void postRequest(){
//do something you want after the request
}
}


package cai.milenfan.basic.test; 
//客户端调用.
public class TestProxy {
public static void main(String[] args){
Subject subject = new ProxySubject();
subject.request();
}
}


代理模式将一个代理插入到客户端和主题角色之间,提供了较多的灵活性,如代理主题可以在向真实主题传递客户端的请求之前执行特定的操作,并决定是否将请求传递给真实主题,代理主题可以在向真实主题传递客户端请求后执行另外一种操作,比如将客户端请求计数.....

四:Java2.0对代理模式的支持
(A)反身映射(Reflection)与动态代理
自从JDK1.3以来,Java语言通过在java.lang.reflect库中提供下面三个类直接支持代理模式:Proxy,InvocationHandler和Method.其中Proxy类使得设计师能够在运行时间创建代理对象,当有一个代理对象后,对原对象的方法调用首先被分派给一个调用处理器(Invocation Handler),程序可以在处理器的invoke()方法里截获这个调用,进行额外的操作,Java所提供的这一支持是建立在反身映射(Reflection)的基础上的,设计师可以按照下面的步骤创建动态代理对象:
(1)指明一系列的接口来创建一个代理对象
(2)创建一个调用处理器(InvocationHandleer)对象
(3)将这个代理指定为某个其他对象的代理对象
(4)在调用处理器的invoke()方法中采取代理,一方面将调用传递给真实对象,另一方面执行各种需要做的操作.
下面给出一个例子,这个例子要解决的问题是为一个Vector对象提供一个代理对象,当Vector的任何方法被调用之前和之后,分别打印出两条信息,这表明代理对象有能力截获和控制这个Vecto对象,这里仅仅需要一个新的类,称为VectorProxy类,此类需要实现java.lang.reflectInvocationHandler,由于Vector对象实现了java.util.List接口,因此调用List的方法,可以操控代理对象,其源代码如下:
package cai.milenfan.basic.test; 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Vector;
public class VectorProxy implements InvocationHandler{
private Object proxyobj;
public VectorProxy(Object obj){
proxyobj = obj;
}
//静态工厂方法
public static Object factory(Object obj){
Class cls = obj.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),new VectorProxy(obj));
}
//调用某个方法
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
System.out.println("before calling " method);
if(args!=null){
for(int i=0;i<args.length;i ){
System.out.println(args[i] "");
}
}
Object o = method.invoke(proxyobj, args);
System.out.println("after calling " method);
return o;
}
public static void main(String[] args){
List v = null;
v = (List)factory(new Vector());
v.add("Milenfan");
v.add("czy");
}
}


也就是说,代理对象截获了对Vector对象的所有调用,在将调用传递给Vector之前和之后,代理对象具有采取合适操作的灵活性,虽然这里代理对象所采取的操作不过就是打印两种信息.本例子的对象图如下:
客户端-->VectorProxy-->InvocationHandler-->Vector。
在此例子中使用了静态工厂方法factory(),负责创建出Proxy类的实例,它将创建实现的细节隐藏起来,这是简单工厂模式的应用.
客户端分辨不出代理主题对象与真实主题对象,这是代理模式的一个重要用意.

五:代理模式的实现
代理模式可能并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并且传入.
(A)与适配器模式的关系:这两种模式看上去很相像,它们都可视为一个对象提供一种前置的接口。但是,适配器模式的用意是要改变所考虑的对象的接口,而代理模式并不能改变所代理的对象的接口,在这一点上两个模式有明显的区别。
(B)与装饰模式的关系:装饰模式与所装饰的对象具有相同的接口,因此这两种模式也有可能混淆,但是,装饰模式应当为所装饰的对象提供增强功能,而代理模式对对象的使用施加控制,并不提供对象本身的增强功能。
(C)与门面模式的关系:有的时候,门面模式兼任代理的责任.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值