设计模式——1_6 代理(Proxy)

诗有可解不可解,若镜花水月勿泥其迹可也

—— 谢榛

文章目录

  • 定义
  • 图纸
  • 一个例子:图片搜索器
    • 图片加载
    • 搜索器
      • 直接在Image添加
      • 组合他们
  • 各种各样的代理
    • 远程代理:镜中月,水中花
    • 保护代理:对象也该有隐私
    • 引用代理:我什么时候可以动手?
    • 虚拟代理:我们真的需要全部信息吗?

定义

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


图纸

请添加图片描述


一个例子:图片搜索器

某天,你突发奇想,想做一个可以展示指定文件夹内所有图片的桌面应用。这个应用很简单,遍历文件夹,发现图片文件,把图片加载到GUI上的图片列表里,显示图片名和图片,就像这样:

在这里插入图片描述


图片加载

为了实现这样的效果,你编写了自己的 Image 类簇,并给予他一个通过 InputStream 来载入图片并获取图片信息的方法,就像这样:

在这里插入图片描述

我们可以通过 Image 中的 loadByStream 方法把参数输入流内的图片文件加载到内存中来,并把获取到的信息写到 messageMap 中,根据需要获取里面的内容反馈给 client

至此,不出意外的话我们根据 Image对象 提供的信息绘制出GUI后就可以得到截图类似的效果


搜索器

随着文件夹里面的图片越来越多,在里面找到你需要的变得越来越困难,于是新的想法出现了,你想要加一个搜索框,用于筛选读取到的图片


这个需求很合理,但是实现起来却出现了问题

Image 是通过把图片载入到内存的方式来获取图片信息的,这就意味着我要获取所有图片的文件名用于搜索之前必须加载所有的图片,这是无法接受的


经过我们分析,只要不把文件加载到内存里,只是遍历文件夹获取其中的所有文件的文件名是很快的,通过File

也就是说,对于一个文件来说,他在程序里会同时拥有对应的 Image对象 和 File对象

我当然希望这两个对象可以绑定在一起,那该怎么做呢?


直接在Image添加

直接添加到Image中,就像这样:

在这里插入图片描述

看起来很美好,也很必要

可是我要为将来考虑,这个程序里面的 Image 不一定都从硬盘上读取文件,我允许他从任何输入流中加载图片出来

这种时候file对象的存在就显得很尴尬,而且会导致getName方法的异常,我又得给他写 if(file==null)……

这显然是很糟糕的设计


组合他们

既然直接添加不可以,那很显然就只能用另一个类来把他们组合起来

但是怎么组合,有讲究

组合他们的这个类本质上还是Image,我并不是为了用这个类的对象来复制/删除文件……他的任务是包含了 Image 的任务的

所以我们可以考虑这样做:

在这里插入图片描述

我们创建了一个 Image类 的 代理类 ImageFileProxy,这个代理类本质上还是 Image,当你调用他的 loadByStream 或者 getWidth 之类的方法时,他直接会去调用 super 对象的对应方法

而当你访问 getName 的时候,他里面藏着的 File 会处理对应的业务,他才不管你现在有没有把图片加载完。这样一来就可以实现一边加载一边查询了


不要小看这种写法,将来如果你突发奇想想在加载图片的时候增加一个加载进度条,那也只是新增Image的子类而已,对已有的代码不会有什么影响

那你会说,这种实现跟代理的图纸差别太大了,这不就是我平时用的继承吗?

你可以试着把Image的接口抽象出来,并在ImageFileProxy的构造方法中要求传入Image对象,就像这样:

在这里插入图片描述

是不是发现他成了一个标准的代理实现?



各种各样的代理

远程代理:镜中月,水中花

远程代理是指在不同的地址空间里提供对相同内容的局部代表

是不是觉得这个定义老复杂了,emmmm,举个例子,比如说数组的复制,就像这样:

数组A里存着 X/Y/Z 三个对象,接着我们复制数组A得到数组B。数组A和B的内存地址当然是不一样的,但B里面存的还是 X/Y/Z。操作B,其实跟操作A没什么区别,其实此时B就能算是A的一个远程代理


真正让远程代理广为人知的是网络相关的开发

比如说现在我有Java写成的 服务器和N个客户机,我希望在服务器上有个按钮,点击后可以直接获取客户机上的硬件信息。

要做成这个效果,根据不同的连接方式,实现方法各不相同。其中一种是利用 RMI技术,让服务器直接调用客户机上运行的对象里的方法,并获取结果,这时候其实就是在服务器上建立客户机的 远程代理

是的,你没看错,我说的就是在服务器JVM上调用运行在其他JVM上的对象。这不是魔法,是真实可行的技术,同时他也是分布式的基础,也是远程代理大放异彩的舞台


