位置: IT常识 - 正文

设计模式---代理模式(设计模式代理模式)

编辑:rootadmin
简述 对客户端隐藏目标类,创建代理类拓展目标类,并且对于客户端隐藏功能拓展的细节,使得客户端可以像使用目标类一样使用代理类,面向代理(客户端只与代理类交互)。 话不多说,看一个优化案例。 优化案例 最初版v0 目前的功能是下载可以下载文件。 public class BiliBiliDownload ... 简述

推荐整理分享设计模式---代理模式(设计模式代理模式),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:设计代理完整版,设计模式代理模式的典型例子,设计模式代理模式的典型例子,设计模式代理模式的典型例子,设计模式代理模式的典型例子,设计模式代理模式 迭代器,设计模式代理模式,设计模式代理模式,内容如对您有帮助,希望把文章链接给更多的朋友!

对客户端隐藏目标类,创建代理类拓展目标类,并且对于客户端隐藏功能拓展的细节,使得客户端可以像使用目标类一样使用代理类,面向代理(客户端只与代理类交互)。

话不多说,看一个优化案例。

优化案例最初版v0

目前的功能是下载可以下载文件。

public class BiliBiliDownloader { public byte[] download(String filePath) throws InterruptedException { System.out.printf("正在下载BiliBili文件:%s%n", filePath); // 模拟文件下载,睡个10秒 Thread.sleep(10000); return new byte[1024]; // 假装是下载文件的字节数组 }}

客户端调用代码,如下。

public class Client { public static void main(String[] args) throws InterruptedException { BiliBiliDownloader bilidownloader = new BiliBiliDownloader(); bilidownloader.download("/root/buzuweiqi/java_manual.txt"); }}

下载工具类对客户端完全暴露,客户端可以直接使用下载类实现下载,这实际上是无可厚非的。经过研究发现,这个下载类有一个问题:每次调用都肯定会下载新的文件,即便文件已经被下载过。

为了解决这个问题,开发团队经过商讨已经有了一个初步的方案。看一下代码样例。

修改版v1

团队决定使用传统的修改方式(直接修改BiliBiliDownloader),认为这样最为的直观。确实,代码量少且未来可以预期修改不频繁时,传统的修改方案也未尝不是一个好的选择。

public class BiliBiliDownloader { // 定义用来缓存数据的map对象 private static Map<String, byte[]> map = new HashMap<>(); public byte[] download(String filePath) throws InterruptedException { System.out.printf("正在下载BiliBili文件:%s%n", filePath); if (map.containsKey(filePath)) { return map.get(filePath); } // 模拟文件下载,睡个10秒 Thread.sleep(10000); byte[] res = new byte[1024]; // 假装这是下载后的字节数组 map.put(filePath, res); // 加入缓存 return res; }}

客户端调用代码,还是和原来一样。

public class Client { public static void main(String[] args) throws IOException, InterruptedException { BiliBiliDownloader downloader = new BiliBiliDownloader(); downloader.download("/root/home/buzuweiqi/java_manual.txt"); // 由于文件已经缓存,所以这次下载非常快 downloader.download("/root/home/buzuweiqi/java_manual.txt"); // 由于文件还未缓存,所以这次下载比较缓慢 downloader.download("/root/home/buzuweiqi/linux_manual.txt"); }}设计模式---代理模式(设计模式代理模式)

到目前为止好像都没有啥不妥的地方。直到有一天,客户提出了新的需求:虽然现在只可以下载bilibili的文件(视频,音频,文章等),以后还想要下载youtube的文件。

为了实现这个需求,以及方便以后同类的需求变更,是时候用上代理模式。

修改版v2

代理模式在使用的时候需要顶一个一个顶层接口,并且使得代理类和被代理类都实现这个接口。代理类中需要持有非代理类的一个对象。并且在调用代理类的功能前后可以根据业务需要拓展新的功能。

public interface Downloader { byte[] download(String filePath) throws InterruptedException;}public class BiliBiliDownloader implements Downloader { public byte[] download(String filePath) throws InterruptedException { System.out.printf("正在下载BiliBili文件:%s%n", filePath); // 模拟文件下载,睡个10秒 Thread.sleep(10000); return new byte[1024]; // 假装是下载文件的字节数组 }}public class ProxyBiliBiliDownloader implements Downloader { private static Map<String, byte[]> map = new HashMap<>(); private BiliBiliDownloader downloader = new BiliBiliDownloader(); public byte[] download(String filePath) throws InterruptedException { if (map.containsKey(filePath)) { System.out.printf("正在下载BiliBili文件:%s%n", filePath); return map.get(filePath); } byte[] res = downloader.download(filePath); map.put(filePath, res); return res; }}public class YoutubeDownloader implements Downloader { public byte[] download(String filePath) throws InterruptedException { System.out.printf("正在下载Youtube文件:%s%n", filePath); // 模拟文件下载,睡个10秒 Thread.sleep(10000); return new byte[1024]; // 假装是下载文件的字节数组 }}public class ProxyYoutubeDownloader implements Downloader { private static Map<String, byte[]> map = new HashMap<>(); private BiliBiliDownloader downloader = new BiliBiliDownloader(); public byte[] download(String filePath) throws InterruptedException { if (map.containsKey(filePath)) { System.out.printf("正在下载Youtube文件:%s%n", filePath); return map.get(filePath); } byte[] res = downloader.download(filePath); map.put(filePath, res); return res; }}

客户端的使用案例如下。

public class Client { public static void main(String[] args) throws IOException, InterruptedException { Downloader downloader = new ProxyBiliBiliDownloader(); downloader.download("/root/home/buzuweiqi/java_manual.txt"); downloader = new ProxyYoutubeDownloader(); downloader.download("/root/home/buzuweiqi/linux_manual.txt"); }}

客户端不再依赖目标类,而是转而依赖代理类。代理模式使得增加相似需求时可以只增加一对实现类(目标类,代理类),而不用修改原本的类,符合开闭原则。

实际上通常我们会使用一个更为简单的方式控制代理对象的创建:反射。

修改版v3

高层接口,实现的目标类、代理类依旧不变。

public interface Downloader { byte[] download(String filePath) throws InterruptedException;}public class BiliBiliDownloader implements Downloader { public byte[] download(String filePath) throws InterruptedException { System.out.printf("正在下载BiliBili文件:%s%n", filePath); // 模拟文件下载,睡个10秒 Thread.sleep(10000); return new byte[1024]; // 假装是下载文件的字节数组 }}public class ProxyBiliBiliDownloader implements Downloader { private static Map<String, byte[]> map = new HashMap<>(); private BiliBiliDownloader downloader = new BiliBiliDownloader(); public byte[] download(String filePath) throws InterruptedException { if (map.containsKey(filePath)) { System.out.printf("正在下载BiliBili文件:%s%n", filePath); return map.get(filePath); } byte[] res = downloader.download(filePath); map.put(filePath, res); return res; }}public class YoutubeDownloader implements Downloader { public byte[] download(String filePath) throws InterruptedException { System.out.printf("正在下载Youtube文件:%s%n", filePath); // 模拟文件下载,睡个10秒 Thread.sleep(10000); return new byte[1024]; // 假装是下载文件的字节数组 }}public class ProxyYoutubeDownloader implements Downloader { private static Map<String, byte[]> map = new HashMap<>(); private BiliBiliDownloader downloader = new BiliBiliDownloader(); public byte[] download(String filePath) throws InterruptedException { if (map.containsKey(filePath)) { System.out.printf("正在下载Youtube文件:%s%n", filePath); return map.get(filePath); } byte[] res = downloader.download(filePath); map.put(filePath, res); return res; }}

在客户端调用时,引入Java反射,通过反射创建具体的代理对象。在config.prop文件中定义PROXY_NAME变量并指定需要反射创建的类的完整路径。

public class Client { public static void main(String[] args) throws Exception { Properties prop = new Properties(); prop.load(new FileReader("src/resource/props/config.prop")); Downloader downloader = (Downloader) Class.forName(prop.getProperty("PROXY_NAME")) .getDeclaredConstructor().newInstance(); downloader.download("/root/home/buzuweiqi/java_manual.txt"); downloader = new ProxyYoutubeDownloader(); downloader.download("/root/home/buzuweiqi/linux_manual.txt"); }}

通过Java反射机制,应对每次的需求变更,甚至都不需要修改客户端代码,只需要修改案例中的config.prop即可。减少了不必要的代码修改,提高了系统的可维护性。

总结优点

代理类与目标类的使用方式一致,这极大的降低了客户端调用的学习成本,易用性高。

面向接口,无需在意实现的细节。

缺点类的数量倍增,系统复杂度增加。适用场景当需要对于模块拓展,但又不方便打破客户端原有的调用规则时。客户端中对象的创建依旧需要修改,这没有什么好的办法。常用的代理模式使用方案缓冲代理(案例)远程代理虚拟代理

除此之外还有很多应用场景,代理模式是设计模式中使用非常广泛的一种。

本文链接地址:https://www.jiuchutong.com/zhishi/311549.html 转载请保留说明!

上一篇:自定义映射resultMap(映射器可以定义参数类型)

下一篇:织梦DedeCMS访京东多条件筛选教程(织梦系统)

