在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保姆、找工作等都可以通过找中介完成。

在软件设计中,使用代理模式的例子也很多,例如,要访问的远程对象比较大(如视频或大图像等),其下载要花很多时间。还有因为安全原因需要屏蔽客户端直接访问真实对象,如某单位的内部数据库等。

代理模式的定义与特点

代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

代理模式的主要优点有:

  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
  • 代理对象可以扩展目标对象的功能;
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性

其主要缺点是:

  • 代理模式会造成系统设计中类的数量增加
  • 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
  • 增加了系统的复杂度;

那么如何解决以上提到的缺点呢?答案是可以使用动态代理方式

代理模式的结构与实现

代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问,下面来分析其基本结构和实现方法。

1. 模式的结构

代理模式的主要角色如下。

  1. 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  2. 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  3. 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

其结构图如图 1 所示。

在代码中,一般代理会被理解为代码增强,实际上就是在原代码逻辑前后增加一些代码逻辑,而使调用者无感知。

根据代理的创建时期,代理模式分为静态代理和动态代理。

  • 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
  • 动态:在程序运行时,运用反射机制动态创建而成

2. 模式的实现

代理模式的实现代码如下:

package proxy;public class ProxyTest {public static void main(String[] args) {Proxy proxy = new Proxy();proxy.Request();}
}//抽象主题
interface Subject {void Request();
}//真实主题
class RealSubject implements Subject {public void Request() {System.out.println("访问真实主题方法...");}
}//代理
class Proxy implements Subject {private RealSubject realSubject;public void Request() {if (realSubject == null) {realSubject = new RealSubject();}preRequest();realSubject.Request();postRequest();}public void preRequest() {System.out.println("访问真实主题之前的预处理。");}public void postRequest() {System.out.println("访问真实主题之后的后续处理。");}
}

程序运行的结果如下:

访问真实主题之前的预处理。
访问真实主题方法...
访问真实主题之后的后续处理。

代理模式的应用实例

【例1】韶关“天街e角”公司是一家婺源特产公司的代理公司,用代理模式实现。

分析:本实例中的“婺源特产公司”经营许多婺源特产,它是真实主题,提供了显示特产的 display() 方法,可以用窗体程序实现(点此下载该实例所要显示的图片)。而韶关“天街e角”公司是婺源特产公司特产的代理,通过调用婺源特产公司的 display() 方法显示代理产品,当然它可以增加一些额外的处理,如包裝或加价等。客户可通过“天街e角”代理公司间接访问“婺源特产公司”的产品,图 2 所示是公司的结构图。

图2 韶关“天街e角”公司的结构图

程序代码如下:

package proxy;import java.awt.*;
import javax.swing.*;public class WySpecialtyProxy {public static void main(String[] args) {SgProxy proxy = new SgProxy();proxy.display();}
}//抽象主题:特产
interface Specialty {void display();
}//真实主题:婺源特产
class WySpecialty extends JFrame implements Specialty {private static final long serialVersionUID = 1L;public WySpecialty() {super("韶关代理婺源特产测试");this.setLayout(new GridLayout(1, 1));JLabel l1 = new JLabel(new ImageIcon("src/proxy/WuyuanSpecialty.jpg"));this.add(l1);this.pack();this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public void display() {this.setVisible(true);}
}//代理:韶关代理
class SgProxy implements Specialty {private WySpecialty realSubject = new WySpecialty();public void display() {preRequest();realSubject.display();postRequest();}public void preRequest() {System.out.println("韶关代理婺源特产开始。");}public void postRequest() {System.out.println("韶关代理婺源特产结束。");}
}

程序运行结果如图 3 所示。

图3 韶关“天街e角”公司的代理产品

代理模式的应用场景

当无法或不想直接引用某个对象或访问某个对象存在困难时,可以通过代理对象来间接访问。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。

前面分析了代理模式的结构与特点,现在来分析以下的应用场景。

  • 远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如,用户申请某些网盘空间时,会在用户的文件系统中建立一个虚拟的硬盘,用户访问虚拟硬盘时实际访问的是网盘空间。
  • 虚拟代理,这种方式通常用于要创建的目标对象开销很大时。例如,下载一幅很大的图像需要很长时间,因某种计算比较复杂而短时间无法完成,这时可以先用小比例的虚拟代理替换真实的对象,消除用户对服务器慢的感觉。
  • 安全代理,这种方式通常用于控制不同种类客户对真实对象的访问权限。
  • 智能指引,主要用于调用目标对象时,代理附加一些额外的处理功能。例如,增加计算真实对象的引用次数的功能,这样当该对象没有被引用时,就可以自动释放它。
  • 延迟加载,指为了提高系统的性能,延迟对目标的加载。例如,Hibernate 中就存在属性的延迟加载和关联表的延时加载。

代理模式的扩展

在前面介绍的代理模式中,代理类中包含了对真实主题的引用,这种方式存在两个缺点。

  1. 真实主题与代理主题一一对应,增加真实主题也要增加代理。
  2. 设计代理以前真实主题必须事先存在,不太灵活。采用动态代理模式可以解决以上问题,如 SpringAOP,其结构图如图 4 所示。

图4 动态代理模式的结构图

代理模式(代理设计模式)详解相关推荐

