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

  • 最详细的18种微信推广方法(最详细的18种微信头像)

    最详细的18种微信推广方法(最详细的18种微信头像)

  • vivox70像素是多少(vivoy70t像素)

    vivox70像素是多少(vivoy70t像素)

  • 在excel中一个完整的函数包括(excel中一个完整的函数包括什么?)

    在excel中一个完整的函数包括(excel中一个完整的函数包括什么?)

  • 最后一页空白页怎么删除(最后一页空白页怎么删除不了)

    最后一页空白页怎么删除(最后一页空白页怎么删除不了)

  • 手机设置路由器后上不了网(手机设置路由器教程)

    手机设置路由器后上不了网(手机设置路由器教程)

  • 华为哪款手机主打拍照(华为哪款手机主打自拍)

    华为哪款手机主打拍照(华为哪款手机主打自拍)

  • xr声音小怎么设置(xr声音小怎么设置好听)

    xr声音小怎么设置(xr声音小怎么设置好听)

  • 数据库与文件系统主要区别(数据库文件系统阶段特点)

    数据库与文件系统主要区别(数据库文件系统阶段特点)

  • 爱奇艺会员别人怎么登录(爱奇艺会员别人登录怎么取消)

    爱奇艺会员别人怎么登录(爱奇艺会员别人登录怎么取消)

  • 对方限制登录能看朋友圈吗(对方限制登陆)

    对方限制登录能看朋友圈吗(对方限制登陆)

  • 5v2a可以充蓝牙耳机吗(5v2a充5v1a的蓝牙耳机会爆炸吗)

    5v2a可以充蓝牙耳机吗(5v2a充5v1a的蓝牙耳机会爆炸吗)

  • 手机防盗器可以托运吗(防盗功能手机)

    手机防盗器可以托运吗(防盗功能手机)

  • 微信群拉人不需要验证(微信群拉人不需要群主同意)

    微信群拉人不需要验证(微信群拉人不需要群主同意)

  • 手机怎么连接音响放音乐(手机怎么连接音响视频教程)

    手机怎么连接音响放音乐(手机怎么连接音响视频教程)

  • 索尼xperia1怎么设置铃声

    索尼xperia1怎么设置铃声

  • 微信零钱怎么设置看不到(微信零钱怎么设置手势密码)

    微信零钱怎么设置看不到(微信零钱怎么设置手势密码)

  • 抖音双向关注什么意思(抖音双向关注是什么)

    抖音双向关注什么意思(抖音双向关注是什么)

  • vivox27闪充在哪儿关(vivox27闪充在哪里关闭)

    vivox27闪充在哪儿关(vivox27闪充在哪里关闭)

  • 苹果怎么设置双击亮屏(苹果怎么设置双重曝光指令)

    苹果怎么设置双击亮屏(苹果怎么设置双重曝光指令)

  • 直播都需要什么设备(直播都需要什么装备)

    直播都需要什么设备(直播都需要什么装备)

  • hpwuschd.exe是什么软件的进程 起到哪些什么作用 hpwuschd进程安全吗(hp workwise service是什么)

    hpwuschd.exe是什么软件的进程 起到哪些什么作用 hpwuschd进程安全吗(hp workwise service是什么)

  • 网络延迟高解决方法(网络延迟高不稳定怎么办)

    网络延迟高解决方法(网络延迟高不稳定怎么办)

  • 米苏尔岛,拉贾安帕特群岛中的岛屿,印度尼西亚 (© rusm/Getty Images)(米苏拉塔是哪个国家)

    米苏尔岛,拉贾安帕特群岛中的岛屿,印度尼西亚 (© rusm/Getty Images)(米苏拉塔是哪个国家)

  • phpcms是收费的么(phpcms 用的是什么模板引擎)

    phpcms是收费的么(phpcms 用的是什么模板引擎)

  • 企业工程款发票税率是多少2021
  • 外地预缴的增值税要在本地计算附加税吗?
  • 岗位津贴和岗位补贴
  • 个税身份验证不通过
  • t3用友软件怎么设置三级科目
  • 年前买东西
  • 制造企业售后服务方案
  • 个人账户转公司账户需要交税吗
  • 从国外购进样品要交税吗
  • 汇兑损益在外币业务核算中有什么重要意义
  • 项目结余是什么意思
  • 企业零申报教学视频
  • 房产税每次申报都要维护吗
  • 农林牧渔业税务优惠
  • 全年一次性奖金税收优惠政策
  • 税务三方协议一式几份
  • 孵化器虚拟地址多少钱一个啊
  • 企业收到待清算的现金
  • 没给顾客发票需要罚款吗
  • 新建厂房购入材料会计分录
  • 成本费用总额包括信用减值损失吗
  • 工资薪金总额包括哪些内容
  • 应交税费应交增值税明细科目设置
  • 小规模纳税人出售使用过固定资产
  • 免税的普通发票怎么开
  • 购进货物无偿赠送其他单位
  • WIN7系统的镜像文件在哪里
  • 事业单位租赁收入的处理
  • 员工没有工资卡可以转到一个人的账户上发工资不
  • win10开发工具在哪
  • php substring
  • elementui常用组件
  • 一般纳税人出售旧设备的税率
  • 提取公益金会计科目
  • 委托代建的法律规定
  • php preg_quote
  • smarty怎么用
  • 进项税额准予抵扣的有哪些
  • php lcg_value与mt_rand生成0~1随机小数的效果对比分析
  • 税务稽查的进项税怎么处理
  • 顺流交易的会计处理
  • pytorch如何训练模型
  • php导出大量数据
  • 个人开发app最简单方法
  • php统计中文长度
  • 小企业其他应收款坏账处理
  • 企业内部培训费用
  • mongodb如何查询数据
  • 公司的融资租赁怎么做账
  • 人工成本的分类是
  • 资产负债表怎么看盈利或亏损
  • php怎么连接sqlserver
  • 企业银行基本户和一般户的区别
  • 盈余公积的会计科目
  • 医院如何开票
  • 在建工程领用原材料税费怎么处理
  • 管理费用漏记了跨年调整
  • 高新技术企业亏损弥补的年限为十年
  • 商贸企业增值税税率是多少
  • 小规模纳税人免税政策2023年
  • 报销人跟领款人有什么区别
  • 发票冲销后还能用吗
  • 免征增值税还要计提附加税吗
  • 资本公积可用于弥补企业亏损
  • 增值税收入的确认时间
  • centos6.10配置网络
  • macos high sierra深色模式
  • linux中添加用户和组的操作
  • win7旗舰版磁盘清理
  • win10画图功能
  • cocos html
  • node.js入门
  • linux防火墙开启80端口视频
  • jq读取json
  • 批处理执行bat文件
  • javascript开发app教程
  • 党建引领安全宣传美篇幼儿园
  • 低保户系统能查出来吗
  • 税收优惠政策有经营和居民住宅出租
  • 杭州电子税务局怎么添加办税员
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设