  • iqoo8应用分身怎么设置(iqooz1应用分身)

    iqoo8应用分身怎么设置(iqooz1应用分身)

  • 公众号一天可以发几篇(公众号一天可以转载几篇文章)

    公众号一天可以发几篇(公众号一天可以转载几篇文章)

  • 抖音怎么把app里的视频保存在手机里(怎么把抖音app放到手机桌面)

    抖音怎么把app里的视频保存在手机里(怎么把抖音app放到手机桌面)

  • 快手通过动态添加关注是从哪关注的(快手动态添加好友什么意思)

    快手通过动态添加关注是从哪关注的(快手动态添加好友什么意思)

  • vivo手机实名认证怎么更改(vivo手机实名认证怎么修改)

    vivo手机实名认证怎么更改(vivo手机实名认证怎么修改)

  • 拼多多app怎么打开(拼多多APP怎么打大)

    拼多多app怎么打开(拼多多APP怎么打大)

  • 录抖音如何声音更大(录抖音声音为什么会延迟)

    录抖音如何声音更大(录抖音声音为什么会延迟)

  • 微信视频左右脸是反的(微信视频左右脸是反的怎么解决)

    微信视频左右脸是反的(微信视频左右脸是反的怎么解决)

  • 快手是腾讯的吗(快手是腾讯的吗大王卡免流吗)