保护代理:对象也该有隐私

当你需要管理N个具有相同根类对象的时候,十有八九会用到 容器,List也好,Set也好,或者数组、Map 这不重要

重要的是这些容器对象拥有对自己所存储的对象的完全掌控权,我的意思是说,client 可以随自己喜好对容器里面的内容增删改查,这完全不受控

不是所有的容器都允许随意往里添加或删除的内容的,这时候你就需要隐藏容器的某些接口


我们会再建一个类把真正的容器类封装起来,接着不提供被隐藏的接口的访问方式(或者根据不同的权限提供不同的行为)。而 client 只能和外部的 代理类 交互,至此实现对容器的保护,这就是保护代理


引用代理:我什么时候可以动手?

如果说工厂方法之类的模式提供了对一个对象的 创建行为的包装 的话,那么引用代理就是 对一个对象提供从创建到销毁全方面的包装

因为 client 只能通过代理类对象来访问被代理的对象,那么所有对被代理的对象的访问都是在代理类对象的监控之下的。只要你想,你可以知道被代理对象现在被多少个地方引用,他有没有进入某个有锁的区域,也可以决定被代理对象什么时候被初始化……

知道这些信息是有用的,打个比方:

  • 知道多少个引用:可以做引用计数、可以在丢失所有引用时释放资源
  • 了解状态是否被锁:可以控制别的对象不允许修改被代理对象的状态
  • 决定何时初始化:是第一次被访问时初始化?还是跟代理类对象一起被初始化?

引用代理可以给你的程序提供很多很偏门的优化手段哒


虚拟代理:我们真的需要全部信息吗?

代理模式可以提供对对象的一种访问控制

