把设计模式用起来(3)用不好的原因之时机不对

news2024/12/24 8:27:33


上一篇:《把设计模式用起来(3)——用不好的原因 之 实践不足》icon-default.png?t=O83Ahttps://blog.csdn.net/nanyu/article/details/141939342

本篇继续讲设计模式用不好的常见原因,这是第二个:使用设计模式的时机不对。

二、时机不对

这里说的时机并不是单纯指软件研发周期中的时间阶段,而是指条件;更具体一点,指程序员应该满足什么条件,才是使用设计模式的好时机。

第一个条件前面说过了,得有问题。第二个条件,程序员需具备分析问题的能力。毕竟,只有通过分析才能从问题得到模式,如图:

图:  从问题到模式

这张图中最重要的是分析,最不重要的是模式。你甚至可以认为,一个没学过模式的程序员面对某个具体问题,只要分析得当,往往也能应用正确的模式,只是他自己不知道自己组织代码方式,被称作某某模式。

那么,我们要如何获得更强的分析能力呢?其一,对问题所属的业务逻辑越熟悉,对问题就越了解;其二,既然模式是此过程的结果,那么,熟悉模式也有利于我们强化分析问题的能力。由此,我们可以画一张更复杂一点的图:

图:  问题-分析-模式

尽管熟悉模式倒过来有助于理解问题,但程序员的更多努力仍需用在正向路径:熟悉业务→理解问题→分析问题→找到并应用正确的设计模式。

在理解问题的基础上,思考是否需要以及如何使用设计模式,这个结论听起来是如此的自然而然,几乎称得上是一条“公理”,但确实有很多程序员,特别是正在学习设计模式或自诩擅长设计模式的程序员,容易违背,犯“先有模式,然后到处找问题”的错误。

有同学说,“老师,虽然我心里确实装满设计模式,快溢出来的那种,但我并不会犯拿模式硬套问题的低级错误;相反,我总是在看到某个问题和某个模式匹配度很高的情况后,才会放心地套用设计模式。”

“只是放心吗?难道没有开心?”

“当然也开心啊!每当用对一次设计模式,我的内心充满成就感。”

这正是罪之所在:对设计模式的使用,有迫切的期待。这是贪欲,这是心魔,是引发更多软件研发问题的万恶之源。这种心态很容易让我们提倡的“工作逼迫你使用设计模式”,变成“你逼迫工作使用设计模式”。

说这么多,是在表达一个观点:使用设计模式应宁缺勿滥,因为,一段用错设计模式的代码往往比未使用模式的代码,更令后来人头痛。

每一个设计模式,都是在表达特定意图(Intent)的一种组织代码的方式。一段代码用上一个设计模式,意味着这段代码至少多出了两个明显的属性:一是它的意图,二是它的代码结构。一段什么设计模式都没用上代码,它就是一段代码;而一段代码用上了设计模式,代码中的设计模式就像人群有个显眼包,它会一直叫嚷:“看我,看我!我的设计意图是……我的实现结构是……”

那么,阅读者接收到这两个信息,是好事还是坏事?这就得看设计模式用对与否。幸福的代码都是相似的,不幸的代码却各有各的不幸,见表:

功能满足

(业务)

模式选择

(意图)

模式实现

(结构)

不幸的效果

表达了错误的意图且该意图未正确实现,程序不对劲

表达并实现了一个错误的意图,程序不对劲

意图正确,但该意图实现有错,程序不对劲

表达了错误的意图,且意图实现有误,但程序能跑对

用一个错误的模式实现了程序所需的功能

无论模式选对选错,也无论功能满足与否,表中几种应用情况中的设计模式,都会给代码阅读者带来更多干扰甚至误导,毕竟它们会说话。

这里特别讲讲表中最后一类不幸:“用一个错误的模式实现了程序所需功能”。这里最常见的“错误”,就是用了一个并不需要的模式。比如,使用策略模式,但直至系统下线也没用上第二个策略。再如,实现了一个无比强大的解释器,却只用它顺序执行指令。

丁小明严肃地从座位站起来:“老师,您应知道‘防御性编程’?程序员总是预设程序存在问题且将持续需要修改。所以,尽管在刚开始做设计时我们无法预测是否有第二个策略,但我们应该预设它有。至于解释器的例子,确实有点过度设计之嫌,但原则上,假定未来会有复杂的流程脚本需要执行,不对吗?”

这是很多同学都会有的疑惑:防御性编程是对的,可是切忌过度设计也是对的,日常编程做设计,能不能有一个简单明了且有效的方法,能迅速将我们从“加上!”和“不要!”,甚至是“砍掉!”的纠结中拉出来?

