概述:
代理模式,顾名思义就是一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
代理,在显示生活中有很多代理的例子,比如我们可以在售票点买到火车站的火车票,售卖点就是铁路公司的代理,Windows电脑桌面的快捷方式就是应用软件启动程序的代理。
从上面的例子可以明白代理的意图就是代替原有的对象执行该对象的功能。
那么为什么需要代理呢?不能直接访问该对象的功能吗?
因为有时候我们直接访问该对象会比较麻烦,比如 我们买火车票总不能每次跑到几十公里外的火车站去买吧,家门口的售票点就能买到火车站的火车票,简单方便;我们打开软件,总不能打开文件资源管理器,根据安装目录一层层地找到应用启动程序文件(还得记住启动程序文件地路径),多麻烦呀,在桌面放一个代理这个启动程序文件,一键启动快捷方便。
特点:
优点:
- 职责清晰
- 高扩展性
- 智能化
缺点:
- 在客户端和被代理对象之间增加了一个代理对象 ,因此有些类型的代理模式可能会造成请求处理的速度变慢
- 实现代理模式需要额外的工作,有些代理模式实现非常复杂
对比适配器模式和装饰器模式:
- 适配器模式主要改变所考虑对象的接口,代理模式则不能改变所代理的对象的接口
- 装饰器模式主要为了增强功能,代理模式是为了加以控制
使用场景:
- 远程代理
- 虚拟代理
- Copy-on-Write 代理
- 保护(Protect or Access)代理
- Cache代理
- 防火墙(Firewall)代理
- 同步化(Synchronization)代理
- 智能引用(Smart Reference)代理
实现方法:
现在我们有这样一个需求,我们需要加载一个图片返回给客户端进行展示,但是我们程序所在的这个服务器呢特别差,需要减少对象加载对内存的占用。
首先我们有一个图片展示的接口
public interface Image {
void display();
}
然后有一个实际加载图片并实现该接口的RealImage
类来实现实际的加载和展示
public class RealImage implements Image{
private String filename;
public RealImage (String filename){
this.filename = filename;
loadFromDisk(filename);
}
@Override
public void display() {
System.out.println("image display "+ filename);
}
private void loadFromDisk(String filename){
// 这个方法特别占用内存
System.out.println("image loading from disk " +filename);
}
}
然后我们为这个特别占用内存的类创建一个代理类ImageProxy
public class ImageProxy implements Image{
// 代理对象
private RealImage realImage;
private String filename;
public ImageProxy(String filename){
this.filename = filename;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(filename);
}
realImage.display();
}
}
这样客户端每次调用展示图片方法display()
时通过代理类就不用每次去执行loadFromDisk()
方法去加载图片了
public class ProxyTest {
public static void main(String[] args) {
Image image = new ImageProxy("test.jpg");
image.display();
System.out.println("\n");
image.display();
}
}
执行main
方法,我们可以看到loadFromDisk()
方法只被执行了一次
image loading from disk test.jpg
image display test.jpg
image display test.jpg