结构型模式 - 代理模式(控制对象访问)

代理模式(Proxy Pattern)

简介

一个类代表另一个类的功能。创建具有现有对象的对象,以便向外界提供功能的接口。

意图

为其他对象提供一种代理以控制这个对象的访问。

特点

主要解决:在直接访问对象时带来的问题,比如说,访问的对象在远程的机器上,在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大),或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

何时使用:想在访问一个类时做一些控制。
如何解决:增加中间层。
关键代码:实现与被代理类组合。
应用实例:

  1. Windows快捷方式;
  2. 火车票代售点;
  3. 一张支票或银行存单,是资金的代理,支票是市场交易中用来替代现金,并对提供签发人账号上资金的控制;
  4. spring aop;
  • 优点
  1. 职责清晰;
  2. 高扩展性;
  3. 智能化;
  • 缺点
  1. 由于在客户端和真实主题之间增加了代理对象,请求处理速度可能变慢;
  2. 实现代理模式需要额外的工作,有些代理模式实现非常复杂;

外观模式 vs 代理模式

外观模式和代理模式都像用户提供访问内部对象的接口,它们有什么区别呢?

  1. 外观模式提供统一、唯一的接口给用户,主要是为了隐藏内部复杂性,简化交互,而代理并没有修改原有被代理对象的接口,主要是为了提供控制被代理对象的访问,代理接口与原接口一致。
  2. 外观模式提供的可能是一个系统(多个类)的接口的封装,而代理提供的一般是一个类、对象的访问控制。

应用场景

  1. 远程代理;
  2. 虚拟代理;
  3. Copy-on-Write代理;
  4. 保护代理(Protect or Access);
  5. Cache代理;
  6. 防火墙代理(Firewall);

代理模式 vs 适配器模式

适配器模式主要改变所考虑对象接口(因为适配器模式是解决由于接口不兼容而不能使用的问题),而代理模式不能改变所代理类的接口。

代理模式 vs 装饰器模式

装饰器模式是为了增强功能(扩展原有类的功能),而代理模式是为了加以控制。

UML类图

实现代码

  1. 创建接口Image
// Image.java
public interface Image {
      public void display();
}
  1. 创建实现接口的实体类
// 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
posted @ 2021-01-12 16:14  明明1109  阅读(136)  评论(0编辑  收藏  举报