概述
- 定义:为其他对象提供一种代理以控制对这个对象的访问
- 适用场景:
- 远程代理:为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实
- 虚拟代理:根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象
- 安全代理:用来控制真实对象访问时的权限
- 智能代理:是指当调用真实的对象时,代理处理另外一些事
实现
静态代理
public interface ISubject {
void work();
}
// 被代理的类
public class ConcreteSubject implements ISubject {
@Override
public void work() {
System.out.println("working");
}
}
// 代理
public class Proxy implements ISubject {
private ISubject subject;
public Proxy() {
this.subject = new ConcreteSubject();
}
@Override
public void work() {
// 扩展原始work()方法,添加输出执行耗时功能
long start = System.currentTimeMillis();
subject.work();
long end = System.currentTimeMillis();
System.out.println("duration: " + (end - start));
}
}
// 客户端
public class Client {
public static void main(String[] args) throws Exception {
ISubject sub = new Proxy();
sub.work();
}
}
动态代理
当要对多个类使用代理模式时,使用静态代理会产生大量的代理类,为了解决这个问题,动态代理出现了
jdk中要实现动态代理,需要实现InvocationHandler接口
public class DynamicProxy implements InvocationHandler {
private ISubject real;
public DynamicProxy() {
this.real = new ConcreteSubject();
}
// 当调用被注册代理接口中的方法时,该方法会自动被调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object ret = method.invoke(real, args);
long end = System.currentTimeMillis();
System.out.println("duration: " + (end - start));
return ret;
}
}
// 客户端
public class Client {
public static void main(String[] args) throws Exception {
ClassLoader loader = Client.class.getClassLoader();
ISubject proxy = (ISubject) Proxy.newProxyInstance(loader, new Class<?>[] { ISubject.class }, new DynamicProxy());
proxy.work();
}
}
与装饰器模式的区别
无论从功能还是从实现上看,装饰器模式和代理模式都十分相似,总给人一种这两货一模一样的感觉,但仔细思考后会发现两者确实不同
- 装饰器模式更加关注于功能的扩展
- 代理模式更关注与对象的控制
换言之,代理模式可以对客户端隐藏一个对象的信息,而装饰器模式一般不用这么干
再直白点就是装饰器模式中装饰器的构造方法一般会传入一个参数当作被装饰对象,但是代理模式中被代理类一般是在代理类中创建的而非参数传递
// 装饰器模式
public class Decorator implements ISubject {
private ISubject subject;
public Decorator(ISubject subject) {
this.subject = subject;
}
...
}
// 代理模式
public class Proxy implements ISubject {
private ISubject subject;
public Proxy() {
this.subject = new ConcreteSubject();
}
...
}