具体到何时使用设计模式这个问题,新的疑惑是:假设我还没有完全掌握业务需求就被迫写代码,那这些代码未来一定会变,那么,我现在是不是应该预防性地多加使用设计模式?毕竟,设计模式生来就是为了应对变化。让我们画张图来更清楚的表达:

因为会有变化,所以就马上用模式?

这种想法是错的,它把工作理想化了,并且弄错了工作首要目标。编程工作首先需保证正确实现当下的功能,然后才去考虑如何更好地就应对未来的变化。

为什么是这样先后次序?有两个理由,第一个略显功利:先快点做对,再慢慢做好,这样比较不会挨训,也可以反过来说,你上来就花大力气让代码能应对未来的65536种变化,大概率也得不到领导夸奖。第二个理由很客观:后者依赖前者,即,通常,正是在从不对,到不那么对,到最终做对的过程中,才能对眼下的功能、未来的变化、应有的设计这三者都产生深刻的理解。

丁小明再次发问:“有些功能未来会发生的变化,在程序员一行代码未写时,就可以猜出十之八群,这种情况下,程序员直接用上设计模式,也不合理吗?”这种理想状态当然存在。诸如:

  • 项目前期工作非常棒,需求清晰,设计详细,详细到此处该用什么模式都写出来了;
  • 你对此类问题有深刻理解,或有可靠的经验,此类功能后续的变化路径,你看得清楚、也看得长远;
  • 针对眼前这类问题,业界有教科书般的解决方法。

更多的时候,程序员处在水深火热中:

  • 甲方对现有的功能都说不清楚,遑论未来的变化;
  • 甲方基于防御性心理,罗列了各种各样的,未来可能的变化;
  • 甲方没怎么提,我方(领导、产品经理、程序员自己)设想了一大堆;
  • 甲方没怎么提,我方也没怎么想,但因为业务领域问题,我方并未正确理解甲方的真实需求;
  • 甲方提了一些,我方想了一些,并且我方正确地理解了甲方,只是不管甲方说还是我方想的,都有不对的地方;
  • ……

如果某一块的功能需求还比较模糊,作为乙方,千万不要自信可以通过一个“强大的设计”以做到“以不变应万变”,从而“立于不败之地”。此时的正确做法,应是直接的、快速地把当前所理解的功能做出来,并借助它尽快确定相关需求。

对问题的理解是一切设计的基础,不过,实现设计的过程,能极大帮助程序员全面地,深入地理解问题。多数时候,甲方能告诉你需求,但不能帮你做需求分析,而程序员因为跨领域的原因,所做的需求分析仍然有不少模糊与暧昧。比如,功能F1客观上需要的输入是I1、I2、I3,但程序员有可能在开始时认为是I1、I3和I4。有很多方法有助发现并纠正这个错误认知,其中一种非常高效的方法,就是编写代码尝试实现,在实现的过程,即可验证、强化、纠偏、补充程序员对业务系统的理解,包括厘清对象职责和理清对象关系,这二者是面向对象和用对设计模式的重要基础。

这是本小节的结论:除非你对问题理解到位透彻,否则不要一开始写代码就想着使用设计模式,在功能写对之前,更不要为了该功能“未来可能的变化”去套用设计模式。

这个结论只说了不要,那什么时候可以要呢?两点:

  1. 如果你对问题和业务所在领域非常有经验,那么,可以直接上设计模式以应对未来的变化;
  2. 否则,请在变化发生一次、两次、甚至三次的时候,再开始考虑使用设计模式重构代码。

台下有同学一脸落莫,问:“老师,我赞同第二点,但我们的领导不愿意给我重构所需的资源,比如时间,怎么办?”。这是回到上一小节“实践不足”中的情况B了。你可以屈服,从此不去想设计模式的好;也可以造反,说服领导,或想办法让自己当上领导;还也可以跳槽。无论如何,我都不建议一个程序员在这种恶劣的工作环境下,一边要抓紧完成业务功能,一边要努力用对设计模式。注意,当我说这话时,我站边技术主管。本来,主管只需检查你功能做对做错,现在,他需要同时检查功能和模式,其中后者还有需区分选择和实现上的错误,诸如:(a) 功能做错,模式选错,模式写错;(b) 功能做错,模式选对,模式写错; (c) 功能做对,模式选错,模式写对……(参见表2)。

猜,技术主管在这种场景下,最喜欢说的是哪一句话?答:“你这是要把错误雕成一朵花吗?”

