22.代理模式:思考与解读
原文地址:代理模式:思考与解读 更多内容请关注:深入思考与解读设计模式
引言
在软件开发中,尤其是当对象的访问需要控制时,你是否遇到过这样的问题:某些操作或对象可能需要进行额外的检查、优化或延迟加载,或者你希望控制客户端如何访问一个资源?如果我们有一种方式,可以让客户端通过另一个对象来间接访问原始对象,从而控制这个访问过程,这样的设计是否能提高系统的灵活性和安全性?
代理模式正是为了解决这个问题而设计的。它通过创建一个代理对象,控制客户端对目标对象的访问。你是否理解,为什么通过代理对象可以将访问控制和目标对象的具体实现分离,从而使得系统更具扩展性和可维护性?
在本文中,我们将通过一系列问题,逐步引导你理解代理模式的核心思想、应用场景以及如何实现它。
什么是代理模式?
问题1:你是否曾经需要控制客户端对某个对象的访问?例如,是否希望对某些方法进行权限检查,或者在某些情况下延迟加载对象?
假设你有一个对象,它非常耗时或者非常重要,且你希望控制哪些客户端可以访问它,或者在某些时候才创建它。你通常如何实现这样的控制?
问题2:如果可以通过一个代理对象来控制对目标对象的访问,是否能够在不修改目标对象的情况下,增加额外的行为或控制?
代理模式通过引入一个代理对象来控制对目标对象的访问。你是否理解,为什么这种设计方式可以在不改变目标对象的情况下,灵活地为其增加控制行为?
代理模式的核心概念
问题3:代理模式通常包含哪些角色?每个角色的职责是什么?
代理模式通常包含以下几个核心角色:
-
主题接口(Subject):定义了目标对象和代理对象共同遵循的接口,通常包含一个
request()
方法。 -
真实主题(RealSubject):实现了
Subject
接口,执行实际的操作。 -
代理(Proxy):也实现了
Subject
接口,控制对RealSubject
的访问,可能会增加额外的行为或控制请求。 -
客户端(Client):通过代理对象访问目标对象。
你能理解这些角色是如何协同工作,确保代理对象可以控制对真实对象的访问,并在访问过程中加入额外的功能吗?
问题4:为什么要通过代理对象来控制对真实对象的访问?这种设计如何将访问控制与真实对象的实现解耦?
代理对象负责管理对真实对象的访问,能够在不修改真实对象的情况下,为其增加行为。你是否理解,这种解耦如何使得系统更加灵活,且易于扩展?
问题5:代理模式如何通过延迟加载、权限控制或其他方式增加额外的功能?代理对象是如何决定是否将请求转发给真实对象的?
代理对象可以在转发请求之前执行额外的操作(如权限检查、延迟加载等)。你能理解,为什么这种方式能够帮助我们灵活地控制对象的行为,而不需要改变目标对象本身?
代理模式的实现
假设你正在开发一个系统,其中有一个图片加载模块,这个模块加载图片非常耗时。你希望通过代理模式来延迟加载图片,直到真正需要它的时候。
步骤1:定义主题接口
from abc import ABC, abstractmethodclass Image(ABC):@abstractmethoddef display(self):pass
问题6:为什么我们需要定义一个主题接口(Image
)?它的作用是什么?
Image
接口定义了目标对象和代理对象共同遵循的接口。通过接口,我们可以确保代理对象和真实对象都具备相同的方法,使得客户端代码能够通过统一的接口来访问目标对象。你能理解,为什么这种设计让代理对象能够透明地控制对目标对象的访问?
步骤2:定义真实主题类(真实对象)
class RealImage(Image):def __init__(self, filename: str):self.filename = filenameself.load_image()def load_image(self):print(f"Loading image: {self.filename}")def display(self):print(f"Displaying image: {self.filename}")
问题7:RealImage
类是如何实现Image
接口的?它的display()
方法和load_image()
方法有什么作用?
RealImage
类实现了Image
接口,并在load_image()
方法中加载图片,display()
方法中展示图片。你是否理解,为什么RealImage
负责实际的加载和展示操作,而代理对象则不直接参与这些操作?
步骤3:定义代理类(Proxy)
class ProxyImage(Image):def __init__(self, filename: str):self.filename = filenameself.real_image = Nonedef display(self):if not self.real_image:self.real_image = RealImage(self.filename)self.real_image.display()
问题8:ProxyImage
类是如何控制对RealImage
的访问的?为什么它需要延迟加载RealImage
对象?
ProxyImage
类通过display()
方法来延迟加载RealImage
对象。只有在第一次请求显示图片时,代理对象才会创建RealImage
对象并加载图片。你是否理解,为什么这种延迟加载能够节省资源,且提高系统性能?
步骤4:客户端代码
def main():image1 = ProxyImage("image1.jpg")image2 = ProxyImage("image2.jpg")# 第一次访问时,代理对象会加载图片image1.display() # Loading image: image1.jpg# Displaying image: image1.jpg# 第二次访问时,代理对象不会再次加载图片image1.display() # Displaying image: image1.jpg# 延迟加载另一个图片image2.display() # Loading image: image2.jpg# Displaying image: image2.jpgif __name__ == "__main__":main()
问题9:在客户端代码中,如何通过代理对象来访问真实对象?代理对象如何管理真实对象的加载和显示?
客户端通过代理对象访问图片,而不直接操作RealImage
对象。代理对象会在第一次访问时加载图片,并在后续访问中直接展示图片。你是否理解,为什么代理对象能够有效控制图片的加载过程,并在客户端与真实对象之间起到中介作用?
代理模式的优缺点
问题10:代理模式的优点是什么?它如何帮助我们控制对真实对象的访问,并增加额外的行为?
代理模式通过在客户端和真实对象之间插入代理层,使得我们能够灵活地控制对真实对象的访问。你是否理解,为什么通过代理可以添加权限控制、延迟加载等行为,而不需要修改真实对象的实现?
问题11:代理模式的缺点是什么?它是否可能增加系统的复杂性,尤其是在代理层过多的情况下?
代理模式引入了额外的代理层,可能会导致系统的复杂性增加。你是否认为,当代理层过多时,可能会使系统变得更加难以理解和维护?如何避免过度使用代理模式?
适用场景
问题12:代理模式适用于哪些场景?
代理模式特别适用于以下场景:
-
当需要控制对对象的访问时,例如,延迟加载、缓存控制等。
-
当需要在不修改目标对象的情况下,增加访问控制逻辑时,例如,安全检查、权限控制等。
-
当对象的创建代价高昂,且我们希望延迟对象的创建时。
你能想到其他适用场景吗?例如,数据库连接池、网络请求代理等,是否也可以使用代理模式?
问题13:代理模式是否适用于所有场景?在某些情况下,是否有更合适的设计模式来替代代理模式?
虽然代理模式能够很好地控制访问,但在某些场景中,是否可以通过其他简单的设计模式(如装饰者模式、策略模式)来达到类似的效果?你是否认为,代理模式的引入可能会使得系统过于复杂,尤其是代理对象过多时?
接下来,我们将通过具体的代码示例来加深理解代理模式。
代理模式深入解读
一、引言
代理模式(Proxy Pattern)是一种结构型设计模式,它通过为另一个对象提供一个代理对象来控制对该对象的访问。代理模式的核心思想是通过代理对象来间接访问目标对象,以便可以在访问目标对象时进行一些额外的操作,比如延迟加载、权限检查、日志记录等。
二、简单理解:什么是代理模式?
1. 什么是代理模式?
代理模式的核心思想是:为目标对象提供一个代理对象,客户端通过代理对象访问目标对象。代理对象可以在请求目标对象之前或之后执行一些额外的操作,比如权限检查、日志记录、延迟加载等。代理模式通常用于控制对目标对象的访问。
通俗地讲,代理模式就像是你通过助手来与一个专家进行沟通。你不直接联系专家,而是通过助手。助手可以帮你安排与专家的会面、传达信息,甚至在你不方便的时候代替你进行某些操作。
2. 代理模式的组成部分
代理模式通常包含以下几个部分:
-
主题接口(Subject):定义了目标对象和代理对象的共同接口,客户端通过这个接口与目标对象或代理对象进行交互。
-
真实主题(RealSubject):实现了主题接口,包含具体的业务逻辑,是目标对象。
-
代理对象(Proxy):实现了主题接口,控制对真实主题的访问,并在必要时对请求进行处理。
-
客户端(Client):通过代理对象与目标对象进行交互。
三、用自己的话解释:如何理解代理模式?
1. 类比实际生活中的场景
假设你想咨询一个专家,但专家非常忙,不能直接见每一个人。这时,你可以通过他的秘书(代理对象)来安排会面。秘书会帮你筛选有价值的咨询请求,确保你不会浪费专家的时间。如果秘书认为某个请求不重要,可能会拒绝这个请求;如果请求有价值,秘书会将你引荐给专家(真实主题)。
在编程中,代理模式通过创建代理对象,控制对目标对象的访问。代理对象可以执行额外的操作(如延迟加载、权限检查等),让客户端和目标对象的交互变得更加灵活和高效。
2. 为什么要使用代理模式?
使用代理模式的好处是,它能让我们控制对目标对象的访问。通过代理对象,我们可以在请求前或请求后做一些处理,如权限控制、延迟加载、缓存管理等。代理模式不仅能简化客户端代码,还能提高系统的性能和安全性。
四、深入理解:代理模式的实现
接下来,我们通过一个具体的代码示例来实现代理模式,帮助你更好地理解如何在代码中使用这个模式。
示例:图片显示系统
假设我们有一个图片显示系统,其中图片对象加载需要时间。如果我们每次都直接加载图片,会浪费很多时间和资源。为了提高效率,我们可以使用代理模式,让代理对象在首次加载图片时进行延迟加载(即只在需要时加载图片),而之后就直接使用已经加载的图片。
1. 定义主题接口
# 主题接口:定义目标对象和代理对象的公共接口 class Image:def display(self):pass
2. 定义真实主题类:图片
# 真实主题类:图片
class RealImage(Image):def __init__(self, filename: str):self.filename = filenameself.load_image()def load_image(self):print(f"Loading image from {self.filename}...")def display(self):print(f"Displaying image: {self.filename}")
3. 定义代理类:图片代理
# 代理类:图片代理
class ProxyImage(Image):def __init__(self, filename: str):self.filename = filenameself.real_image = Nonedef display(self):if self.real_image is None:self.real_image = RealImage(self.filename) # 延迟加载图片self.real_image.display() # 使用真实主题类的方法来显示图片
4. 客户端代码:使用代理加载和显示图片
# 客户端代码:通过代理对象加载和显示图片
proxy_image1 = ProxyImage("image1.jpg")
proxy_image2 = ProxyImage("image2.jpg")# 第一次显示时,代理会加载图片
proxy_image1.display() # 输出:Loading image from image1.jpg... Displaying image: image1.jpg
proxy_image2.display() # 输出:Loading image from image2.jpg... Displaying image: image2.jpg# 第二次显示时,代理直接显示已加载的图片
proxy_image1.display() # 输出:Displaying image: image1.jpg
proxy_image2.display() # 输出:Displaying image: image2.jpg
代码解析:
-
Image
类:这是主题接口,定义了目标对象和代理对象的公共方法。display()
方法用于显示图片。 -
RealImage
类:这是真实主题类,表示图片对象。它实现了Image
接口,并提供了加载和显示图片的方法。加载图片的操作是比较耗时的,通常在首次请求时执行。 -
ProxyImage
类:这是代理类,延迟加载图片。它也实现了Image
接口,但在首次调用display()
方法时,代理会先创建RealImage
对象并加载图片。之后,它会直接调用RealImage
的display()
方法来显示图片。 -
客户端代码:客户端通过代理对象来加载和显示图片,代理对象确保只有在需要时才会加载真实图片,而后续的显示操作直接通过代理对象完成。
五、解释给别人:如何讲解代理模式?
1. 用简单的语言解释
代理模式就像是你通过助手来处理一些复杂的事情。你不直接接触专家,而是通过助手来安排和协调工作。代理对象可以做一些额外的事情,比如延迟加载、权限控制等,从而提高系统的效率和安全性。在编程中,代理模式通过代理对象来控制对目标对象的访问,让客户端与目标对象之间的交互更加灵活。
2. 为什么要使用代理模式?
使用代理模式的好处是,它能够控制对目标对象的访问,避免客户端直接与目标对象交互,从而能在目标对象访问之前或之后执行一些附加操作。例如,可以使用代理来实现延迟加载(只有在需要时才加载资源)、权限验证(在访问目标对象之前进行身份验证)等功能。
六、总结
代理模式通过引入代理对象控制对真实对象的访问,并可以为其添加额外的行为或控制,如延迟加载、权限检查等。这种设计能够在不修改真实对象的情况下,为其增加灵活的控制逻辑。
然而,代理模式也可能导致系统复杂性增加,尤其是代理层过多时。因此,在使用代理模式时,需要根据具体的需求权衡其优势和成本。
通过以上学习过程,我们可以得出以下结论:
-
代理模式 通过引入代理对象来控制对目标对象的访问,代理对象可以在请求前后执行一些附加操作,如延迟加载、权限检查等。
-
代理模式适用于那些需要控制访问、增加额外功能或延迟处理的场景,例如延迟加载、缓存管理、权限控制等。
代理模式的优点:
-
解耦:通过代理对象,客户端与目标对象之间的直接依赖关系被解耦,使得系统更加灵活。
-
附加功能:代理可以在访问目标对象之前或之后增加额外的功能,如延迟加载、缓存、权限检查等。
-
提高性能:通过延迟加载和缓存机制,代理模式可以有效提高系统的性能。
代理模式的缺点:
-
增加复杂性:引入代理对象可能会导致系统复杂度增加,尤其在代理对象的功能较多时。
-
性能开销:代理对象本身会引入一定的性能开销,尤其在处理大量请求时,可能会影响系统性能。
相关文章:
22.代理模式:思考与解读
原文地址:代理模式:思考与解读 更多内容请关注:深入思考与解读设计模式 引言 在软件开发中,尤其是当对象的访问需要控制时,你是否遇到过这样的问题:某些操作或对象可能需要进行额外的检查、优化或延迟加载ÿ…...

