首页 > 其他分享 >代码坏味道的变迁

代码坏味道的变迁

时间:2023-07-07 12:15:09浏览次数:33  
标签:编程 函数 第一版 味道 代码 变迁 版中 第二

  2018年,Martin Fowler的《重构》第二版出版,距离第一版,已经19年了。为什么作者要出新版?通过分析两个版本的变化,可以探知端倪。这些变化,一方面体现了作者多年的思考和总结,另一方面也体现了技术潮流的演进。本文先从讨论坏味道的变迁开始。

  《重构》第一版中有22种坏味道,第二版中有24种。相对于第一版,第二版中完全保留了16种。变化的部分分为三种情况:新增、删除和改名。下面分析一下这几类变化。

1 新增的坏味道

  第二版中新增了4种坏味道。

1.1 全局数据(Global Data)

  全局数据,主要是可变的全局数据,“自古以来”就被认为是有害的。第一版中没有出现,反而是一件奇怪的事情。究其原因,大概是因为那时用的是Java。Java是所谓(形式上)纯粹的面向对象语言,不太容易写出全局数据。而第二版中用的是JavaScript。在这种松散的语言中,全局数据就很容易出现了。第二版中增加这个坏味道,算是对第一版中遗漏的弥补。

  为什么第二版要用JavaScript而不是Java呢?作者在书中说是因为JavaScript日益普及。但除此之外,我们还可以看出一个隐含的原因。

  在第一版出版的时候(1999年),我们可以看到,Martin Fowler是一个“面向对象原教旨主义者”,这在那个时代是很普遍的,因此第一版很强调面向对象编程。到了第二版,作者已经成长为一名“编程范式中立主义者”。因此作者会更强调在结构化、面向对象、函数式等编程范式中找到共性的东西。JavaScript的多范式特点恐怕是第二版中采用这一语言的另一个重要原因。

1.2 循环语句(Loops)

  对于同时支持命令式和函数式编程的语言来说的,当可以用 Stream 加 λ 表达式等方式简化代码时,用传统的循环语句就显得臃肿了。在第一版时,Java还不支持 λ 表达式,而作者当时可能也没有关注到函数式编程。在新版中,作者更加注重函数式编程,因此增加了这个坏味道。

  不过,用函数式编程简化循环时要注意一些通用的规则,比如说 λ 表达式应简短,不要有副作用等。

1.3 可变数据 (Mutable Data)

  这个坏味道首先仍然和函数式编程有关,因为函数式编程中理论上是没有“变”量的。

  其次,即使不考虑函数式编程,在能够使用不变数据时,也应该尽量不变。Java中的有一种建议是尽可能用final修饰属性和方法参数,用Collentions.ummodifiableList()来返回不可变列表,都体现了这一思路。在当前的JavaScript中,可以用闭包模拟不可变数据。

1.4 神秘命名 (Mysterious Name)

  编程中,命名是最难的问题之一,即使对于编程老手也是如此。反而新手常常忽略这一点。这个坏味道没有出现在第一版,只能理解为遗漏了。

2 改名的坏味道

  第二版中有4中坏味道进行了改名。

2.1 内幕交易(Insider Trading)

  原名:押昵关系(Inappropriate Intimacy)

  这是应该唯一一个与技术无关的改动。Intemacy的桃色意味较浓,在书中显得不雅而又突兀。改成“Insider Trading”就好多了。

  Insider Trading指模块之间过多的使用了对方的私有部分。以下是几种常见的情形:

  • C++中过度使用“友元”机制
  • 类中的字段设置成了public的,被其他类大量使用
  • 尽管类的字段不是public的,但有大量公用的setter和getter,事实上造成了与上一条类似的后果,这种情况也常常体现为 Feature Envy
  • 子类大量使用父类的protected字段

2.2 冗赘的元素(Lazy Element)

  原名:冗赘的类(Lazy Class)

  改动的原因仍然是“编程范式中立”。当把眼光放开后,不仅类会冗赘,其他元素,如函数、(Python等语言中的)模块等都可能冗赘。因此改为“冗赘的元素”是恰当的。

2.3 过长的函数(Long Function)

  原名:过长的方法(Long Method)

  仍然是因为“编程范式中立”。函数比方法范围更广。方法可以看作特殊的函数。因此第二版提“函数”而不是“方法”。这一现象也出现在多个重构手法的改名中。

2.4 重复的Switch(Repeated Switches)

  原名:Switch语句(Switch Statements)

  这里的Switch语句是switch、 case、 if...elseif...等形式的统称。

  仅从技术角度来说,任何switch语句总可以被多态所代替。在早期的面向对象社区中,有人认为一切swithch语句都应该用多态代替,否则就不够面向对象,不符合“开闭原则”了。从现在的观点来看,这显得有些矫枉过正。有时switch语句的使用是合理的。

  实际上,Martin Fowler在第一版中已经说过,重复的switch才会带来明显的问题。但由于这个坏味道的名字命名为"Switch Statement",因此会让望文生义的人陷入过度设计。所以第二版干脆改成“Repeated Switches”。这样意思就很明确了。

  这里的解决方案常常是策略模式、状态模式或模板模式。要注意的是,如果一个实体类,因为某些属性或状态而有不同的算法,那么一般来说,应该针对这些属性或算法采用上述设计模式,而不是对实体类本身采用多态。

3 删除的坏味道

  第二版中删除了2种坏味道。