    快手是腾讯的吗(快手是腾讯的吗大王卡免流吗)

  • 拨打号码已过期是什么意思(拨打电话已过期)

    拨打号码已过期是什么意思(拨打电话已过期)

  • 关联了看不到聊天记录(关联看不到聊天记录怎么回事)

    关联了看不到聊天记录(关联看不到聊天记录怎么回事)

  • 微信仅聊天对方知道吗(微信仅聊天对方还能看到我的评论吗)

    微信仅聊天对方知道吗(微信仅聊天对方还能看到我的评论吗)

  • 怎么给别人充爱奇艺vip(怎么给别人充爱奇艺会员连续包月)

    怎么给别人充爱奇艺vip(怎么给别人充爱奇艺会员连续包月)

  • 为什么抖音打开看不了(为什么抖音打开是黑屏)

    为什么抖音打开看不了(为什么抖音打开是黑屏)

  • page up是什么键(page up是哪个键笔记本)

    page up是什么键(page up是哪个键笔记本)

  • word文档文字竖排居中(word文档文字竖排怎么变横排)

    word文档文字竖排居中(word文档文字竖排怎么变横排)

  • 华为哪个手机是type-c(华为哪个手机是麒麟990)

    华为哪个手机是type-c(华为哪个手机是麒麟990)

  • 爱奇艺怎么关注好友(爱奇艺怎么关注会员)

    爱奇艺怎么关注好友(爱奇艺怎么关注会员)

  • 荣耀20有nfc和红外吗(荣耀20有nfc功能在哪里)

    荣耀20有nfc和红外吗(荣耀20有nfc功能在哪里)

  • 2016.9.20英文日期写法(2016.9.20英文日期写法缩写)

    2016.9.20英文日期写法(2016.9.20英文日期写法缩写)

