23种设计模式漫画版系列—代理模式(一)

简介: 23种设计模式漫画版系列—代理模式(一)

01意图

代理模式是一种结构型设计模式 让你能够提供对象的替代品或其占位符 代理控制着对于原对象的访问 并允许在将请求提交给对象前后进行一些处理


02问题

为什么要控制对于某个对象的访问呢 举个例子 有这样一个消耗大量系统资源的巨型对象 你只是偶尔需要使用它 并非总是需要

 数据库查询有可能会非常缓慢


你可以实现延迟初始化 在实际有需要时再创建该对象 对象的所有客户端都要执行延迟初始代码 不幸的是 这很可能会带来很多重复代码

在理想情况下 我们希望将代码直接放入对象的类中 但这并非总是能实现 比如类可能是第三方封闭库的一部分


03解决方案

代理模式建议新建一个与原服务对象接口相同的代理类 然后更新应用以将代理对象传递给所有原始对象客户端 代理类接收到客户端请求后会创建实际的服务对象 并将所有工作委派给它

代理将自己伪装成数据库对象 可在客户端或实际数据库对象不知情的情况下处理延迟初始化和缓存查询结果的工作



这有什么好处呢 如果需要在类的主要业务逻辑前后执行一些工作 你无需修改类就能完成这项工作 由于代理实现的接口与原类相同 因此你可将其传递给任何一个使用实际服务对象的客户端



04真实世界类比


信用卡和现金在支付过程中的用处相同


信用卡是银行账户的代理 银行账户则是一大捆现金的代理 它们都实现了同样的接口 均可用于进行支付 消费者会非常满意 因为不必随身携带大量现金 商店老板同样会十分高兴 因为交易收入能以电子化的方式进入商店的银行账户中 无需担心存款时出现现金丢失或被抢劫的情况



05代理模式


06伪代码

本例演示如何使用代理模式在第三方腾讯视频 TencentVideo 代码示例中记为 TV 程序库中添加延迟初始化和缓存

使用代理缓冲服务结果

程序库提供了视频下载类 但是该类的效率非常低 如果客户端程序多次请求同一视频 程序库会反复下载该视频 而不会将首次下载的文件缓存下来复用

代理类实现和原下载器相同的接口 并将所有工作委派给原下载器 不过 代理类会保存所有的文件下载记录 如果程序多次请求同一文件 它会返回缓存的文件

// 远程服务接口。interface ThirdPartyTVLib is
    method listVideos()
    method getVideoInfo(id)
    method downloadVideo(id)// 服务连接器的具体实现。该类的方法可以向腾讯视频请求信息。请求速度取决于// 用户和腾讯视频的互联网连接情况。如果同时发送大量请求,即使所请求的信息// 一模一样,程序的速度依然会减慢。class ThirdPartyTVClass implements ThirdPartyTVLib is
    method listVideos() is
        // 向腾讯视频发送一个 API 请求。
    method getVideoInfo(id) is
        // 获取某个视频的元数据。
    method downloadVideo(id) is
        // 从腾讯视频下载一个视频文件。// 为了节省网络带宽,我们可以将请求结果缓存下来并保存一段时间。但你可能无// 法直接将这些代码放入服务类中。比如该类可能是第三方程序库的一部分或其签// 名是`final(最终)`。因此我们会在一个实现了服务类接口的新代理类中放入// 缓存代码。当代理类接收到真实请求后,才会将其委派给服务对象。class CachedTVClass implements ThirdPartyTVLib is
    private field service: ThirdPartyTVLib
    private field listCache, videoCache
    field needReset
    constructor CachedTVClass(service: ThirdPartyTVLib) is
        this.service = service
    method listVideos() is
        if (listCache == null || needReset)
            listCache = service.listVideos()
        return listCache
    method getVideoInfo(id) is
        if (videoCache == null || needReset)
            videoCache = service.getVideoInfo(id)
        return videoCache
    method downloadVideo(id) is
        if (!downloadExists(id) || needReset)
            service.downloadVideo(id)// 之前直接与服务对象交互的 GUI 类不需要改变,前提是它仅通过接口与服务对// 象交互。我们可以安全地传递一个代理对象来代替真实服务对象,因为它们都实// 现了相同的接口。class TVManager is
    protected field service: ThirdPartyTVLib
    constructor TVManager(service: ThirdPartyTVLib) is
        this.service = service
    method renderVideoPage(id) is
        info = service.getVideoInfo(id)
        // 渲染视频页面。
    method renderListPanel() is
        list = service.listVideos()
        // 渲染视频缩略图列表。
    method reactOnUserInput() is
        renderVideoPage()
        renderListPanel()// 程序可在运行时对代理进行配置。class Application is
    method init() is
        aTVService = new ThirdPartyTVClass()
        aTVProxy = new CachedTVClass(aTVService)
        manager = new TVManager(aTVProxy)
        manager.reactOnUserInput()


07代理模式适合应用场景

使用代理模式的方式多种多样 我们来看看最常见的几种

延迟初始化 虚拟代理 如果你有一个偶尔使用的重量级服务对象 一直保持该对象运行会消耗系统资源时 可使用代理模式

你无需在程序启动时就创建该对象 可将对象的初始化延迟到真正有需要的时候