3.1 平行的继承体系 (Parallel Inheritance Hierarchies)

  在第一版中已经说过,平行的继承体系是霰弹式修改的特例。而且这一坏味道仅局限于面向对象编程,与“编程范式中立”相悖。大概是因为这些原因,在第二版中干脆删除了。

3.2 不完美的库类 (Incomplete Library Class)

  在第一版中,这个坏味道涉及的问题是,当一个类库不能完全满足需要时的处理的技巧。

  尽管这些技巧是有用的,但这不应该算作坏味道。因为坏味道关注的应该是我们自己掌控范围内的,从而能够用重构技术进行完善的代码。而不完美的类库本身不在我们的掌控范围内,因此在第二版中应该删除。

4 总结

  第二版中对坏味道的修改可归纳为以下几种原因:

  编程范式中立

  这是最主要的原因,影响到的坏味道包括“循环语句”、“可变数据”、“冗赘的元素”、“过长的函数”。其中“可变数据”也可理解为一种遗漏。

  补充遗漏

  包括“全局数据”、“神秘命名”。其中“全局数据”也认为是由于编程范式中立而引发的。

  避免矫枉过正

  包括“重复的Switch”。

  更恰当的命名

  包括“内幕交易”。

  删除重复或不属于坏味道的内容

  包括“并行的继承体系”和“不完美的类库”。

标签:编程,函数,第一版,味道,代码,变迁,版中,第二
From: https://www.cnblogs.com/ybqjymy/p/17534581.html

相关文章

  • 代码的坏味道 《重构改善既有代码的设计》
    1.DuplicatedCode重复代码,在程序中多次出现的相同结构或功能的代码同一个类中的两个函数含有相同的表达式两个互为兄弟的子类中含相同的表达式相互独立的类中出现相同表达式2.LongMethod过长的函数难以理解及维护段函数或间接层具有很强的解释能力、共享能力和选择能......
  • 代码的坏味道
    代码坏味道:是指在代码之中潜在问题的警示信号。并非所有的坏味道所指示的确实是问题,但是对于大多数坏味道,均很有必要加以查看,并作出相应的修改。1. 重复的代码如果你在一个以上的地点看到相同的程序结构,那么当可肯定:设法将它们合而为一,程序会变得更好。同一个class内的两个......
  • 项目受源代码管理。向源代码管理注册此项目时出错。建议不要对此项目进行任何更改
    http://www.noobyard.com/article/p-uweyzjzb-cp.html编译Rocket.Windows.Framework项目的时候提示如题的错误,html 用记事本打开出错的几个项目的.csproj文件,把下面几行内容删掉就好了。vue   <SccProjectName>Svn</SccProjectName>  <SccLocalPath>Svn</SccLocalP......
  • ARIMA模型,ARIMAX模型预测冰淇淋消费时间序列数据|附代码数据
    全文下载链接:http://tecdat.cn/?p=22511最近我们被客户要求撰写关于ARIMAX的研究报告,包括一些图形和统计输出。标准的ARIMA(移动平均自回归模型)模型允许只根据预测变量的过去值进行预测。该模型假定一个变量的未来的值线性地取决于其过去的值,以及过去(随机)影响的值。ARIMAX模型......
  • R语言和Python用泊松过程扩展:霍克斯过程Hawkes Processes分析比特币交易数据订单到达
    全文下载链接:http://tecdat.cn/?p=25880 最近我们被客户要求撰写关于泊松过程的研究报告,包括一些图形和统计输出。本文描述了一个模型,该模型解释了交易的聚集到达,并展示了如何将其应用于比特币交易数据。这是很有趣的,原因很多。例如,对于交易来说,能够预测在短期内是否有更多的买......
  • Git 代码分支管理
    一、引言近日,IoT研发团队加入了不少新同学,对git分支的命名和管理方式有些许的模糊,分支的命名规范以及管理方式对项目的版本发布至关重要,为了解决实际开发过程中版本发布时代码管理混乱、冲突等比较头疼的问题,我们将在文中阐述如何更好的管理代码分支。二、总览从上图可以看......
  • SRGAN图像超分重建算法Python实现(含数据集代码)
    摘要:本文介绍深度学习的SRGAN图像超分重建算法,使用Python以及Pytorch框架实现,包含完整训练、测试代码,以及训练数据集文件。博文介绍图像超分算法的原理,包括生成对抗网络和SRGAN模型原理和实现的代码,同时结合具体内容进行解释说明,完整代码资源文件请转至文末的下载链接。完整......
  • 【WALT】scale_exec_time() 代码详解
    @目录【WALT】scale_exec_time()代码详解代码展示代码逻辑:为什么归一化?⑴ 将CPUcycles转换为CPU当前频率⑵ 归一化delta【WALT】scale_exec_time()代码详解代码版本:Linux4.9android-msm-crosshatch-4.9-android12代码展示staticinlineu64scale_exec_time(u64delt......
  • 嵌入式宝藏级别的C代码
    在嵌入式开发中,有一些常用的C语言代码片段被认为是宝藏级别的,因为它们在处理底层硬件和优化性能方面非常有用。以下是一些常见的宝藏级别的C语言代码和解释:1.位操作代码//设置某个位为1#defineSET_BIT(reg,bit)((reg)|=(1<<(bit)))//清除某个位为0#defineCLEAR_BIT(re......
  • poi-tl 将html代码渲染到word中
    引入依赖<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.15.3</version></dependency><dependency><groupId>io.github.draco1023</groupId>......