结构型模式 - 代理模式(控制对象访问)
代理模式(Proxy Pattern)
简介
一个类代表另一个类的功能。创建具有现有对象的对象,以便向外界提供功能的接口。
意图
为其他对象提供一种代理以控制这个对象的访问。
特点
主要解决:在直接访问对象时带来的问题,比如说,访问的对象在远程的机器上,在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大),或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。
关键代码:实现与被代理类组合。
应用实例:
- Windows快捷方式;
- 火车票代售点;
- 一张支票或银行存单,是资金的代理,支票是市场交易中用来替代现金,并对提供签发人账号上资金的控制;
- spring aop;
- 优点
- 职责清晰;
- 高扩展性;
- 智能化;
- 缺点
- 由于在客户端和真实主题之间增加了代理对象,请求处理速度可能变慢;
- 实现代理模式需要额外的工作,有些代理模式实现非常复杂;
外观模式 vs 代理模式
外观模式和代理模式都像用户提供访问内部对象的接口,它们有什么区别呢?
- 外观模式提供统一、唯一的接口给用户,主要是为了隐藏内部复杂性,简化交互,而代理并没有修改原有被代理对象的接口,主要是为了提供控制被代理对象的访问,代理接口与原接口一致。
- 外观模式提供的可能是一个系统(多个类)的接口的封装,而代理提供的一般是一个类、对象的访问控制。
应用场景
- 远程代理;
- 虚拟代理;
- Copy-on-Write代理;
- 保护代理(Protect or Access);
- Cache代理;
- 防火墙代理(Firewall);
代理模式 vs 适配器模式
适配器模式主要改变所考虑对象接口(因为适配器模式是解决由于接口不兼容而不能使用的问题),而代理模式不能改变所代理类的接口。
代理模式 vs 装饰器模式
装饰器模式是为了增强功能(扩展原有类的功能),而代理模式是为了加以控制。
UML类图
实现代码
- 创建接口Image
// Image.java
public interface Image {
public void display();
}
- 创建实现接口的实体类
// RealImage.java
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk();
}
@Override
public void display() {
System.out.println("Image: RealImage display");
}
public void loadFromDisk() {
System.out.println("RealImage: load image from path = " + fileName);
}
}
// ProxyImage.java
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
public void display() {
if(null == realImage) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
3.使用ProxyImage来获取RealImage类的对象
// ProxyPatternDemo.java
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
image.display(); // 从磁盘加载
System.out.println("");
image.display(); // 无需从磁盘加载
}
}
运行结果
RealImage: load image from path = test.jpg
Image: RealImage display
Image: RealImage display