Scratch节日 | 粽子收集
端午节怎么过?当然是收粽子啦!这款 粽子收集 小游戏,让你一秒沉浸节日氛围,轻松收集粽子,收获满满快乐! 🎮 玩法介绍f 开始游戏:点击开始按钮,游戏正式开始!…...

stl三角面元文件转颗粒VTK文件
效果展示: import os import sys import json import argparse import numpy as np import pandas as pd import open3d as o3d from glob import globPARTICLE_RADIUS 0.025def stl_to_particles(objpath, radiusNone):if radius is None:radius PARTICLE_RADIU…...

Java String的使用续 -- StringBuilder类和StringBuffer
文章目录 字符串的不可变性StringBuilder和StringBuffer函数使用 字符串的不可变性 字符串不可变是因为有private修饰,只能在类的内部使用不可以在类外使用,因此使用时是不可以修改字符串的 public class test {public static void main(String[] args…...
Android学习之定时任务
Android定时任务的实现方式 在Android开发中,定时任务主要可以通过以下两类方式实现: Android系统组件 Handler消息机制:通过Handler.postDelayed()实现延时任务,适合简单UI线程操作AlarmManager:系统级定时服务&…...
WEB安全--RCE--webshell HIDS bypass4
继WEB安全--RCE--webshell HIDS bypass3的补充: 十三、时间开关 webshell: <?php ini_set("display_errors",1); function foo($test, $bar FSYSTEM) {echo $test . $bar; } $function new ReflectionFunction(foo); $q new ParseEr…...

基于python+Django+Mysql的校园二手交易市场
文章目录 基于pythonDjangoMysql的校园二手交易市场运行步骤系统设计功能设计任务目标用户特点参与者列表基本要求功能模块图 数据库设计会员用户信息表(user_userinfo)商品信息表(goods_goodsinfo)管理员用户信息表(a…...

从零打造算法题刷题助手:Agent搭建保姆级攻略
我用Trae 做了一个有意思的Agent 「大厂机试助手」。 点击 https://s.trae.com.cn/a/d2a596 立即复刻,一起来玩吧! Agent 简介 Agent名称为大厂机试助手,主要功能有以下三点。 解题: 根据用户给出的题目给出具体的解题思路引导做…...
Oracle 12c新增的数字转换验证VALIDATE_CONVERSION函数
Oracle 12c新增的数字转换验证函数 一、VALIDATE_CONVERSION函数(12c R2新增) Oracle 12c Release 2引入了原生验证函数,可直接判断字符串能否转换为指定类型: SELECT VALIDATE_CONVERSION(123.45 AS NUMBER) FROM dual; -- 返…...
参数/非参数检验和连续/离散/分类等变量类型的关系
参数统计方法通常应用于参数变量,但参数变量并不都是连续型变量。参数变量是指那些可以用参数(如均值、方差等)来描述其分布特征的变量。参数变量可以是连续型变量,也可以是离散型变量,只要它们遵循某种特定的分布&…...

懒人云电脑方案:飞牛NAS远程唤醒 + 节点小宝一键唤醒、远程控制Windows!
后台高频问题解答: “博主,飞牛NAS能定时开关机了,能不能让它顺便把家里Windows电脑也远程唤醒控制?最好点一下就能连,不用记IP端口那种!” 安排!今天这套方案完美实现: ✅ 飞牛NAS…...

【Python】第一弹:对 Python 的认知
目录 一、Python 的背景 1.1. Python 的由来 1.2 Python 的作用 1.3 Python 的优缺点 1.4 Python 的开发工具 一、Python 的背景 1.1. Python 的由来 Python 由荷兰数学和计算机科学研究学会的吉多・范罗苏姆 (Guido van Rossum)在 20 世纪 80 年代…...

直播预告 | 聚焦芯必达|打造可靠高效的国产 MCU 与智能 SBC 汽车解决方案
随着汽车电子国产化快速推进,车规级 MCU 与 CAN/LIN SBC 作为车身控制的核心组件,正面临更高的安全与可靠性挑战。品佳集团将携手芯必达微电子,深入剖析国产 MCU/SBC/智能 SBC 的最新技术与应用,助力企业打造高性能、可量产的国产…...

Java源码中有哪些细节可以参考?(持续更新)
欢迎来到啾啾的博客🐱。 记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。 目录 String的比较final的使用transient避免序列化 St…...

GelSight Mini触觉传感器:7μm精度+3D 映射,赋能具身智能精密操作
GelSight Mini 高分辨率视触觉传感器采用先进的光学成像与触觉感知技术,赋予机器人接近人类的触觉能力。该设备可捕捉物体表面微观细节,并生成高精度的2D/3D数字映射,帮助机器人识别形状、纹理及接触力,从而执行更复杂、精准的操作…...

day 23 机器学习管道(pipeline)
在机器学习领域,“pipeline” 常被翻译为 “管道” 或 “流水线”,它是机器学习中极为重要的概念。在构建机器学习模型时,通常需按特定顺序对数据执行预处理、特征提取、模型训练以及模型评估等步骤,而使用 “pipeline” 能有效管…...
shell编程笔记
变量定义 在 Shell 中,变量定义无需声明类型,直接赋值即可。变量名区分大小写,建议使用大写字母命名环境变量,小写字母命名局部变量。赋值时等号()两边不能有空格。 MY_VAR"Hello World" # 定…...

鸿蒙仓颉开发语言实战教程:自定义组件
关于仓颉开发语言我们已经连续分享了很多天,相信大家对于仓颉开发语言已经有了一定的了解。今天我们继续进阶,分享一个仓颉开发语言中的自定义组件知识。 本文案例就以上一篇文章中的自定义tabbar为例,因为我们自己开发的tabbar一直放在inde…...

基于Spring Boot+Vue 网上书城管理系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...

opencvsharp usb摄像头录像 c# H264编码
1.首先创建ConsoleApp,.Net 9.0,不要创建WinForm 。WInForm帧率和实际对不上,有延时。 2.下载opencvsharp。 3.下载openh264-1.8.0-win32.dll , openh264-1.8.0-win64.dll .放在根目录。 https://github.com/cisco/openh264 using OpenCv…...
ch12 课堂参考代码 及 题目参考思路
课堂参考代码 Bellman-Ford 主要思路:对所有的边进行 n-1 轮松弛操作 单源最短路算法, O ( n m ) O(nm) O(nm) using ll long long; const int maxn 5010, maxm 5010; struct Edge {int u, v, w; } E[maxm]; // d[u]: 当前 s 到 u 的最短路 ll d[m…...
uniapp 实现腾讯云 IM 消息已读回执
uniapp 实现腾讯云 IM 消息已读回执处理全攻略 一、功能实现原理 腾讯云 IM 的已读回执功能通过 消息已读上报机制 实现,核心流程如下: 接收方阅读消息时,客户端自动上报已读状态云端记录最新已读时间戳(精确到会话维度&#x…...

JavaScript 性能优化按层次逐步分析
JavaScript 性能优化实战 💡 本文数据基于Chrome 136实测验证,涵盖12项核心优化指标,通过20代码案例演示性能提升300%的实战技巧。 一、代码层深度优化 1. 高效数据操作(百万级数据处理) // 不良实践:频繁…...
三分钟打通Stable Diffusion提示词(附实战手册)
文章目录 一、提示词的本质是"思维翻译器"避坑指南1:三大常见翻车现场 二、结构化提示词公式(抄作业版)实战案例:生成赛博朋克猫咪 三、进阶玩家的秘密武器1. 权重控制大法2. 风格融合黑科技3. 时间轴控制 四、避不开的…...

【Linux网络篇】:初步理解应用层协议以及何为序列化和反序列化
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:Linux篇–CSDN博客 文章目录 一.序列化和反序列化为什么需要序列化和反序列化为什么应用层…...
RK3588 Opencv-ffmpeg-rkmpp-rkrga编译与测试
RK3588 Opencv-ffmpeg-rkmpp-rkrga编译与测试 硬件背景说明编译环境准备1. 编译MPP(媒体处理平台)2. 编译RGA(图形加速库)3. 构建支持硬件加速的FFmpeg重要代码修改说明4. 验证安装5.FFmpeg转码测试OpenCV编译集成Python OpenCV+FFmpeg测试硬件背景说明 RK3588是瑞芯微推出…...

特伦斯 S75 电钢琴:奏响极致音乐体验的华丽乐章
在音乐爱好者增多、音乐教育普及,以及科技进步的推动下,电钢琴市场蓬勃发展。其在技术、品质和应用场景上变化巨大,高端化、个性化产品受青睐,应用场景愈发多元。在此背景下,特伦斯 S75 电钢琴以卓越性能和独特设计&am…...

硬件学习笔记--64 MCU的ARM核架构发展及特点
MCU(微控制器)的ARM核架构是当前嵌入式系统的主流选择,其基于ARM Cortex-M系列处理器内核,具有高性能、低功耗、丰富外设支持等特点。以下是ARM核MCU的主要架构及其发展: 1. ARM Cortex-M系列内核概览 ARM Cortex-M系…...
div或button一些好看实用的 CSS 样式示例
1:现代渐变按钮 .count {width: 800px;background: linear-gradient(135deg, #72EDF2 0%, #5151E5 100%);padding: 12px 24px;border-radius: 10px;box-shadow: 0 4px 15px rgba(81, 81, 229, 0.3);color: white;font-weight: bold;border: none;cursor: pointer;t…...

USB充电检测仪-2.USB充电检测仪硬件设计
本系列文章的最终目标是制作一个USB充电检测仪,支持的功能: 显示USB充电电压、电流、功率、充电量(单位WH);实现Typec口和USB-A口的相互转换(仅支持USB 2.0); 当然网上有很多卖这种…...