代理模式使用代理对象完成用户请求,屏蔽用户对真实对象的访问。现实世界的代理人被授权执行当事人的一些事宜,无需当事人出面,从第三方的角度看,似乎当事人并不存在,因为他只和代理人通信。而事实上代理人是要有当事人的授权,并且在核心问题上还需要请示当事人。
在软件设计中,使用代理模式的意图也很多,比如因为安全原因需要屏蔽客户端直接访问真实对象,或者在远程调用中需要使用代理类处理远程方法调用的技术细节 (如 RMI),也可能为了提升系统性能,对真实对象进行封装,从而达到延迟加载的目的。
写法
没有什么可写的,就是用一个代理类继承/实现接口从而内部包含真实对象.在客户端使用代理类.
需要注意的是我们通常使用接口,实现具体被代理对象和代理类以及客户端的解耦:
代理模式角色分为 4 种:
主题接口:定义代理类和真实主题的公共对外方法;
真实主题:真正实现业务逻辑的类;
代理类:用来代理和封装真实主题;
客户端: 使用代理类和主题接口完成一些工作。
使用场景
代理模式的重点是你可以通过代理实现什么.
延迟加载
假设系统启动时需要加载一个很大的资源,启动时间很长,这时我们把可以把实际加载资源的操作封进代理类, 由代理类实现延迟加载(不用不加载),外部客户端调用统一使用代理类.
比如一个例子:
public interface Image {
void display();
}
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName){
System.out.println("Loading " + fileName);
}
}
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
}
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 图像将从磁盘加载
image.display();
System.out.println("");
// 图像不需要从磁盘加载
image.display();
}
}
附加处理
当调用真实的对象时,代理处理另外一些事。比如打印日志.
远程调用
RPC远程调用
安全代理
用来控制真实对象访问时的权限。一般用于对象应该有不同的访问权限的时候
动态代理
上面我们主要演示了手写代码实现的静态代理,
实际java支持基于JDK/cglib的动态代理,两者有不同的特点.