当前位置: 首页 > news >正文

把设计模式用起来!(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)呢?如果你不能张口就来,那么,从对个别设计模式的认知,还没达到知根知底的水平。

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

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

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

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

相关文章:

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

(清华大学出版社 《把设计模式用起来》书稿试读) 上一篇:把设计模式用起来!(3)用不好模式?之时机不对 为什么用不好设计模式?——原理不明 难搞的顾客:“抹这种霜&#…...

安卓13去掉下拉菜单的Dump SysUI 堆的选项 android13删除Dump SysUI 堆

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析3.1 位置13.2 位置24.代码修改5.编译6.彩蛋1.前言 客户需要去掉下拉菜单里面的Dump SysUI 堆图标,不让使用这个功能。 2.问题分析 android的下拉菜单在systemui里面,这里我们只需要定位到对应的添加代…...

vue3常用的组件间通信

一 props props 可以实现父子组件通信&#xff0c;props数据是只读。 1. 基本用法 在父组件中&#xff0c;你可以这样传递 props&#xff1a; <template><ChildComponent message"Hello, Vue 3!" /> </template><script setup> import C…...

Windows 查找特定进程的ID并杀死

"*分析用户信息.py*" 换为自己的文件名 Get-WmiObject Win32_Process | Where-Object { $_.CommandLine -like "*分析用户信息.py*" } 查找后 内容如下 __GENUS : 2 __CLASS : Win32_Process __SUPERCLASS …...

Snapchat API 访问:Objective-C 实现示例

Snapchat 是一个流行的社交媒体平台&#xff0c;它允许用户发送和接收短暂存在的图片和视频。对于开发者来说&#xff0c;访问 Snapchat API 可以为应用程序添加独特的社交功能。本文将介绍如何在 Objective-C 中实现对 Snapchat API 的访问&#xff0c;并提供一个详细的代码示…...

ps证件照蓝底换白底

ps证件照蓝底换白底 1、打开 Photoshop&#xff0c;导入需要处理的照片。 2、左侧工具栏中选择“魔棒工具”&#xff0c;点击证件照的背景区域进行选择。 3、使用快捷键 Shift F5 或者从顶部菜单选择“编辑” -> “填充”&#xff0c;在弹出的对话框中选择“填充内容”中…...

阿里云kafka消息写入topic失败

1. 问题现象描述 20240918,14:22&#xff0c;测试反馈说kafka有问题&#xff0c;生产者写入消息的时候报错&#xff0c;并发了一张日志截图&#xff0c;主要报错如下&#xff1a; to topic xxxx: org.apache.kafka.common.errors.TimeoutException: Expiring 1 record(s) for x…...

图像放大效果示例【JavaScript】

实现效果&#xff1a; 当鼠标悬停在小图&#xff08;缩略图&#xff09;上时&#xff0c;大图&#xff08;预览图&#xff09;会随之更新为相应的小图&#xff0c;并高亮当前悬浮的小图的父元素。 代码&#xff1a; 1. HTML部分 <!DOCTYPE html> <html lang"z…...

【C#生态园】云端之C#:全面解析6种云服务提供商的SDK

C#开发者必读&#xff1a;深度比较6种云服务SDK 前言 随着云计算技术的迅猛发展&#xff0c;越来越多的企业和开发者选择将应用程序部署到公共云平台上。针对C#开发者而言&#xff0c;各大云服务提供商纷纷推出了适用于C#的SDK&#xff0c;以便开发者能够更轻松地与其云服务进…...

远程升级又双叒叕失败?背后原因竟然是。。。

最近又遇到了远程升级接连失败的情况&#xff0c;耐心和信心都备受折磨&#xff01; 事情是这样的&#xff1a;有客户反馈在乡村里频繁出现掉线的情况&#xff0c;不敢耽搁&#xff0c;赶紧联系小伙伴排查测试&#xff0c;最后发现&#xff0c;只有去年某一批模块在当下环境才…...

【测试】——Selenium API (万字详解)