来听一个源于真实案例改编的故事吧。主人公本应是丁小明,为节省篇幅,我们用“你”来代替。

假设问题为Q,正确答案是A;而因为理解有误,你以为需要实现的业务逻辑是B,并且你迅速想到B未来有可能发展成B1、B2、B3。想到这里,你一边啜吸奶茶发出嗞嗞嗞的声音;一边在脑海中构建原始思路C。为了更好地表达思路,也为了更好地应对B1、B2、B3,你果断选用设计模式D,D的意图是I。不过,由于你还是设计模式新人,所以你真实想表达的意图其实是J,而你写的模式很像D但又不是D,称作“D' ”。测试一把,确实能实现B,你充满成就感地提交了代码E。

技术主管开始审查E,他迅速嗅到D的味道;会心一笑,品一口咖啡,感觉自己像羽扇纶巾的诸葛亮,准备欣赏一场漂亮的战役,看看自己的员工如何通过设计模式优雅地干掉Q。10分钟过去,20分钟过去,30分钟过去……经验老到的主管,终于发现D` 和 D 只是长得像而已。

主管放下代码,翻出上次设计模式内训的文档,发现当时你写的答案那叫一个似是而非。他叹一口气,陷入自责。

1个小时过去,主管猛然领悟,你的真实意图是J。

2个小时过去,主管醍醐灌顶:“这家伙想要实现的业务逻辑是B,不是A!”,不过,纵使如此,也不应该用D啊?看一眼时间是夜里11点30分,还早;他拨通了你的电话。

夜深人静,主管的身边人呼吸均匀,偶尔吐一两句梦话。主管轻悄悄地换个姿式,继续听话里的你兴奋地谈着:“B1、B2、B3变化,可能还是保守了,我有一种预感,三个月以后,随着用户量的剧增,B99,B100,B101也是有可能发生的……”

这样的破事来个三四次,故事中主人公的工作类型就会发生变化,参见上一小节“实践不足”的情况D、情况C、情况A。

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

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

相关文章

linux的文本编辑器vim常用操作命令介绍

目录 一、vim介绍 二、vim的特点 1、模式编辑 2、强大的命令集 3、可配置性 4、插件系统 5、多平台支持 三、vim的基础用法 1、打开或创建文件 2、移动光标 3、编辑文件 4、返回命令模式 5、保存文件并退出 6、不保存并退出 四、vim的部分进阶用法 1、快速删除行 2、撤销操作…

数据结构——复杂度讲解

已经太久没用更新了,由于各种原因,导致很久没用更新了,但是停更期间我也是一直在很努力的学习与复习之前学过的知识,读了两本C语言的数据,初学者也是可以看的,推荐给大家,如果需要pdf&#xff0…

SAP TR传输工具

实现效果 不用释放请求,可以把对方对象从DEV直接释放到目标系统中 表对象设计 表结构设计 1. ZSAB0007 Develop toolset: current working objects 2. Structure:ZSAB0008 发版计划请求列表 3. ZSAB0022 Development objects - object search r…

Bootstrap布局实例(偏移列)

偏移是一个用于更专业的布局的有用功能。它们可用来给列腾出更多的空间。例如,.col-xs-* 类不支持偏移,但是它们可以简单地通过使用一个空的单元格来实现该效果。 为了在大屏幕显示器上使用偏移,请使用 .col-md-offset-* 类。这些类会把一个…

Vue3: setup语法糖

一. setup语法糖 在 Vue 3 中,setup 语法糖是一种简化组件内部状态和方法管理的特性。它允许你将组件的逻辑直接编写在组件的定义中,而不是像 Vue 2 那样需要在 methods 和 data 属性中管理。setup 语法糖基于 ES6 的类的静态方法,允许你更灵…

改进大语言模型的最全方法!

这是一篇关于适应开源大语言模型(LLMs)的三部系列博客的第一篇。本文探讨将LLM适应领域数据的各种方法。 第二部分讨论如何确定微调(fine-tuning)是否适合您的用例。第三部分探讨策划良好训练数据集的一些经验法则。 0 引言 大…

NX二次开发—批量导出点工具

在NX上进行二次开发,设计一个UI界面,将选择的点导出 在NX上,进行UI样式编辑器 添加选择对象,修改标题,设置为多选 创建一个组,添加枚举,设置标题和枚举内容,不显示枚举标题LabelVis…

云微客AI文案编写,有手就能出“爆款”

​现如今新媒体时代,短视频平台已经成为了企业品牌宣传的重要战场,那么如何利用短视频平台进行品牌宣传、制作爆款视频就成为了各大商企需要解决的难题。由此,不得不提到云微客短视频矩阵系统,一键助力商企品牌轻松打造爆款内容。…

python学习第九节:爬虫实战-抓取地址库

python学习第九节:爬虫实战-抓取地址库 话不多说,直接上代码;下面的代码是从统计局抓取地址库并保存为json格式和excel格式。大家拿到代码直接运行即可。 #codingutf-8 #加入上面这行代码表示可以在下面代码中包含中文 import bs4 #网页解析…

wopop靶场漏洞挖掘练习

一、sql注入漏洞 1.在搜索框输入-1 union select 1,2,3# 可以看到页面有回显 2.查询数据库名 -1 union select 1,2,database()# 3.通过查询admin表的数据可以进行登录后台 -1 union select 1,2,group_concat(user_name,user_pass) from admin# 二、文件上传漏洞 1.登录后台…

李龙受邀参加济南高新区“质量月”能力提升活动,并做专题培训

9月11日,济南高新区在山东省知识产权公共服务平台举行2024年“质量月”启动仪式暨质量管理能力提升系列活动。安畅检测首席技术专家李龙先生出席了“质量月”启动仪式 ,并为到场企业代表就信创产业相关知识做了专题培训。 济南市市场监督管理局党组成员王…

101.游戏安全项目-创建人物对象结构

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 内容参考于:易道云信息技术研究院 上一个内容:100.游戏安全项目-不可见数据的搜索 以 98.游戏的启动与多开-分析与实现多开器 它的代码…

7.sklearn-逻辑回归、精确率和召回率、ROC曲线和AUC指标

文章目录 环境配置(必看)头文件引用1.逻辑回归1.1 API介绍1.2 代码实现1.3 运行结果 2.分类评估方法2.1 精确率(Precision)2.2 召回率(Recall)2.3 F1-score2.4 分类评估报告api2.5 代码工程2.6 运行结果 3.ROC曲线与AUC指标3.1 TPR和FPR3.2 ROC曲线3.3 A…

2024年宠物空气净化器选购攻略?哪款最值得买

表妹在去年刚上大学就养了一只爱掉毛的银渐层,宿舍矛盾不断激化,甚至一度产生了退学的念头。 究其原因,主要是她觉得刚进大学太孤独和身边的人都不太熟,所以就不想聊天,为了缓解这种孤独养了一只银渐层,有…

用 nextjs 创建 Node+React Demo

1、环境准备 1、安装Node 访问Node官网下载对应Node版本:Node官网,安装成功后通过命令查看当前node版本 node -v2、安装Node版本管理工具nvm 如果nvm install 安装node失败,一般是网络问题,可以用手机热点或者翻墙 # 安装nvm c…

ssm“健康早知道”微信小程序 LW PPT源码调试讲解

第二章开发技术与环境配置 以Java语言为开发工具,利用了当前先进的SSM框架,以MyEclipse10为系统开发工具,MySQL为后台数据库,开发的一个“健康早知道”微信小程序。 2.1 Java语言简介 Java是由SUN公司推出,该公司于2…

通义灵码获得国产 AI 编码工具最高成绩丨阿里云云原生 8 月产品月报

云原生月度动态 云原生是企业数字创新的最短路径。 《阿里云云原生每月动态》,从趋势热点、产品新功能、服务客户、开源与开发者动态等方面,为企业提供数字化的路径与指南。 趋势热点 🥇 Gartner 首次发布 AI 代码助手魔力象限&#xff0…

数据链路层/ARP协议

当一个报文需要从一个主机转发到另一个主机的时候,表面上是 IP 报文的跨网络转发,但也并不是直接就将数据报转发到对应的主机了,而是从网络层更下面的数据链路层一跳一跳的转发到下一个链路层,数据链路层实现的是到达短距离目的地…

2024年让你的营销机构省时的18款AI工具

提高效率是经营一家盈利的营销机构的关键。利用AI工具不仅可以提升效率,还能够保持甚至增加团队的工作量和工作质量。 这些都是非常理想的结果。然而,随着越来越多的AI工具问世,从哪里入手呢? 在这里,你会找到一份简…

公司小、资源少?别慌!5招让你有效开展测试工作

在经济环境下行的当下,很多测试人员被迫去一些小公司先渡过难关,但是去小公司做测试往往都会遇到很多问题,除了要给一些开发人员普及测试的概念和流程,而且还要从0-1准备测试资源,因为我就是这么过来的,所以…