ps:图片来自网络
实现代码:
package com.psyco.proxy;
//抽象角色
public interface Subject {
public void doSomething();
}
/*
* 真实对象
*/
public class RealSubject implements Subject {
public void doSomething() {
System. out.println("realStubject done.." );
}
}
public class ProxySubject implements Subject {
private Subject img ;
@Override
public void doSomething() {
if (img == null) {
img = new RealSubject(); //这时候才去调用真是对象的方法
}
img.doSomething();
}
public void doOtherthing() {
System.out.print("to do other method");
}
}
public class Test {
public static void main(String[] args) {
ImgImpl imgl = new ImgImpl();
imgl.doSomething();
}
}
由以上代码可以看出,客户实际需要调用的是RealSubject类的doSomething()方法,现在用ProxySubject来代理 RealSubject类,同样达到目的,同时还可以封装了其他方法(doOtherthing()),可以处理一些其他问题。
动态代理类
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。 这个抽象方法在代理类中动态实现。
(2).Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
public class DynamicSubject implements InvocationHandler {
private Subject img ;
public DynamicSubject() {
}
public DynamicSubject(Subject img) {
this.img = img;
}
@Override
public Object invoke(Object proxy, Method method , Object[] args)
throws Throwable {
System. out.println("before calling" + method );
method.invoke(img, args);
System. out.println("after calling" + method );
return null ;
}
}
public class Test {
public static void main(String[] args) {
// apointe proxy class
RealSubject img = new RealSubject();
InvocationHandler ds = new DynamicSubject(img);
Class cls = img.getClass();
//ceate a proxy
Subject imgi = (Subject)Proxy. newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds);
System. out.println(cls.getClassLoader().getClass().getPackage());
System. out.println(cls.getInterfaces().getClass().getName());
imgi.doSomething();
}
}
程序运行结果:
before calling public abstract void Subject.request()
From real subject.
after calling public abstract void Subject.request()
通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。
总结:代理模式适合的场合
- 远程代理,也就是为了一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实,就像web service里的代理类一样。
- 虚拟代理,根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象,比如浏览器的渲染的时候先显示问题,而图片可以慢慢显示(就是通过虚拟代理代替了真实的图片,此时虚拟代理保存了真实图片的路径和尺寸。
- 安全代理,用来控制真实对象访问时的权限,一般用于对象应该有不同的访问权限。
- 智能指引,只当调用真实的对象时,代理处理另外一些事情。例如C#里的垃圾回收,使用对象的时候会有引用次数,如果对象没有引用了,GC就可以回收它了。
参考:《大话设计模式》