Java设计模式之:代理模式Proxy或Surrogate
代理模式的英文叫做Proxy或Surrogate,所谓代理,就是一个人或者一个机构代表一个机构采取行动。
在一些情况下,一个客户不想活着不能直接引用一个对象,而代理对象可以在客户端和目标对象之间起起到中介作用。
代理的例子:
Windows系统提供的快捷方法,可以使任何对象同时出现多个地方,而不必修改原对象。对快捷方式的调用完全与对原对象的调用一样。
一个名为link1的快捷方式是一个名为explorer.exe的文件的代理。
代理模式的结构:
代理主题角色:
声明了真是主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以使用代理模式
代理主题角色(Proxy):
代理主题角色内部含有对真实主题的引用,从而可以在任何时候操作主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便可以在儿女和时候都可以替代真是主题;控制对真是主题的引用,负责在需要的时候创建主题对象(和删除真是主题对象);代理角色通常在将客户调用传递真实的主题之前或者之后,都要执行某个操作,而不是单纯的将调用船体给真实主题对象。
真实主题对象:
定义了代理角色所代表的真实对象这里给出了一个非常简单的示意性实现,下面给出的是主题角色的示意性源代码:
package com.javapatterns.proxy;
abstract public class Subject
{
//声明一个抽象的请求方法
abstract public void request();
}
下面是具体主题角色的示意性源代码:
package com.javapatterns.proxy;
public class RealSubject extends Subject
{
public RealSubject(){}
//实现请求方法
public void request()
{
System.out.println("From real subject");
}
}
下面是代理主题角色的源代码,代理主题除了将所有的请求原封不动地委派给真实角色之外,还在委派之前和之后分别执行一个preRequset()操作和一个postRequest()操作。
package com.javapatterns.proxy;
public class ProxySubjext extends Subject
{
private RealSubject realSubject;
public ProxySubject(){}
//实现请求方法
public void request()
{
preRequest();
if(realSubject==null)
{
realSubject=new RealSubject();
}
realSubject.request();
postRequest();
}
//请求前的操作
private void preRequest()
{
//something your want to do before requesting
}
//请求后的操作
private void postRequest()
{
//something you want to do after requesting
}
}
在使用代理主题时,要将变量的明显类型声明为抽象主题的类型,而将其真实类型设置为代理主题类型,如下所示
Subject subject = new ProxySubject(); subject.request();
java对代理模式的支持
java.lang.reflect库中提供下面三个类直接支持代理模式:Proxy,InvocationHandler和Method
Proxy类似的设计师能够在运行时创建代理对象。
当系统有了一个代理对象后,对原对象的方法调用会首先被分派给一个调用处理器(InvocationHandler)
程序可以在调用处理器的invoke()方法中截获这个调用,进行额外的操作。显然java所提供的这一支持是建立在反射的基础上的。
所以设计师可以按照下面的步骤创建动态代理对象:
(1)指明一系列的接口来创建一个代理对象
(2)创建一个调用处理器(Invocation Handler)对象
(3)将这个代理指定为某个其他对象的代理对象
(4)在调用处理器的invoke()方法中采取处理,一方面将调用传递给真实对象,另一个方面执行各种需要的操作。
百闻不如一见,这里提供一个具体的例子讲解java.lang.reflect.Proxy的使用方法。
这个例子要解决为一个Vector对象提供一个代理对象。当你访问Vector的任何方法时,在调用的前后都会分别打印出两条信息。这表明代理对象有能力截获和控制这个Vector对象。
系统仅仅需要一个新的类,称为VectorProxy类,此类需要实现InvocationHandler接口的invoke()方法.
可以看出VectorProxy类必须实现invoke()方法,因为这是InvocationHandler接口的要求,由于Vector对象实现了java.util.List接口,因此,通过调用List的方法,可以控制代理对象。
代码如下:(已经经过JCreator+jdk1.4测试了)
package com.java.patterns.proxy.reflect;
import java.lang.reflect.*;
import java.util.*;
public class VectorProxy implements InvocationHandler
{
//代理对象
private Object proxyobj;
//构造函数
public VectorProxy(Object obj)
{
this.proxyobj=obj;
}
//静态工厂方法
public static Object factory(Object obj)
{
Class cls = obj.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),new VectorProxy(obj));
}
//代理对象的处理函数(实现InvocationHandler接口函数)
/**
*proxy代理对象,这里是proxyobj
*method代理对象执行被代理对象的函数,相当于C++中的函数指针,但Method是个封装函数指针的类,我个人这么认为的^_^
*args是执行函数method的参数数组
*/
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable
{
System.out.println("调用"+method.toString()+"之前");
if(args!=null)
{
System.out.println("调用参数:");
for(int i=0;i<args.length;i++)
{
System.out.println(args[i]+"/");
}
}
Object o = method.invoke(proxyobj,args);
System.out.println("调用"+method.toString()+"之后");
System.out.println("___________________________________________________");
return o;
}
public static void main(String[] args)
{
List v = null;
//List是Vector实现的一个接口,所以可以用这个接口指向实际的代理对象,详细问题查Jdk去,
//我一般很负责任的,只是有时候偷懒
v = (List)factory(new Vector());
v.add("Hello");
v.add("ByeBye");
v.add(1,"Welcome");
v.remove(0);
v.remove(1);
}
}
也就是说代理对象截获了对Vector对象的所有调用,再调用传递给Vector之前和之后,代理对象具有采取合适操作的灵活性,虽然这里代理对象采取的操作不过就是打印出两种信息。