把设计模式用起来!(4) 用不好模式?之原理不明

(清华大学出版社 《把设计模式用起来》书稿试读)

上一篇:把设计模式用起来!(3)用不好模式?之时机不对

为什么用不好设计模式?——原理不明

难搞的顾客:“抹这种霜,真的能让我额头上的皱纹减少?”

销售:“当然啦,只要你坚持使用我们的淡纹霜,你脸的上细纹一定会比没有抹要少很多。”

难搞的顾客:“你们有没有现成的测试数据?提供三个对比组至少一年的数据,一组不抹,一组抹你家的,最后一组抹那瓶比你家便宜200元的霜。请您现在就把三组测试人员前后一年的皮肤状态数据,拿出来我要看下……”

销售:“这个……”

作为类比,再来看关于设计模式效果的对话,如下:

布道师:“设计模式能让代码更好的应对未来的变化……”

难搞的程序员:“不要和我说未来,设计模式被世人广泛认识都30年了,就没有现成的一些数据来证明它们的作用吗?”

布道师:“嗯,具体一点,您想看什么数据?”

难搞的程序员:“比如说,有人于2000年在某项目的一段代码里用了P模式,十年过后,该项目经历无数修改,依然存活。我想知道,当初代码中参与了P模式的那些代码,它们变化几何?会不会已经面目全非?”

布道师:“我明白你的意思了,一组应用了设计模式的代码,当然也是代码,所以你想观察号称可以‘更好应对变化’的设计模式自身,会不会反倒没能扛过变化?如果是,就能证明设计模式就是泥菩萨过河,自身难保,徒有虚名?”

难搞的程序员:“是的。”

布道师:“你的想法是错的。”

“难搞的程序员”想要的数据,倒是可以从不少论文中查到。我挑选了有延续关系的两篇,分别是2007年的《An empirical study on the evolution of design patterns(关于设计模式演化的一个实证研究)》和2012年的《How changes affect software entropy: An empirical study(变化如何影响软件熵值:一个实证研究)》。两篇论文的研究对象,均为知名的开源软件系统,它们是:

表 3 两篇论文所用到的开源软件项目

项目

关键特征

研究数据时间跨度

备注

JHotDraw

中型项目/主要开发语言:Java

3年 (2001~2004)

仅论文1使用

ArgoUML

中型项目/主要开发语言:Java

论文1:5年 (2000 ~2005)

论文2:11年 (1998~2009)

Eclipse-JDT

大型项目/主要开发语言:Java

论文1:3年 (2001~2004)

论文2:10年 (2001~2011)

Mozilla

大型项目/主要开发语言:C++

13年 (1998~2011)

仅论文2使用

Samba

中型项目/主要开发语言:C++

8年 (1996~2004)

仅论文2使用

下面列举两篇论文涉及到设计模式与代码变更关系的一些实证结果:

  • 在软件系统的演化进程中,尽管有些设计模式(指使用了设计模式的代码,下同)确实很少发生代码变更,但有些设计模式变更剧烈,甚至超过没有使用任何设计模式的代码;
  • 确实有会一些设计模式比另一些模式,在不同的项目中都显得更惰性(变更少、代码稳定),反过来,有些模式明显比别的模式更善变(一有变更,首先动到的就是参与该模式的代码);
  • 不同的设计模式产生频繁更改的代码位置也不尽相同,有的喜欢改动类的属性、有的喜欢改类的方法,有的改方法的实现,还有的最喜欢添加子类;
  • 参与设计模式的代码的变更频率,以及它们所引发的其它代码的变更的数量,取决于模式自身,更多取决于模式所要实现的业务功能。越关键、重要的功能,变更通常越剧烈,相应的代码维护工作量也越大;
  • 如果用错了设计模式,那么,后续发现问题加以订正时,变更往往更加剧烈(或许应该用“惨烈”来形容)——无论是参与设计模式实现的代码,还是涉及到的其它代码。

类似的实证结果还很多,并且都很有趣,也很值得大家找出这两篇论文细读加深思。不过,此刻我们只需要得出一个最简单的结论:应用了设计模式的代码,并不能“以不变应对万变”;相反,更多时候,设计模式是在“以变治变”

举个论文中的实际例子,参与代理(Proxy)模式的代码,就容易被变更。《How changes affect software entropy: An empirical study(变化如何影响软件熵值:一个实证研究)》论文基于ArgoUML项目的研究结果表明:参与代理模式的类,比不参与任何设计模式的类具有更高的变化熵,也比参与复合、装饰器、工厂方法和观察者模式的类具有更高的变化熵,而与单例、状态策略和模板方法等模式的变化熵没有显著差异(In summary, results indicate that:Classes participating in Proxy design patterns have a higher change entropy than classes that do not participate in any design pattern, and than classes participating in Composite, Decorator, Factory Method, and Observer, while no significant difference can be found with Singleton, State Strategy, and Template Method. )。

为什么会这样呢?让我们简单分析一下。假设在项目中,PA代理A。如果A是一个无关紧要的功能,具体表现为,A功能做出来后无人问津,同时A对其它功能也没有多大影响……这就是前述的结果③。另一种可能,A功能非常重要,总有人用,总有人提建议或意见,于是它一直在改进,于是问题变成:为什么A一修改(包括增加特性),PA就大概率地也要随之更改?