访问控制 保护代理 如果你只希望特定客户端使用服务对象 这里的对象可以是操作系统中非常重要的部分 而客户端则是各种已启动的程序 包括恶意程序 此时可使用代理模式

代理可仅在客户端凭据满足要求时将请求传递给服务对象

本地执行远程服务 远程代理 适用于服务对象位于远程服务器上的情形

在这种情形中 代理通过网络传递客户端请求 负责处理所有与网络相关的复杂细节

记录日志请求 日志记录代理 适用于当你需要保存对于服务对象的请求历史记录时

代理可以在向服务传递请求前进行记录

缓存请求结果 缓存代理 适用于需要缓存客户请求结果并对缓存生命周期进行管理时 特别是当返回结果的体积非常大时

代理可对重复请求所需的相同结果进行缓存 还可使用请求参数作为索引缓存的键值

智能引用 可在没有客户端使用某个重量级对象时立即销毁该对象

代理会将所有获取了指向服务对象或其结果的客户端记录在案 代理会时不时地遍历各个客户端 检查它们是否仍在运行 如果相应的客户端列表为空 代理就会销毁该服务对象 释放底层系统资源

代理还可以记录客户端是否修改了服务对象 其他客户端还可以复用未修改的对象

08实现方式

1. 如果没有现成的服务接口 你就需要创建一个接口来实现代理和服务对象的可交换性 从服务类中抽取接口并非总是可行的 因为你需要对服务的所有客户端进行修改 让它们使用接口 备选计划是将代理作为服务类的子类 这样代理就能继承服务的所有接口了

2. 创建代理类 其中必须包含一个存储指向服务的引用的成员变量 通常情况下 代理负责创建服务并对其整个生命周期进行管理 在一些特殊情况下 客户端会通过构造函数将服务传递给代理

3. 根据需求实现代理方法 在大部分情况下 代理在完成一些任务后应将工作委派给服务对象

4. 可以考虑新建一个构建方法来判断客户端可获取的是代理还是实际服务 你可以在代理类中创建一个简单的静态方法 也可以创建一个完整的工厂方法

5. 可以考虑为服务对象实现延迟初始化

09代理模式优缺点

  • 你可以在客户端毫无察觉的情况下控制服务对象
  • 如果客户端对服务对象的生命周期没有特殊要求 你可以对生命周期进行管理
  • 即使服务对象还未准备好或不存在 代理也可以正常工作
  • 你可以在不对服务或客户端做出修改的情况下创建新代理
  • 代码可能会变得复杂 因为需要新建许多类
  • 服务响应可能会延迟

10与其他模式的关系

  • 适配器模式能为被封装对象提供不同的接口 代理模式能为对象提供相同的接口 装饰模式则能为对象提供加强的接口
  • 外观模式与代理的相似之处在于它们都缓存了一个复杂实体并自行对其进行初始化与其服务对象遵循同一接口 使得自己和服务对象可以互换 在这一点上它与不同
  • 装饰和代理有着相似的结构 但是其意图却非常不同 这两个模式的构建都基于组合原则 也就是说一个对象应该将部分工作委派给另一个对象 两者之间的不同之处在于通常自行管理其服务对象的生命周期的生成则总是由客户端进行控制



相关文章
|
6月前
|
设计模式 缓存 监控
【设计模式系列笔记】代理模式
代理模式是一种结构型设计模式,它允许一个对象(代理对象)控制另一个对象的访问。代理对象通常充当客户端和实际对象之间的中介,用于对实际对象的访问进行控制、监控或其他目的。
121 1
|
6月前
|
设计模式 缓存 安全
小谈设计模式(8)—代理模式
小谈设计模式(8)—代理模式
|
2月前
|
设计模式 缓存 安全
设计模式——代理模式
静态代理、JDK动态代理、Cglib 代理
设计模式——代理模式
|
6月前
|
设计模式 Java
Java一分钟之-设计模式:装饰器模式与代理模式
【5月更文挑战第17天】本文探讨了装饰器模式和代理模式,两者都是在不改变原有对象基础上添加新功能。装饰器模式用于动态扩展对象功能,但过度使用可能导致类数量过多;代理模式用于控制对象访问,可能引入额外性能开销。文中通过 Java 代码示例展示了两种模式的实现。理解并恰当运用这些模式能提升代码的可扩展性和可维护性。
65 1
|
2月前
|
设计模式 Java 数据安全/隐私保护
Java设计模式-代理模式(7)
Java设计模式-代理模式(7)
|
6月前
|
设计模式 Java 数据库连接
【重温设计模式】代理模式及其Java示例
【重温设计模式】代理模式及其Java示例
|
3月前
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
3月前
|
设计模式
设计模式的基础问题之代理模式在工作中的问题如何解决
设计模式的基础问题之代理模式在工作中的问题如何解决
|
4月前
|
设计模式 算法 Go
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
|
4月前
|
设计模式 缓存 JavaScript
js设计模式【详解】—— 代理模式
js设计模式【详解】—— 代理模式
32 0

热门文章

最新文章

  • 1
    C++一分钟之-设计模式:工厂模式与抽象工厂
    43
  • 2
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    50
  • 3
    C++一分钟之-C++中的设计模式:单例模式
    58
  • 4
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    38
  • 5
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    64
  • 6
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    59
  • 7
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    42
  • 8
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    50
  • 9
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    112
  • 10
    Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
    78