  1. JDK动态代理模式小白式详解

    动态代理模式到底是干啥的? 答:当我们想去修改一个类的实现,而又不能去直接修改.干预该类的代码时,我们就需要一个该类的代理类来辅助我们. 比如,我们想在每次调用某个类的save方法时,都在日志文件里写 ...

  2. 动态代理模式(实例化详解)

    简介 代理模式通常用于达到对原有系统功能进行扩充的目的, 比如:你刚接手一个别人没有完成的项目,这时你不想动别人原来的代码,还需要添加新功能.这时代理模式,这时代理模式会很好的帮我们解决问题 代理模式 ...

  3. 原型模式(设计模式详解)

    原型模式 描述 实现 使用场景 描述 原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而无需从头开始编写代码. 在原型模式中,一个原型对象作为模 ...

  4. 《设计模式详解》结构型模式 - 代理模式

    代理模式 5.1 代理模式 5.1.1 概述 5.1.2 结构 5.1.3 静态代理 5.1.4 动态代理 JDK 动态代理 JDK 动态代理分析 CGLIB 动态代理 5.1.5 三种代理的对比 5 ...

  5. 《设计模式详解》结构型模式 - 组合模式

    组合模式 5.6 组合模式 5.6.1 概述 5.6.2 结构 5.6.3 案例实现 5.6.4 组合模式的分类 5.6.5 优点 5.6.6 使用场景 完整的笔记目录:<设计模式详解>笔 ...

  6. 《设计模式详解》结构型模式 - 外观模式

    外观模式 5.5 外观模式 5.5.1 概述 5.5.2 结构 5.5.3 案例 5.5.4 使用场景 5.5.5 Tomcat 源码 完整的笔记目录:<设计模式详解>笔记目录,欢迎指点! ...

  7. 《设计模式详解》结构型模式 - 桥接模式

    桥接模式 5.4 桥接模式 5.4.1 概述 5.4.2 结构 5.4.3 案例 5.4.4 使用场景 完整的笔记目录:<设计模式详解>笔记目录,欢迎指点! 结构型模式描述如何将类或对象按 ...

  8. 《设计模式详解》结构型模式 - 适配器模式

    适配器模式 5.2 适配器模式 5.2.1 概述 5.2.2 结构 5.2.3 类适配器模式 5.2.4 对象适配器模式 5.2.5 接口适配器模式 5.2.6 应用场景 5.2.7 JDK 源码 - ...

  9. Nginx(二):反向代理原理 与 配置文件详解

    相关阅读: Nginx(一):Nginx原理概述 与 安装步骤详解 Nginx(二):反向代理原理 与 配置文件详解 Nginx(三):负载均衡策略 与 Nginx静态服务器 Nginx(四):Ngi ...

  10. ssh转发代理:ssh-agent用法详解

    SSH系列文章: SSH基础:SSH和SSH服务 SSH转发代理:ssh-agent用法详解 SSH隧道:端口转发功能详解 使用ssh-agent之前 使用ssh公钥认证的方式可以免去ssh客户端(如 ...

最新文章

  1. SQL Server procedure
  2. 基于sharepoint 2003的内容管理1.0
  3. BeagleBone Black项目实训手册(大学霸内部资料)
  4. Des和Base64的Util
  5. java 服务端客户端数据传输出现乱码
  6. SOCKET编程中,select()函数的作用
  7. Luban(鲁班)——可能是最接近微信朋友圈的图片压缩算法
  8. 《大数据日知录:架构与算法》前言
  9. 无向图求割点(找桥)tarjan
  10. % 在C语言中的用法
  11. 【机器视觉学习笔记】二值图像连通区域提取算法(C++)
  12. xb2xe2 是什么编码 php,python - 这是什么编码,如何解码
  13. vue引入阿里图标库
  14. 【EasyAR学习】平面追踪、表面跟踪和运动跟踪、稀疏空间地图
  15. Android 蓝牙开发 BLE(低功耗) 摩拜单车共享汽车开门实例
  16. 51单片机——LED1357亮,2468闪
  17. 运用awk提取日志文件中的IP地址
  18. ③读后感之《异类不一样的成功启示录》格拉德威尔
  19. Excel如何批量为员工信息表添加照片
  20. css文字怎么显示在一起,css如何让文字成排显示

热门文章

  1. linux系统 too many open files解决方法
  2. 打印机连接,共享打印机出现连接失败,0x0000011b、用户禁用问题
  3. 诗词鉴赏 ————不做新时代的文化穷人
  4. 使用SQL创建视图和存储过程
  5. 微信小程序-讲解bindconfirm回车事件及focus自动获取焦点【超级详细】
  6. Flink内核源码(八)Flink Checkpoint
  7. 华尔街顶级基金更青睐团队投资,高质量人才成为最大资本
  8. Mp3stego使用,附题,实验吧misc-Canon
  9. 仿京东商城商品图片 缩略图+放大镜效果
  10. 高斯回归进行数据预测