答:因为在代理模式中,代理人不仅要对客户提供被代理人的功能,而且还要调整被代理人对外提供的功能。如果我们用C来表示客户,那么,C、PA、A三者关系如下:

PA的变化,可能来自A。当A兴冲冲地增加了一些新功能,或者气嘟嘟停用了某些功能,作为代理,PA 大概率需要同步这些变化。

PA的变化,也可能来自C。当C意欲增加新的请求时,PA必须同步增加对该项请求的处理。有意思的是,这时候A可能响应变化,也保持不动,后者的意思是:让PA先把这项请求应付下来。

如果变化仅仅来自两端,那还不能称代理人善变。PA的变化,极大可能来自自己,事实上这正是代理模式中的代理人最喜欢干的事:在C不知不觉和A不声不吭的状态下,为了某些特定需要,修改了某些请求,修改了某些响应,包括前面所说的:抛开A自行处理、响应了C的一些请求。在真实的项目世界中,存在大量A不太重要,但PA很重要,也就是“太监”比“皇帝”干的活多的情况。

PA只能代理A吗?不,现实世界中的项目,一个代理类需要代理多个被代理类的情况并不少见。

综上所述可知,参与代理模式的代码确实是善变的(除非被代理人和代理人都不重要)。我们真正关心的问题来了:以Proxy模式为例,一段善变的代码,是如何帮助其它代码更好地应对变化呢?我们让PA来说出答案,它是含泪说的:让C和A都守住单纯,你们那些奇奇怪怪的要求,冲我一个人来吧!

典型的牺牲我一个,幸福其他人。这就是Proxy模式发挥药效的基本原理。当然,并不是所有的模式都有这种思想高度,在本书后面的章节中我们将从源头上讲清楚每一种设计模式的发挥“药效”的原理。

现在就用一句话回答:命令(Command)模式在让代码更好地应对未的变化这件事上,原理是什么?也是通过牺牲自己吗?工厂方法(Factory Method)呢?观察者(Obsever)呢?如果你不能张口就来,那么,从对个别设计模式的认知,还没达到知根知底的水平。

不屈不挠的丁小明:“老师,我是没办法一提某个模式,就想到它的作用原理,但我并不认为我用的设计模式都错了。”

“发烧吃退烧药,流鼻涕就吃感冒药,咳嗽厉害,喝上半个月的止咳糖浆……”

“对啊,烧退了,感冒症状消失了,咳嗽也停了,这样不行吗?”

“当病人可以,当医生不行。”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1539300.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

学习ROS2第一天—新手笔记(humble版本)

————今早七点达到实验室,吃了早饭收拾了一下现在07:24开始学习———— 1. RO2与ROS1的不同架构: ROS1架构下,所有节点都是Master进行管理 ROS使用基于DDS的Discovery机制,和Master说再见 API的重新设计 编译…

数集相等的定义凸显初等数学几百年重大错误:将无穷多各异数集误为同一集

黄小宁 创造型人才的突出特征:敢于独立思考,不愿人云亦云随大流做分数的奴隶。初数中定义域为R的一次函数ykx(正常数k≠1)的值域问题是师生们不屑一顾的初数中的初数,然而数集相等的定义凸显初数一直搞错了y的值域而将…

MD5、SHA256哈希值生成验证工具-生成文件的“指纹ID”-调用了微软.Net Framework里的加密工具来生成哈希值

MD5、SHA256等哈希值生成工具通常用来验证文件的完整性,或者说是生成文件的“指纹ID”。 Windows系统下调用哈希工具,要用命令提示符cmd调用,生成和比较不太方便。我编写了一个小工具,将文件拖拽到软件界面即可生成比较。 下载地址…

前端——表格、列表标签

今天我们来学习一下web开发里面的表格标签、列表标签 常用快捷键&#xff1a; shift alt 下 复制粘贴选中内容 表格标签 table HTML 表格由 <table> 标签来定义。 HTML 表格是一种用于展示结构化数据的标记语言元素。 每个表格均有若干行&#xff08;由 <tr>…

Qt实战案例(60)——利用QTimer类实现实时时间功能

目录 一、项目介绍二、项目基本配置三、UI界面设置四、主程序实现4.1 widget.h头文件4.2 widget.cpp源文件 五、效果演示 一、项目介绍 本文介绍利用QTimer类实现实时时间功能并在状态栏中进行显示。 二、项目基本配置 新建一个Qt案例&#xff0c;项目名称为“TimeTest”&am…

【北京迅为】《STM32MP157开发板使用手册》- 第三十八章 任务管理实验

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…

解决【WVP服务+ZLMediaKit媒体服务】加入海康摄像头后,能发现设备,播放/点播失败,提示推流超时!

环境介绍 每人搭建的环境不一样&#xff0c;情况不一样&#xff0c;但是原因都是下面几种&#xff1a; wvp配置不当网络端口未放开网络不通 我搭建的环境&#xff1a; WVP服务&#xff1a;windows下&#xff0c;用idea运行的源码 ZLM服务&#xff1a;虚拟机里 问题描述 1.…

