1、定义
为其他对象提供一种代理以控制对这个对象的访问。
2、使用场景
当无法或不想直接访问某个对象或者访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。
3、UML图
4、代码示例
public interface Subject {
public void visit();
}
//被代理类
public class RealSubject implements Subject {
@Override
public void visit() {
System.out.println("RealSubject visit");
}
}
//代理类
public class ProxySubject implements Subject {
private Subject mSubject;
public ProxySubject(Subject mSubject) {
this.mSubject = mSubject;
}
@Override
public void visit() {
//转调被代理对象的方法
mSubject.visit();
}
}
public class Client {
public static void main(String args[]) {
Subject realSub = new RealSubject();
//构造一个代理对象
ProxySubject proxySub = new ProxySubject(realSub);
//调用代理对象的方法
proxySub.visit();
}
}
5、Java的动态代理
以上自己实现的代理模式称为Java 的静态代理,这种实现有个较大的缺点,就是如果 Subject 接口发生变化,那么代理类和目标实现都要变化,不是很灵活。
通过Java内建的代理模式来实现的代理称为Java的动态代理。动态代理不像静态代理那样要实现Subject 接口的方法,而是只有一个 invoke 方法。
Java动态代理目前只能代理接口,基本的实现时依靠Java的反射机制和动态生成 class 的技术,来动态生成被代理的接口的实现对象。
示例代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//需要实现 InvocationHandler 接口
public class DynamicProxySubject implements InvocationHandler {
private Subject mSubject;
public DynamicProxySubject(Subject mSubject) {
this.mSubject = mSubject;
}
//需要实现 invoke 方法
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(mSubject, args);
return result;
}
}
public class Client {
public static void main(String args[]) {
Subject realSub = new RealSubject();
//构造一个动态代理对象
DynamicProxySubject dynamicProxy = new DynamicProxySubject(realSub);
ClassLoader loader = realSub.getClass().getClassLoader();
Subject sub = (Subject) Proxy.newProxyInstance(loader, new Class[] {Subject.class}, dynamicProxy);
//调用代理对象的方法
sub.visit();
}
}
5、代理模式的类型
代理模式在客户个被客户访问的对象之间引入了一定程度的间接性,不同的代理类型,这种附加的间接性有不同的用途,也有不同的特点。
- 远程代理(Remote Proxy):为某个对象在不同的内存地址空间提供局部代理,使系统可以将Server部分的实现隐藏,以便Client可以不必考虑Server的存在。
- 虚拟代理(Virtual Proxy):使用一个代理对象表示一个十分耗资源的对象并在真正需要时才创建。
- 保护代理(Protection Proxy):使用代理控制对原始对象的访问。这种类型的代理常被用于原始对象有不同访问权限的情况。
- 智能引用(Smart Reference):在访问原始对象时,执行一些自己附加的操作并对指向原始对象的引用计数。
注意:静态和动态代理都可以应用于上述4中情形,两者是各自独立的变化。