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

news2024/11/13 9:17:19

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

上一篇:把设计模式用起来!(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.coloradmin.cn/o/2147922.html

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

相关文章

【prefect】python任务调度工具 Prefect | 可视化任务工具 | Python自动化的终极武器 | 高效数据管道管理

一、产品介绍 1、官方 Github https://github.com/PrefectHQ/prefect 2、官方文档 https://docs.prefect.io/3.0/get-started/index 3、Pgsql说明 正确的python链接pgsql如下: import psycopg2 from sqlalchemy import create_enginedef connect_with_psycopg2(…

【机器学习】经典数据集鸢尾花的分类识别

【机器学习】经典数据集鸢尾花的分类识别 1、数据集介绍1.1 数据集详情 2、实验内容2.1 准备数据集2.2 创建颜色映射对象2.3 绘制特征散点图2.4 数据的归一化2.5 数据的标准化 3、实验截图提取萼片长度与萼片宽度分类提取萼片长度与花瓣长度分类提取萼片长度与花瓣宽度分类提取…

Photoshop 2021安装教程

软件介绍 Adobe Photoshop,简称“PS”,是美国Adobe公司旗下最为出名的图像处理软件系列之一。ps 2021新增一键换天空,AI只能滤镜,新增内置的画笔工具极为丰富,成千上万的精致像素、动态和矢量画笔可以满足你的各种绘图…

谷歌深度学习研究揭示OpenAI O1模型优化策略:比规模更重要的计算效率

引言 近年来,大型语言模型(LLMs)如OpenAI的GPT-4和Google DeepMind的Palm 2已成为自然语言处理领域的佼佼者,它们通过生成类人文本、回答复杂问题、编写代码等能力,改变了许多行业的工作方式。然而,随着这…

2.4 数据库表字段约束

一、数据库三大范式 我们构造数据库的时候必须要遵守一定的原则,那这个规则就是范式关系型数据库,一共有六种范式,一般情况下只需要满足第三范式即可。 ​第一范式:原子性构造数据库必须遵循一定的规则,这种规则就是…

使用集成学习对不同的机器学习方法进行集成

数据入口:数据人才的现场调研 - Heywhale.com 本数据集中有 43 行,19 列,数据集包含如下字段: 首先读取数据: import pandas as pd# 读取Excel文件 data pd.read_excel(数据人才的现场调研.xls)可以输出每一列含有…

供方软件供应链安全保障要求及开源场景对照自评表(下)

国标《信息安全技术 软件供应链安全要求》确立了软件供应链安全目标,规定了软件供应链安全风险管理要求和供需双方的组织管理和供应活动管理安全要求。 开源软件供应链作为软件供应链的一种特殊形式,该国标亦适用于指导开源软件供应链中的供需双方开展组…

C HTML格式解析与生成之gumbo

测试 #include <fstream> #include <iostream> #include <stdlib.h> #include <string>#include "../src/gumbo.h"// 提取纯文本内容 static std::string cleantext(GumboNode* node) {if (node->type GUMBO_NODE_TEXT) {return std::st…

【TabBar嵌套Navigation案例-关于页面 Objective-C语言】

一、关于页面 1.首先,看一下我们的示例程序 点击关于以后,它实际上,跳到的也是SettingController,然后呢,传一个plist,但是,这个Controller里边,又多了一个header,所以,这个里边,我们也是用继承的方式去写,因为其他的页面没有这个header,不是所有的Setting都有he…

数据结构--结构体数组和结构体指针

1.定义结构体数组存储5个学生的信息&#xff1a;姓名&#xff0c;年龄&#xff0c;性别 定义函数实现输入&#xff0c;要求形参使用结构体指针接收 函数实现5个学生年龄排序(注意对年龄排序时&#xff0c;交换的是所有信息) 定义函数实现输出&#xff0c;要求形参使用结构体…

Innovus跑到中途想要更换library怎么办?

有的小伙伴在跑innovus时&#xff0c;可能会碰到library更新等问题。但此时&#xff0c;place已经跑完了&#xff0c;又不想重新跑&#xff0c;怎么办呢&#xff1f; 其实&#xff0c;每次保存的innovus database里面都有专门存放这些数据的文件。我们可以将其中一些setting文件…

VBA技术资料MF197:禁用复制的快捷键

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Linux内核结构

Linux内核结构 文章目录 Linux内核结构一、Linux内核结构介绍1.1 总体结构&#xff1a;1.2 Linux内核结构框图&#xff1a; 二、图解Linux系统架构三、shell3.1 shell的含义&#xff1a;3.2 shell的作用&#xff1a;3.3 shell的类型&#xff1a;3.4 shell的使用&#xff1a;3.5…

Allow anonymous access to my Azure OpenAI chat bot

题意&#xff1a;允许匿名访问我的 Azure OpenAI 聊天机器人 问题背景&#xff1a; I have an Azure OpenAI chat bot using my own data (I configured an OpenAI resource and chose Deploy as Web App) . Members of my domain can access it by logging in. Now I want it…

2.5 数据库索引机制

我们往数据表里面保存数据记录越来越多&#xff0c;一旦达到上千万条&#xff0c;那怎么提高检索速度就需要认真考虑了。我们打开手机上的APP都希望能快些加载出内容&#xff0c;这里的因素有很多&#xff0c;但是如何减少数据查找的时间是其中的重要一环。索引机制就是提升数据…

【内网渗透】最保姆级的春秋云镜Privilege打靶笔记

目录 flag1 flag2 flag3 flag4 flag1 fscan扫外网 访问./www.zip拿到源码 tools/content-log.php存在任意文件读取 根据提示读到Jenkins初始管理员密码 ./tools/content-log.php?logfile../../../../../../../../../ProgramData/Jenkins/.jenkins/secrets/initialAdminP…

第十一章 【后端】商品分类管理微服务(11.5)——增强响应

11.5 增强响应 在前后端分离的开发模式下,我们一般会统一后端的响应格式,比如自定义 Response 结构,但每个开发者可能会封装各自的 Response 结构,造成不一致,因此我们需要将响应格式统一起来,定义一个统一的标准响应格式。 11.5.1 创建响应模块 新建 yumi-etms-respon…

AJAX Jquery $.get $.post $.getJSON

AJAX AJAX Asynchronous JavaScript and XML (异步的J avascript和XML)。 Ajax $.ajax <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, in…

【Linux进程控制】进程程序替换

目录 进程程序替换 替换函数 看现象 替换原理 多进程替换 exec*函数使用&#xff08;部分&#xff09;&#xff0c;并且认识函数参数的含义 1.execl 2.execv 3.execvp 4.execvpe execlp 和execlpe 替换函数总结 进程程序替换 替换函数 有六种以exec开头的函数&am…

AI大语言模型的全面解读

大语言模型&#xff08;Large Language Models, LLMs&#xff09;无疑是近年来最耀眼的星辰之一。他们以惊人的语言生成能力、上下文理解能力以及对复杂任务的泛化能力&#xff0c;正在深刻改变着自然语言处理&#xff08;NLP&#xff09;乃至整个AI领域的格局。 本文将从专业角…