前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >重构—代码的坏味道(一)

重构—代码的坏味道(一)

作者头像
用户9914333
发布2022-07-21 19:39:55
3940
发布2022-07-21 19:39:55
举报
文章被收录于专栏:bug收集bug收集

1. Duplicated Code(重复的代码)

坏味行列中首当其冲的就是Duplicated Code。如果你在一个以上的地点看到相同的程序结构,那么当可肯定:设法将它们合而为一,程序会变得更好

最单纯的Duplicated Code就是[同一个class内的两个函数含有相同表达式(expression)]。这时候你需要做的就是采用ExtractMethod提炼出重复的代码,然后让这两个地点都调用被提炼出来的那一段代码。

2. Long Method(过长函数)

拥有[短函数](short methods)的对象会活得比较好、比较长。不熟悉面向对象技术的人,常常觉得对象程序中只有无穷无尽的delegation(委托),根本没有进行任何计算。和此类程序共同生活数年之后,你才会知道,这些小小函数有多大价值。[间接层]所能带来的全部利益——解释能力、共享能力、选择能力——都是由小型函数支持的。

很久以前程序员就已认识到:程序愈长愈难理解。早期的编程语言中,[子程序调用动作]需要额外开销,这使得做你们不太乐意使用small method,现代OO语言几乎已经完全免除了进程内的[函数调用动作额外开销]。不过代码阅读者还是得多费力气,因为他必须经常转换上下文去看看子程序做了什么。某些开发环境允许用户同时看到两个函数,这可以帮助你省去部分麻烦,但是让small method容易理解的真正关键在于一个好名字。如果你能给函数起个好名字,读者就可以通过名字了解函数的作用,根本不必去看其中写了些什么。

3. Large Class(过大类)

如果想利用单一class做太多事情,其内往往就会出现太多instance变量。一旦如此,Duplicated Code也就接踵而至了。

你可以运用Extract Class将数个变量一直提炼到新class内。提炼时应该选择class内彼此相关的变量,将它们放在一起。例如”depositAmount”和”depositCurrency”可能应该隶属同一个class。通常如果class内的数个变量有着相同的前缀或字尾,这就意味有机会把它们提炼到某个组件内。如果这个组件适合作为一个subclass,你会发现Extract Subclass往往比较简单。

4. Long Parameter List(过长参数列)

刚开始学习编程的时候,老师教我们:把函数所需的所有东西都以参数传递进去。这可以理解,因为除此之外就只能选择全局数据,而全局数据是邪恶的东西。对象技术改变了这一情况,因为如果你手上没有你所需要的东西,总可以叫另一个对象给你。因此,有了对象,你就不必把函数需要的所有东西都以参数传递给它了,你只需给它足够的东西、让函数能从中获得自己需要的所有东西就行了。函数需要的东西多半可以在函数的宿主类(host class)中找到。面向对象程序中的函数,其参数列通常比在传统程序中短得多。

这是好现象,因为太长的参数列难以理解,太多参数会造成前后不一致、不易使用,而且一旦你需要更多数据,就不得不修改它。如果将对象传递给函数,大多数修改都将没有必要,因为你很可能只需(在函数内)增加一两条请求,就能得到更多数据。

此间存在一个重要的例外。有时候你明显不希望造成[被调用之对象]与[较大对象]间的某种依存关系。这时候将数据从对象中拆解出来单独作为参数,也很合情合理。但是请注意其所引发的代价。如果参数列太长或变化太频繁,你就需要重新考虑自己的依存结构了。

5. Divergent Change(发散式变化)

我们希望软件能够更容易被修改——毕竟软件再怎么说本来就该是[软]的。一旦需要修改,我们希望能够跌到系统的某一点,只在该处做修改。如果不能做到这点,你就嗅出两种紧密相关的刺鼻味道中的一种了。

6. Shotgun Surgery(霰弹式修改)

Shotgun Surgery类似DivergentChange,但恰恰相反。如果每遇到某种变化,你都必须在许多不同的class内做出许多小修改以响应之,你所面临的坏味道就是Shotgun Surgery。如果需要修改的代码散布四处,你不但很难找到它们,也很容易忘记某个重要的修改

这种情况下你应该使用Move Method和Move Field把所有需要修改的代码放进同一个class。如果眼下没有合适的class可以安置这些代码,就创造一个。

7. Feature Envy(依恋情结)

最根本的原则是:将总是一起变化的东西放在一块儿[数据]和[引用这些数据]的行为总是一起变化的,但也有例外。如果例外出现,我们就搬移那些行为,保持[变化只在一起发生]。Strategy和Visitor使你得以轻松修改函数行为,因为它们将少量需要被覆写的行为隔离开来——当然也付出了[多一层间接性]的代价。

8. Data Clumps(数据泥团)

数据项就像小孩子:喜欢成群结队地待在一块儿。你常常可以在很多地方看到相同的三或四笔数据项:两个classes内的相同值域、许多函数签名式中的相同参数。这些[总是绑在一起出现的数据]真应该放进属于它们自己的对象中。首先请找出这些数据的值域形式出现点,运用ExtractClass将它们提炼到一个独立对象中。然后将注意力转移到函数签名式上头,运用Introduce Parameter Object或Preserve Whole Object为它减肥。这么做的直接好处是可以将很多参数列缩短,简化函数调用动作。是的,不必因为Data Clumps只用上新对象的一部分值域而在意,只要你以新对象取代两个(或更多)值域,你就值回票价了。

9. Primitive Obsession(基本类型偏执)

大多数编程环境都有两种数据:结构类型允许你将数据组织成有意义的形式;基本类型则是构成结构类型的积木块。结构总是会带来一定的额外开销。它们有点像数据库中的表格,如果只为做一两件事而创建结构类型,也显得太麻烦

对象的一个极大价值在于:它们模糊了横亘于基本数据和体积较大的classes之间的界限。你可以轻松编写出一些与语言内置类型无异的小型classes。例如Java就以基本型别表示数值,而以class表示字符串和日期——这两个型别在其它许多编程环境中都以基本型别表现。

10. Switch Statements(switch惊悚现身)

面向对象程序的一个最明显特征就是:少用switch(或case)语句。从本质上说,switch语句的问题在于重复。你常会发现同样的switch语句散布于不同的地点。如果要为它添加一个新的case子句,你必须找到所有switch语句并修改它们。面向的多态概念可为此带来优雅的解决办法。

如果你只是在单一函数中有些选择事例,而你并不想改动它们,那么[多态]就有点杀鸡用牛刀了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 bug收集 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档