训练加速和推理加速

1. 训练加速 训练加速指的是通过优化技术、硬件加速等方式&#xff0c;减少训练模型的时间&#xff0c;尤其是对于大规模数据集和复杂模型。 训练的特点&#xff1a; 计算量大&#xff1a;模型训练时需要执行前向传播和反向传播&#xff0c;并在多个迭代&#xff08;epoch&a…

Java 23 的12 个新特性!!

Java 23 来啦&#xff01;和 Java 22 一样&#xff0c;这也是一个非 LTS&#xff08;长期支持&#xff09;版本&#xff0c;Oracle 仅提供六个月的支持。下一个长期支持版是 Java 25&#xff0c;预计明年 9 月份发布。 Java 23 一共有 12 个新特性&#xff01; 有同学表示&…

【Java】网络编程-地址管理-IP协议后序-NAT机制-以太网MAC机制

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a; c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 &#x1f434…

vscode关闭git的提交提示

问题描述&#xff1a; vscode中光标停留在每一行都会有出现git仓库的提交信息&#xff0c;影响代码阅读。 解决方法&#xff1a; 左下角设置齿轮&#xff1a; 输入关键词commit input 取消勾选&#xff0c;即可解决。

Apache subversion 编译流程

目录 1. 概述2. 依赖库简介2.1 Expat2.2 Apache apr2.3 Apache apr-iconv2.4 Apache apr-util2.5 Zlib2.6 OpenSSL2.7 Sqlite2.8 Apache Serf2.9 Apache subversion3. 编译3.1 Expat编译3.1.1 源码信息3.1.2 CMake-GUI3.1.3 编译步骤3.2 APR编译3.2.1 源码信息3.2.2 编译步骤3.…

2024年【中级消防设施操作员(考前冲刺)】及中级消防设施操作员(考前冲刺)模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 中级消防设施操作员&#xff08;考前冲刺&#xff09;根据新中级消防设施操作员&#xff08;考前冲刺&#xff09;考试大纲要求&#xff0c;安全生产模拟考试一点通将中级消防设施操作员&#xff08;考前冲刺&#xf…

mp4转换成mp3,八个超简单视频转换方法

怎么将mp4转换成mp3&#xff1f;在现代数字媒体的世界中&#xff0c;视频和音频的转换变得尤为重要。许多人在观看视频时&#xff0c;常常会被其中的声音吸引&#xff0c;想要单独保存下来。这时&#xff0c;将MP4格式的视频转换为MP3格式的音频就显得尤为必要。MP4是一种常用的…

长时间认知任务中的大脑补偿机制:fNIRS和眼动追踪研究

摘要 在需要高度集中和高效完成关键任务的领域&#xff0c;如何在疲劳状态下维持认知表现是一个非常重要的问题。在这种情况下&#xff0c;帮助大脑克服疲劳的补偿机制研究就显得尤为重要。本研究探讨了生理、行为和主观测量之间的相关性&#xff0c;同时考虑了疲劳对工作记忆…

yolov5/8/9/10模型在VOC数据集上的应用【代码+数据集+python环境+GUI系统】

yolov5/8/9/10模型在VOC数据集上的应用【代码数据集python环境GUI系统】 1.背景意义 VOC数据集被广泛应用于计算机视觉领域的研究和实验中&#xff0c;特别是目标检测和图像识别任务。许多知名的目标检测算法都使用VOC数据集进行训练和测试。VOC挑战赛&#xff08;VOC Challeng…

maxwell 输出消息到 kafka

文章目录 1、kafka-producer2、运行一个Docker容器&#xff0c;该容器内运行的是Zendesk的Maxwell工具&#xff0c;一个用于实时捕获MySQL数据库变更并将其发布到Kafka或其他消息系统的应用3、进入kafka容器内部4、tingshu_album 数据库中 新增数据5、tingshu_album 数据库中 更…

[Unity Demo]从零开始制作空洞骑士Hollow Knight第四集:制作更多的敌人

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、制作敌人僵尸虫Zombie 1.公式化导入制作僵尸虫Zombie素材2.制作僵尸虫Zombie的Walker.cs状态机3.制作敌人僵尸虫的playmaker状态机二、制作敌人爬虫Climber…

Gradio 自定义组件

如何使用 Gradio 自定义组件&#xff0c;Gradio 前端使用 Svelte&#xff0c;后端使用的 Python。如何自定义一个组件呢&#xff1f;Gadio 提供了类似于脚手架的命令&#xff0c;可以生成需要开发组件的前后和后端代码。 创建组件 运行如下命令&#xff0c;gradio 会自动生成…

鹏鼎控股社招校招入职SHL综合能力测评:高分攻略及真题题库解析答疑

鹏鼎控股&#xff08;深圳&#xff09;股份有限公司&#xff0c;成立于1999年4月29日&#xff0c;是一家专注于印制电路板&#xff08;PCB&#xff09;的设计、研发、制造与销售的高新技术企业。公司总部位于中国广东省深圳市&#xff0c;并在全球多个地区设有生产基地和服务中…