&#x1f4d6; 前言&#xff1a;本文详细介绍了如何利用Selenium进行Web自动化测试&#xff0c;包括定位元素&#xff08;如cssSelector和xpath&#xff09;、常用操作函数&#xff08;如点击、输入等&#xff09;、窗口管理、键盘鼠标事件和浏览器导航&#xff0c;以及处理弹窗…...

Redis:原理+项目实战——Redis实战3(Redis缓存最佳实践(问题解析+高级实现))

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理项目实战——Redis实战2&#xff08;Redis实现短信登录&#xff08;原理剖析代码优化&#xff09;&#x…...

刚刚,Stable Diffusion 2024升级,最强Ai绘画整合包、部署教程(解压即用)

2024Ai技术大爆发的元年 目前两款Ai神器大火 一款是大名鼎鼎的Chat GPT 另外一款—Stable Diffusion 堪称全球最强Ai绘画工具 Stable Diffusion Ai绘画2024版本更新啦&#xff01; 从4.8.7更新至**4.9版本&#xff01;**更新优化和大模型增加&#xff0c;无需安装&#xf…...

【AIGC】ChatGPT提示词助力高效文献处理、公文撰写、会议纪要与视频总结

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;高效英文文献阅读提示词使用方法 &#x1f4af;高效公文写作提示词使用方法 &#x1f4af;高效会议纪要提示词使用方法 &#x1f4af;高效视频内容分析提示词使用方法 &a…...

centos7更换国内下载源

&#x1f4d6;centos7更换国内下载源 在CentOS 7上更换为国内源可以通过替换 /etc/yum.repos.d/CentOS-Base.repo文件来实现。以下是一些常用的国内源以及如何更换的示例&#xff1a; 阿里云源&#xff1a; mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Bas…...

【Linux】常用指令【更详细,带实操】

Linux全套讲解系列&#xff0c;参考视频-B站韩顺平&#xff0c;本文的讲解更为详细 目录 一、文件目录指令 1、cd【change directory】指令 ​ 2、mkdir【make dir..】指令​ 3、cp【copy】指令 ​ 4、rm【remove】指令 5、mv【move】指令 6、cat指令和more指令 7、less和…...

力扣3290.最高乘法得分

力扣3290.最高乘法得分 递归 记忆化搜索 对于b数组&#xff0c;从右往左考虑取不取&#xff0c;如果取则问题变成b[0] ~ b[i-1]间找j - 1个数 如果不取&#xff0c;则问题变成b[0] ~ b[i]间找j个数即dfs(i,j) max(dfs(i-1,j) , dfs(i-1,j-1) a[j] * b[i]) 边界&#xff1a…...

Python | Leetcode Python题解之第413题等差数列划分

题目&#xff1a; 题解&#xff1a; class Solution:def numberOfArithmeticSlices(self, nums: List[int]) -> int:n len(nums)if n 1:return 0d, t nums[0] - nums[1], 0ans 0# 因为等差数列的长度至少为 3&#xff0c;所以可以从 i2 开始枚举for i in range(2, n):i…...

深入理解 ClickHouse 的性能调优与最佳实践

1. 介绍 ClickHouse 是一款由 Yandex 开发的开源列式数据库&#xff0c;专为在线分析处理&#xff08;OLAP&#xff09;场景设计。它以极高的查询性能著称&#xff0c;尤其适用于大规模数据的快速聚合和分析。自发布以来&#xff0c;ClickHouse 在多个行业中得到了广泛应用&am…...

Elasticsearch——介绍、安装与初步使用

目录 1.初识 Elasticsearch1.1.了解 ES1.1.1.Elasticsearch 的作用1.1.2.ELK技术栈1.1.3.Elasticsearch 和 Lucene1.1.4.为什么不是其他搜索技术&#xff1f;1.1.5.总结 1.2.倒排索引1.2.1.正向索引1.2.2.倒排索引1.2.3.正向和倒排 1.3.Elasticsearch 的一些概念1.3.1.文档和字…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...