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

  • 华为p30pro听筒声音小(华为p30pro听筒声音小要换屏幕吗)

    华为p30pro听筒声音小(华为p30pro听筒声音小要换屏幕吗)

  • 抖音里的作品怎么删除(抖音里的作品怎么置顶)

    抖音里的作品怎么删除(抖音里的作品怎么置顶)

  • 淘宝评价一下全没了(淘宝评价全部给差评对自己有影响吗)

    淘宝评价一下全没了(淘宝评价全部给差评对自己有影响吗)

  • iphonex外屏碎了有必要换吗(iphonex外屏碎了换多少钱)

    iphonex外屏碎了有必要换吗(iphonex外屏碎了换多少钱)

  • 打电话显示对方已振铃是什么意思(打电话显示对方已振铃但是没有声音)

    打电话显示对方已振铃是什么意思(打电话显示对方已振铃但是没有声音)

  • iphonex三维触控没反应(iphone xs 三维触控开与不开区别)

    iphonex三维触控没反应(iphone xs 三维触控开与不开区别)

  • 微信下载不了是怎么回事(微信下载不了是怎么回事安卓)

    微信下载不了是怎么回事(微信下载不了是怎么回事安卓)

  • 目前,因特网上最主要的服务方式是(目前因特网上普遍采用的传输协议是)

    目前,因特网上最主要的服务方式是(目前因特网上普遍采用的传输协议是)

  • 苹果x宽多少厘米(iphonex宽多少厘米)

    苹果x宽多少厘米(iphonex宽多少厘米)

  • 半导体封测是什么(半导体封测概念)

    半导体封测是什么(半导体封测概念)

  • 抖音消息怎么一键清空(抖音消息怎么一键已读)

    抖音消息怎么一键清空(抖音消息怎么一键已读)

  • word进行打印预览时,只能一页一页地观看(word打印预设)

    word进行打印预览时,只能一页一页地观看(word打印预设)

  • 华为怎么开启电脑模式(华为怎么开启电话视频功能)

    华为怎么开启电脑模式(华为怎么开启电话视频功能)

  • 电脑开机一直错误恢复(电脑开机一直错误怎么办)

    电脑开机一直错误恢复(电脑开机一直错误怎么办)

  • 电脑能装几个固态硬盘(电脑装几个固态)

    电脑能装几个固态硬盘(电脑装几个固态)

  • word导航目录设置(word导航目录设置 插件)

    word导航目录设置(word导航目录设置 插件)

  • mate30有没有呼吸灯(华为mate30没有呼吸灯吗?)

    mate30有没有呼吸灯(华为mate30没有呼吸灯吗?)

  • realmex2pro怎么更换锁屏壁纸(realmex2怎么升级realme ui2.0)

    realmex2pro怎么更换锁屏壁纸(realmex2怎么升级realme ui2.0)

  • 荣耀20i怎么看后台(荣耀20怎么打开后盖)

    荣耀20i怎么看后台(荣耀20怎么打开后盖)

  • 如何删除注销抖音账号(如何注销抖音号删除作品)

    如何删除注销抖音账号(如何注销抖音号删除作品)

  • xsmax双卡双待怎么弄(xsmax双卡双待怎么装)

    xsmax双卡双待怎么弄(xsmax双卡双待怎么装)

  • 抖音怎么发本地音乐(抖音怎么发本地图片)

    抖音怎么发本地音乐(抖音怎么发本地图片)

  • dvremind.exe是什么进程 dvremind进程查询(wrme.exe是什么)

    dvremind.exe是什么进程 dvremind进程查询(wrme.exe是什么)

  • Lsass32.exe是什么进程 有什么用 Lsass32进程查询(lsass.exe是什么进程)

    Lsass32.exe是什么进程 有什么用 Lsass32进程查询(lsass.exe是什么进程)

  • Python之ImportError: DLL load failed: 找不到指定的模块解决方案

    Python之ImportError: DLL load failed: 找不到指定的模块解决方案

  • 现代服务是可以做什么的
  • 收到附加税退税的分录
  • 报税是怎么操作的
  • 普通发票的金额包含增值税吗
  • 发票开错对方已抵扣怎么处理
  • 预提费用在资产负债表哪个科目
  • 财务汽车折旧年限的最新规定2020
  • 天猫积分购物券可以退吗
  • 金蝶导出报表
  • 小规模纳税人是个体户吗
  • 库存商品暂估入库
  • 累计折旧的计提分录怎么写
  • 有限合伙企业转让投资股权
  • 公司员工出差发工资吗
  • 公司购买房产给个人发票
  • 月末应付职工薪酬计算方法
  • 年终结账后,应当更换新账的有( )
  • 生产企业出口退税流程
  • 开了专票是否交文化事业建设费?
  • 汇算清缴所得税账务处理
  • 不动产分期转出要交税吗
  • 应交增值税是总额吗
  • w10系统怎么打印文件
  • 以前年度亏损在哪个报表体现
  • 付出去的款项退回的会计分录如何做
  • 新成立公司开票能开多少个点的发票
  • 房地产企业的沙盘模型制作费会计处理
  • 临时工工资的会计处理和税务处理
  • php数组函数题目
  • RegSrvc.exe - RegSrvc是什么进程 有什么用
  • scureapp.exe - scureapp是什么进程 有什么用
  • hp是什么代码
  • 销售机构人员工资属于管理费用吗
  • 盘盈的存货处理
  • php单例模式demo
  • php url函数
  • 小规模企业收到发票
  • 2021年前端面试
  • 年度总产值等于营业收入
  • pwcorr_a命令
  • 锅炉维修项目
  • 现金流量表季度期初现金余额怎么填
  • 企业所得税报表怎么更正
  • dubbo 实现原理
  • 报销业务招待费是什么凭证
  • sql2008r2安装教程
  • mysql创建数据库的操作步骤
  • sql,server
  • 未开票收入如何计提增值税
  • 增值税的预缴税怎么算
  • 劳务公司开出的劳务票需要申报个税吗
  • 行程单入账多久钱能到账
  • 企业优惠政策是什么意思
  • 独立核算的单位是什么意思
  • 库存不够如何结算成本
  • sql提取指定字符串
  • mssql in
  • mysql千万级分页优化
  • win7自带截图保存在哪个文件夹
  • 虚拟机增加磁盘选择物理磁盘分区
  • bd是什么文件
  • mac上safari
  • windows7如何开启游戏模式
  • win10搜索功能不好用
  • win7激活工具怎么使用
  • freebsd服务器怎么样
  • ExtJS4 动态生成的grid导出为excel示例
  • js计算字符串长度 汉字长度
  • Activity的四种启动模式和onNewIntent()
  • linux常用命令及实例
  • unity安装进度条不动
  • Python连接MySQL并使用fetchall()方法过滤特殊字符
  • python操作access数据库
  • jqueryshow和hide封装
  • 22号天蝎座的运势
  • 国家辽宁税务总局
  • 税务核查是什么意思
  • 政府免费
  • 三门峡哪个小区是原火葬场
  • 每个省几个市
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设