位置: 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访京东多条件筛选教程(织梦系统)

  • 网络推广之利用论坛推广的4个切入点(如何利用网络推广)

    网络推广之利用论坛推广的4个切入点(如何利用网络推广)

  • 苹果手机怎么换自定义壁纸(苹果手机怎么换机到新苹果手机)

    苹果手机怎么换自定义壁纸(苹果手机怎么换机到新苹果手机)

  • 小红书可以直播吗(小红书可以直播电影吗)

    小红书可以直播吗(小红书可以直播电影吗)

  • 华为mate30pro录音在哪找(华为mate30pro录音机删除了怎么找到)

    华为mate30pro录音在哪找(华为mate30pro录音机删除了怎么找到)

  • 苹果手机支持北斗卫星导航系统吗(苹果手机开不了机)

    苹果手机支持北斗卫星导航系统吗(苹果手机开不了机)

  • 群聊删了怎么找到群组(群聊删掉了怎么找)

    群聊删了怎么找到群组(群聊删掉了怎么找)

  • 天猫精灵方糖连不上网(天猫精灵方糖连接扫地机器人)

    天猫精灵方糖连不上网(天猫精灵方糖连接扫地机器人)

  • 芒果tvpc端是什么意思(芒果tv pc端)

    芒果tvpc端是什么意思(芒果tv pc端)

  • 苹果短信怎么切换蓝色(苹果短信怎么切换副号)

    苹果短信怎么切换蓝色(苹果短信怎么切换副号)

  • 为什么耳机声音很小(为什么耳机声音自动调小)

    为什么耳机声音很小(为什么耳机声音自动调小)

  • 苹果六与苹果七有什么不同(苹果六与苹果七哪个好)

    苹果六与苹果七有什么不同(苹果六与苹果七哪个好)

  • 手机电话响了屏幕不亮(电话响了屏幕上什么都没有)

    手机电话响了屏幕不亮(电话响了屏幕上什么都没有)

  • 无法加载操作系统(无法加载操作系统,因为系统注册表损坏)

    无法加载操作系统(无法加载操作系统,因为系统注册表损坏)

  • 微型计算机的基本功能(微型计算机的基本输入设备有)

    微型计算机的基本功能(微型计算机的基本输入设备有)

  • 亚马逊自营是啥意思(亚马逊自营和非自营)

    亚马逊自营是啥意思(亚马逊自营和非自营)

  • 怪兽充电宝可以带上飞机吗(怪兽充电宝可以换地方归还吗)

    怪兽充电宝可以带上飞机吗(怪兽充电宝可以换地方归还吗)

  • ps怎么降低图片大小(ps怎么降低图片内存大小)

    ps怎么降低图片大小(ps怎么降低图片内存大小)

  • 手机文件如何传到电视(手机文件如何传入存储卡)

    手机文件如何传到电视(手机文件如何传入存储卡)

  • 苹果云盘怎么清除(苹果云盘怎么清理垃圾)

    苹果云盘怎么清除(苹果云盘怎么清理垃圾)

  • 高通sm6125是什么处理器

    高通sm6125是什么处理器

  • 小米2s是不是4g手机(小米2s支不支持4g)

    小米2s是不是4g手机(小米2s支不支持4g)

  • 无需物流发货什么意思(无需物流发货会有什么处罚)

    无需物流发货什么意思(无需物流发货会有什么处罚)

  • 荣耀手环3可以接电话吗(荣耀手环3可以刷门禁卡吗)

    荣耀手环3可以接电话吗(荣耀手环3可以刷门禁卡吗)

  • iphone8p重量多少克(苹果8p重多少千克)

    iphone8p重量多少克(苹果8p重多少千克)

  • 做PR做了八年,应该放弃PR转MKT吗?(pr可以做后期吗)

    做PR做了八年,应该放弃PR转MKT吗?(pr可以做后期吗)

  • 怎么移除微信群成员(怎么移除微信群聊)

    怎么移除微信群成员(怎么移除微信群聊)

  • iphonexr支持nfc吗(iponexr支持nfc吗?)

    iphonexr支持nfc吗(iponexr支持nfc吗?)

  • 增值税一般纳税人税率
  • 简易计税方法是什么意思
  • 外资企业内资企业
  • 转出未交增值税最终怎么转平
  • 车船使用税2021
  • 年底对账
  • 未担保余值列报
  • 个税手续费返还计入哪个科目
  • 非盈利组织的银行是什么
  • 行政单位待处理财产损益要结转吗
  • 跨境电商零售正面清单
  • 电影剧本稿费代扣代缴个人所得税如何处理?
  • 抵押贷款买房子合适还是商业贷款合适
  • 冲减留抵税会计分录
  • 买东西几块钱忘付了怎么办
  • 甲供材的范围
  • 担保公司做担保怎么收费
  • 什么是股息红利扣税
  • 如何从百旺开票系统中导出开票明细
  • 7月认证的发票7月可以抵扣吗?
  • 接手新公司涉税问题分析
  • 独资企业需要交企业所得税吗
  • 长期待摊费用原值怎么填
  • 办理税务迁移
  • 华为最新款手机2023款
  • 如何停止win11
  • 已经抵扣增值税专用发票对方要换票怎么办
  • 外账的结转成本是什么
  • win11如何设置开机自启动软件
  • 咨询服务费需要什么附件
  • 佣金代扣代缴增值税还有附加税吗
  • 备用金冲销的会计分录
  • 开机自动连接宽带怎么设置w11
  • 买股指期货有什么条件
  • 增值税专用发票几个点
  • 资本化的后续支出包括哪些项目
  • 辅助生产成本的分配
  • 农村个体户需要报税吗
  • php中strstr
  • 增值税缓息是什么意思
  • 防伪税控服务费怎么交
  • 企业季度所得税怎么算
  • transformer模型包含哪些结构
  • 前端搭建小人逃脱游戏(内附源码)
  • ChatGPT在热门行业的应用场景有哪些
  • 微信浏览器支持webassembly
  • php remote_addr
  • 计提工会经费的标准
  • 印花税申报成功后在哪缴税
  • 个体双定户税率
  • 建筑业的账务处理方法
  • 公司承担员工的社保费会计分录
  • 利息应怎么录入收入
  • 土地增值税预缴计税依据
  • 应交税费会计分录完整版
  • 主营业务收入多计提怎么冲减
  • 个人独资企业费用扣除
  • 劳务分包预缴税款计算公式
  • 小规模纳税人转一般纳税人当月如何申报
  • 机票退票手续费可以开发票吗
  • 季度的工会经费怎么算
  • 怎么用公式计算结果填充单元格
  • sql server 数学函数
  • win10系统崩溃后可以通过什么来恢复
  • 苹果电脑安装了双系统怎么恢复苹果系统
  • Linux系统配置要求
  • pop3是什么意思中文
  • 红石怎么启动
  • win10更新提示错误
  • window10光驱不能用了
  • 微信小程序实现微信支付
  • opengl 有哪些特点?与directx相比它有什么不同?
  • unity rpg插件
  • android应用程序的主要语言是
  • 文件读写过程中,程序将直接与磁盘文件进行数据交换
  • ImageView的android:maxHeight,android:minHeight的正确设置
  • 计征土地增值税时需要以评估价格来确定
  • 成都税务二维码扫描
  • 天津定额发票查询真伪查询
  • 代理记账协会成立时间
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设