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

  • 钉钉如何使用投屏码进行投屏(钉钉如何使用投影仪)

    钉钉如何使用投屏码进行投屏(钉钉如何使用投影仪)

  • word怎么把竖着的字横过来(word怎么把竖着的表格横过来)

    word怎么把竖着的字横过来(word怎么把竖着的表格横过来)

  • 中国移动怎么取消视频彩铃(中国移动怎么取消自动续费流量包)

    中国移动怎么取消视频彩铃(中国移动怎么取消自动续费流量包)

  • 红魔6spro怎么插卡(红魔6pro有几个充电孔)

    红魔6spro怎么插卡(红魔6pro有几个充电孔)

  • 为什么chrome是繁体(为什么谷歌浏览器为繁体)

    为什么chrome是繁体(为什么谷歌浏览器为繁体)

  • 华为nova7pro搭配了几个颜色呢(华为nova7pro配置参数对比nova7)

    华为nova7pro搭配了几个颜色呢(华为nova7pro配置参数对比nova7)

  • 抖音被限流会不会通知(抖音限流会不会影响账号权重呢)

    抖音被限流会不会通知(抖音限流会不会影响账号权重呢)

  • 苹果手机漏音怎么解决(苹果手机漏音怎么回事)

    苹果手机漏音怎么解决(苹果手机漏音怎么回事)

  • 内存卡里丢失的照片怎么找回来(内存卡丢失的视频怎么恢复)

    内存卡里丢失的照片怎么找回来(内存卡丢失的视频怎么恢复)

  • 关闭启动项命令(电脑关闭启动项命令)

    关闭启动项命令(电脑关闭启动项命令)

  • 华为录屏快捷键怎么弄出来(华为录屏快捷键怎么设置)

    华为录屏快捷键怎么弄出来(华为录屏快捷键怎么设置)

  • iphone总是断开热点(苹果手机老是自动断开热点)

    iphone总是断开热点(苹果手机老是自动断开热点)

  • 内部版本7601有影响吗(内部版本7601不是正版)

    内部版本7601有影响吗(内部版本7601不是正版)

  • 华为手机双卡为什么突然一个卡不能用了(华为手机双卡为什么一个4G一个2G)

    华为手机双卡为什么突然一个卡不能用了(华为手机双卡为什么一个4G一个2G)

  • 微信声音怎么设置(微信声音怎么设置大小)

    微信声音怎么设置(微信声音怎么设置大小)

  • ps画笔间距怎么调(ps2019画笔间距怎么调)

    ps画笔间距怎么调(ps2019画笔间距怎么调)

  • 如何将手机照片内存变小(如何将手机照片转换成jpg格式)

    如何将手机照片内存变小(如何将手机照片转换成jpg格式)

  • 荣耀9x自带膜可以撕吗(荣耀9x新机带的膜能揭掉吗)

    荣耀9x自带膜可以撕吗(荣耀9x新机带的膜能揭掉吗)

  • 数字振动为什么伤眼(数字振动没有)

    数字振动为什么伤眼(数字振动没有)

  • 小天才z5有充电头吗(小天才z5充电器图片)

    小天才z5有充电头吗(小天才z5充电器图片)

  • 向日葵付费和免费区别(向日葵收费版的会流畅点吗)

    向日葵付费和免费区别(向日葵收费版的会流畅点吗)

  • 如何在Excel中使用组合框控件(在excel中如何用)

    如何在Excel中使用组合框控件(在excel中如何用)

  • 苹果键盘回车键在哪里(苹果键盘回车键怎么调出来)

    苹果键盘回车键在哪里(苹果键盘回车键怎么调出来)

  • 金税四期影响企业贷款吗
  • 做账要不要入库单和出库单
  • 销售退货时发票已认证怎么办
  • 机动车换车
  • 运输费用和保险费用会计分录
  • 通用原始凭证有哪些?
  • 固定资产盘盈盘亏的会计科目
  • 非营利组织对外捐赠
  • 如何计算企业当年利润
  • 个人劳务报酬所得汇算清缴
  • 有收入零申报要紧吗
  • 企业向学校捐赠 流程
  • 经营终止前企业资质变更
  • 扣缴上月税费会计分录
  • 审图费发票需要备注吗
  • win10怎么打开任务管理器
  • 个体工商户未给员工缴纳社保
  • 如何做预估成本
  • 增值税附税的计算公式
  • Windows11更新后无法联网
  • mac侧边栏设置
  • mac触控板使用技巧
  • dxva2.dll是什么意思
  • print-js
  • 竣工工程成本核算
  • wordpress建网站详细教程
  • wordpress site
  • 税收变动作用
  • php实现分页显示
  • 未开票收入申报对企业有什么影响
  • 分页显示怎么实现
  • 用命令ls-al显示出文件ff
  • Laravel5权限管理方法详解
  • 车辆处置收入入什么科目
  • logread命令
  • shell和pycharm
  • 公司在银行买的理财产品怎么做账
  • 支付国外佣金税怎么算
  • 出口退税转内销的话如何算发票金额
  • 残保金计税基数是什么
  • 余热发电前景
  • 以物易物对企业有什么好处
  • 增值税专用发票有几联?
  • 开票软件怎么增加开票员
  • mysqlbinlog命令详解
  • 小规模差额征税的税率是3%还是5%
  • 以前年度的成本忘了结转然后怎么办
  • 运输公司燃油费占比
  • 劳务公司是怎么运作的
  • ERROR CODE: 1175 YOU ARE USING SAFE UPDATE MODE AN
  • 超市购物小票可以入账吗
  • 未分配利润是怎么来的
  • 怎么判断其他债权债务
  • 应交税金在贷方是什么意思
  • 前几个月的印花税怎么算
  • 代扣代缴的增值税算进项税吗
  • 库存商品差额调整会计目录
  • 转出未交增值税借方余额怎么处理
  • sql语句基础题及答案
  • sqlserver2012序列号
  • 尽量别熬夜
  • solaris删除文件命令
  • 苹果mac os x 10.7.5如何升级
  • armcc.exe
  • babylon.exe进程有什么作用 babylon进程是什么文件
  • win7开机错误代码
  • js函数预解析
  • jqueryvalidate验证
  • nodejs利用http模块实现银行卡所属银行查询和骚扰电话验证示例
  • bs cs架构
  • 安卓网络编程面试题
  • 批处理计数
  • 关于jquery的描述错误的是
  • android百分比布局
  • python 递归函数与循环的区别
  • jq easyui
  • js对象值如何表示
  • 北京社保外埠城镇职工和外埠农村劳动力啥区别
  • 如何电子税务局缴纳社保费用
  • 中国税务网发票怎么开
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设