这种控制可以是限制对象公开的接口(保护代理);也可以用来管理被代理对象何时释放(引用代理

他甚至可以做到在某个内容没有被加载进来的情况下展示他的一部分,这就是虚拟代理

试想以下,当我们需要获取一个文件的名字和修改时间,有必要把整个文件都加载到内存里过一遍吗?

答案必然是否定的。要不然你打开【我的电脑】里面的目录一定要很久(因为你打开的时候需要过一遍文件夹里所有的文件

在Java程序里,我们用 File 来表示一个文件,通过 File 对象的方法我们可以获取到和他所代表的文件有关的各种信息

那么请问,File 在获取硬盘上的文件的信息的时候,真的每次都会把整个文件加载到程序中吗?

肯定没有啊。倒不如说在你用 IO流 让这个文件流入程序之前,硬盘上的那个文件根本没有被载入

也就是说 File对象 和硬盘上的那个文件之间,也存在一种代理关系

File 为我们提供了一系列操作文件和读取文件信息的接口;但是换句话来说, File对象 也控制着我们访问文件的路径和方式,让我们一定是按照 File类 的编写者的想法去跟文件交互,就像 getter&setter 一样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/642790.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jupyter Notebook安装使用教程

Jupyter Notebook 是一个基于网页的交互式计算环境,允许你创建和共享包含代码、文本说明、图表和可视化结果的文档。它支持多种编程语言,包括 Python、R、Julia 等。其应用场景非常广泛,特别适用于数据科学、机器学习和教育领域。它可以用于数…

vue element MessageBox.prompt this.$prompt组件禁止显示右上角关闭按钮,取消按钮,及点击遮罩层关闭

vue element MessageBox.prompt this.$prompt组件禁止或取消显示右上角关闭按钮,取消按钮,及点击遮罩层关闭 实现效果: 实现代码 MessageBox.prompt(请先完成手机号绑定, 系统提示, {confirmButtonText: 提 交,showClose: false,closeOnClic…

linux之安装配置VM+CentOS7+换源

文章目录 一、centos07安装二、CentOS 07网络配置2.1解决CentOS 07网络名不出现问题此博主的论文可以解决2.2配置(命令: 【ip a】也可查看ip地址) 三、使用链接工具链接CentOS进行命令控制四、换软件源 一、centos07安装 1、在vmvare中新建虚拟机 2、下…

Linux:动静态库的概念与制作使用

文章目录 动静态库基础认知动静态库基本概念静态库的制作库的概念包的概念 静态库的使用第三方库小结 动态库的制作动态库的使用动态库如何找到内容?小结 本篇要谈论的内容是关于动静态库的问题,具体的逻辑框架是建立在库的制作,库的使用&…

mysql INSERT数据覆盖现有元素(若存在)

INSERT...ON DUPLICATE KEY UPDATE的使用 如果指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则会更新ON DUPLICATE KEY UPDATE关键字后面的字段值。 例如,如果列a被定义为UNIQUE&#xff0…

不要为了学习而学习

经常有朋友问我: 老师,从您这里学了很多方法,也一直想要改变自己,但总是没办法坚持下去,怎么办? 这个问题,我也很无奈啊。毕竟我也没办法飞到你身边,手把手把每一步都教给你。&…

Eyes Wide Shut? Exploring the Visual Shortcomings of Multimodal LLMs

大开眼界?探索多模态模型种视觉编码器的缺陷。 论文中指出,上面这些VQA问题,人类可以瞬间给出正确的答案,但是多模态给出的结果却是错误的。是哪个环节出了问题呢?视觉编码器的问题?大语言模型出现了幻觉&…

七八分钟快速用k8s部署springboot前后端分离项目

前置依赖 k8s集群,如果没有安装,请先安装 kubectl ,客户端部署需要依赖 应用镜像构建 应用镜像构建不用自己去执行,相关镜像已经推送到docker hub 仓库,如果要了解过程和细节,可以看一下,否…

基于springboot+vue的足球青训俱乐部管理系统(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究背景…

C++逆向分析--虚函数(多态的前置)

先理解一件事,在intel汇编层面来说,直接调用和间接调用的区别。 直接调用语法: call 地址 硬编码为 :e8 间接调用语法: call [ ...] 硬编码为: FF 那么在C语法中,实现多态的前提是父类需要实现多态的成员…

「 网络安全术语解读 」通用攻击模式检举和分类CAPEC详解

引言:在网络安全领域,了解攻击者的行为和策略对于有效防御攻击至关重要。然而,攻击模式的描述和分类方式缺乏统一性和标准化。为了解决这个问题,MITRE公司创建了CAPEC标准,以提供一个共享和统一的攻击模式分类框架。 1…

一文让你彻底搞懂cookie和session产生漏洞的原理

首先让我们来看看登录的一般流程: 输入账号密码提交给后端;后端进行判断账号密码是否一致,这里的逻辑根据每个程序员的想法去写;如果通过2登录成功,跳转登录成功的页面; 如果通过2登录失败,跳转…

Tensorflow2.0笔记 - 范式norm,reduce_min/max/mean,argmax/min, equal,unique

练习norm,reduce_min/max,argmax/min, equal,unique等相关操作。 范数主要有三种: import tensorflow as tf import numpy as nptf.__version__#范数参考:https://blog.csdn.net/HiWangWenBing/article/details/119707541 tensor tf.convert_to_tensor(…

TensorRT英伟达官方示例解析(二)

系列文章目录 TensorRT英伟达官方示例解析(一) TensorRT英伟达官方示例解析(二) 文章目录 系列文章目录前言一、03-BuildEngineByTensorRTAPI1.1 建立 Logger(日志记录器)1.2 Builder 引擎构建器1.3 Netwo…

【GitHub项目推荐--Awesome-Go/Python/JavaScript/Java】【转载】

Awesome 译为令人惊叹的、极好的,GitHub 上有很多 Awesome 开头的开源项目。比如 Awesome-Go、Awesome-Python。 就像汇总常用的软件一样,GitHub上有大量的开源项目,开发者就会根据需要汇总一些常用的好用的资源,并且根据 Awesom…

OCP NVME SSD规范解读-7.TCG安全日志要求

在OCP NVMe SSD规格中,TCG的相关内容涉及以下几个方面: 活动事件记录: NVMe SSD需要支持记录TCG相关的持久事件日志,用于追踪固态硬盘上发生的与TCG安全功能相关的关键操作或状态变化,如启动过程中的安全初始化、密钥…

当键入网址后,到网页显示,其间发生了什么

解析 URL: 浏览器地址栏输入 URL,浏览器解析 URL,从而生成发送给 web 服务器的请求信息(例如 www.example.com)。 检查域名缓存: 浏览器查看浏览器缓存系统缓存路由缓存, 如有存在缓存&#x…

SQL注入实战:盲注

盲注: 1、当攻击者利用SQL注入漏洞进行攻击时,有时候web应用程序会显示,后端数据库执行SQL查询返回的错误信息,这些信息能帮助进行SQL注入,但更多时候,数据库没有输出数据web页面,这是攻击者会…

JRT集中打印

之前一直在夯实基础,现在是补demo的时段了。了解过检验集中打印的人知道,集中打印的逻辑有多复杂。既要考虑普通检验报告加上换页。又要考虑微生物报告加上换页,既有A5的报告,也有A4的报告,还要考虑A4打印两个组装A5时…

工程化代码管理高频面试题

1. git常用命令以及工作中都怎么工作 git init 初始化仓库 ​ git status 查看当前各个区域的代码状态。 ​ git log查看commit记录 ​ git reflog查看完整记录 ​ git add 添加工作区代码到暂存区 ​ Git commit 暂存区代码的提交 ​ git reset 代码的版本回退 ​ git stash …