  • reno2前置摄像头多少(opporeno2前置摄像头)

    reno2前置摄像头多少(opporeno2前置摄像头)

  • 华为正在安装的软件怎么删除不了(华为正在安装的软件怎么删除掉)

    华为正在安装的软件怎么删除不了(华为正在安装的软件怎么删除掉)

  • 举报快手去哪里投诉(快手举报在哪里举报)

    举报快手去哪里投诉(快手举报在哪里举报)

  • 苹果回车键在哪里设置(苹果回车键在哪儿)

    苹果回车键在哪里设置(苹果回车键在哪儿)

  • Mac版ios8.1.2怎么越狱?Mac版iOS8.0-iOS8.1.2完美越狱图文教程(苹果mac系统怎么更新最新版本)

    Mac版ios8.1.2怎么越狱?Mac版iOS8.0-iOS8.1.2完美越狱图文教程(苹果mac系统怎么更新最新版本)

  • 如何用 chatGPT,给大家来一个自我介绍(在国内如何用ChatGPT)

    如何用 chatGPT,给大家来一个自我介绍(在国内如何用ChatGPT)

  • 应交增值税是什么意思
  • 小规模企业所得税计算
  • 去年少交增值税的会计处理
  • 土地价值计入房产税文件
  • 投资过程中的相关税费
  • 当月未抵扣的进项税
  • 劳务费增值税专用发票税率是多少
  • 物业公司一般纳税人增值税税率
  • 什么是资产负债率
  • 季度现金流量表是三个月相加吗
  • 中介公司报税怎么操作
  • 土地增值税计税依据
  • 合同解除收取对方的违约金交什么税
  • 对公账户进账是否缴税
  • 注资的设备出售怎么处理
  • 职工培训费进项能抵扣吗
  • 电力公司安装变压器要多少钱
  • 个体户缴纳个人经营所得税分录
  • 不得抵扣的进项税额怎么处理
  • 消费税为什么不计入长投成本
  • 收到押金入什么会计科目
  • 补交上一年度的所得税怎么做账
  • 没有系统U盘,电脑密码忘记了如何打开电脑
  • 发出商品与库存商品的区别
  • php获取指定日期的时间戳
  • 隐藏登录界面的软件
  • vcpkgsrv.exe是什么进程
  • 退休返聘人员报销差旅费
  • 工业企业的费用
  • php二维数组查询指定值
  • 福利费入账要求
  • 付检测费会计分录
  • des算法加密解密过程
  • vue入门
  • 工业企业总产值怎么算
  • 企业销售旧车如何开票
  • 资信证明好开吗
  • 食堂费用没有发票
  • 存货跌价准备的特点
  • 财政补助收入的账务处理
  • 失业保险金退回短信
  • 一般纳税人普通发票要交增值税吗
  • 收回理财款会计分录
  • 公司委托银行付款的账务处理
  • 坏账确认方法有哪些?
  • 手续费和利息费用的区别
  • 鉴证咨询公司
  • 小规模纳税人公户转私户可以吗
  • 根据企业
  • 劳务派遣可以享受产假吗
  • 自制半成品核算方法
  • SQL2005、SQL2008允许远程连接的配置说明(附配置图)
  • mysql多字段数据
  • winxp系统纯净版
  • 戴尔电脑u盘快速启动
  • win7设置在哪里设置
  • win10系统jdk环境变量
  • mac怎么管理字体大小
  • win7某个软件打不开
  • 个性化定制方案怎么写
  • 系统播放音乐
  • -f linux命令
  • Linux下OpenVPN配置静态密钥(static-key)验证教程
  • windows 10运行
  • 分区表 英语
  • linux中shell脚本实验总结
  • python文本处理教程
  • 批处理重命名文件名
  • bat实现的模仿黑客帝国里面的数码雨
  • python语言解析
  • window.parent与window.openner区别介绍
  • jquery easyui插件
  • javascript操作网页
  • js如何动态添加class
  • 志愿者开展活动后存在的问题
  • 技术进出口指什么技术
  • 小规模纳税人可以用专票抵扣税吗
  • 2022年各大省份录取分数线
  • 经纪代理服务税率1%
  • 企业分立需要开发票吗?
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设