1.代理模式
代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
2.代理的种类
如果按照使用目的来划分,代理有以下几种:
(1)远程代理(Remote):为一个位于不同的地址空间的对象提供一个局域代表对象。
(2)虚拟代理(Virtual):根据需要创建一个资源消耗比较大的对象,使得此对象只在需要时才会被真正创建,之前使用的是代理。
(3)Copy-on-write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。
(4)保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。
(5)Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端乐意共享这些结果。
(6)防火墙(firewall)代理:保护目标,不让恶意用户接近。
(7)同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。
(8)智能引用(Smart Referenc)代理:当一个对象被引用是,提供一些额外的操作。
3.代理模式的结构
类图:
抽象主题(Subject):定义了实际对象和代理对象的共同行为,使得能使用实际对象的地方都能使用代理。
代理主题(Proxy):代理类,持有一个被代理的类的引用,可以自由操作被代理对象;用户和被代理类相同的接口,在任何环境中都可以代替被代理类;控制对被代理对象的引用;在引用被代理对象的方法前或者后,一般会执行一些额外操作。
真实主题(RealSubject):被代理类。
4.示例源码
Subject.java
package com.patterns.proxy;
abstract public class Subject
{
abstract public void request();
}
ProxySubject.java
package com.patterns.proxy;
public class ProxySubject extends Subject
{
private RealSubject realSubject;
public ProxySubject()
{
}
public void request()
{
preRequest();
if( realSubject == null )
{
realSubject = new RealSubject();
}
realSubject.request();
postRequest();
}
private void preRequest()
{
System.out.println("pre request from proxy");
}
private void postRequest()
{
System.out.println("after requet from proxy");
}
}
RealSubject.java
package com.patterns.proxy;
public class RealSubject extends Subject
{
public RealSubject()
{
}
public void request()
{
System.out.println("From real subject.");
}
}
Client.java
package com.patterns.proxy;
public class Client
{
private static Subject subject;
static public void main(String[] args)
{
subject = new ProxySubject();
subject.request();
}
}
运行结果:
pre request from proxy
From real subject.
after requet from proxy
代理调用时,在实际对象的调用的前后加入了一些自己的操作(智能引用)。
5.动态代理
在Java中,提供了支持代理模式的接口,可以在运行时间内创建代理对象。
package com.patterns.proxy.reflect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
*
*与代理类相关联的InvocationHandler对象
*
*/
public class ListProxy implements InvocationHandler
{
private Object proxyobj;
public ListProxy(Object obj)
{
proxyobj = obj;
}
/**
*创建代理对象的工厂方法
*
*/
public static Object factory(Object obj)
{
Class<?> cls = obj.getClass();
return Proxy.newProxyInstance( cls.getClassLoader(),
cls.getInterfaces(),//指定被代理的接口函数
new ListProxy(obj) );//指定InvocationHandler
}
/**
* 调用被代理的接口函数的处理,可以添加一些额外的操作
*/
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<String> v = null;
v = (List<String>) factory(new ArrayList<String>());
v.add("New");
v.add("York");
}
}
创建动态代理的过程
(1)指明一系列接口来创建代理对象,上例在工厂方法中指明使用传入参数的接口,如果没有接口的话,本例不适用。
(2)继承InvocationHandler实现一个代理处理器,在创建代理时使用,系统会把它和指定的接口做关联。
(3)invoke函数的改写,invoke函数会拦截被指定的接口,并执行自己的内容。
(4)在运行时,新建代理对象,并运行。
上例中运行结果:
before calling public abstract boolean java.util.List.add(java.lang.Object)
New
after calling public abstract boolean java.util.List.add(java.lang.Object)
before calling public abstract boolean java.util.List.add(java.lang.Object)
York
after calling public abstract boolean java.util.List.add(java.lang.Object)
拦截了被指定的List的接口,包括add();所以在 v.add("New"); v.add("York");时,其实是执行了ListProxy中的invoke的内容