[读书笔记]代码的坏味道---何时重构

这是一本好书,<重构--改善既有代码的设计>。除了重构,它也讲述了怎样构建更易于理解、维护的代码。

当闻到坏味道,就可以考虑重构那些让你不舒服的代码了。这并没有精确的概念,然而由各种迹象带来的直觉,往往就是在提示你需要做些事情了。


一,重复代码。(Duplicated Code)


随处复杂粘贴代码并不是一个好习惯。当我们需要一个功能,去搜索引擎、论坛、或其它项目找到我们需要的代码时,最好组织一下再使用,而不是直接copy到项目中。
如果你在多个地方看见相同的一段代码,就应该合二为一。
常见的情况:
同一个类的两个函数拥有相同的表达式。对策:提炼出重复的代码到新的函数,然后让这两个函数调用新的函数。(Exract Method)
两个兄弟子类含有相同的表达式。对策:将重复的代码提炼到新的函数,再讲新的函数放在父类中。
两个不相关的类出现重复代码。对策:视具体情况而定。你必须决定新提炼的函数放在哪里合适,然后确保他们不会再其他地方出现。

二,过长函数。(Long Method)


你应该更积极的分解长函数。
程序越长越南理解。现在的OO语言几乎完全免除了进程内的函数调用开销,你不用太担心性能问题。
使用间接层来设计----带来更好的解释能力、共享能力、选择能力。请尽量使用小型函数。
每当感觉需要用注释来说明下面的代码功能,就把需要说明的代码放在一个独立函数中,并以其用途而非实现手法命名。
所以可以通过寻找注释,来提醒你可以提炼新函数的代码。
条件、循环表达式常常也是需要提炼的信号。

三,过大的类。(Large Class)


不要用单个类做太多事情。否则可能会出现太多的实例变量,然后会导致各种重复代码。
常见的情况:
变量过多。对策:将几个相关的变量放在一个新类中,他们常常使用相同的前缀或后缀。
代码太多。对策:提炼重复代码到新的函数。可以先确定客户端如何使用这些代码,然后为每一种使用方式提炼出一个借口。
GUI类。对策:Duplicated Observied Data.

四,过长的参数列表。(Long Parameter List)


面向过程的语言常常可以见到一长串的参数列表。
你应该讲这些参数组织到一个对象中,然后传给函数。
对策:给这些函数传递对象。从宿主类或参数对象获取需要的数据。

五,发散式变化。(Divergent Change)


如果新增某种功能,但你需要修改多个函数,或许就意味着发散式变化出现了。
针对某一外界变化的所有相应修改,都只应该发送在单一类中。

六,霰弹式修改。(Shotgun Surgery)


如果遇到某种变化,必须在多个类内做出许多小修改,这就是霰弹式修改,这样就很难找到它们,也容易忘记某个重要的修改。
也许可以使用Move Method和Move Field把所有需要修改的代码放进同一个类。通常可以用Inline Class把一系列相关行为放在同一个类。
七,依恋情节 (Feature Envy)
常见的情况:函数对某个类的兴趣高过对自己所处类的兴趣。这时就应该把它移到该去的地方。如果函数中只有一部分是这样,应该先用Extract Method,然后再移动它。

八,数据泥团(Data Clumps)


也许你经常看到相同的几项数据:两个类中相同的字段、多个函数中相同的参数。

应该将这些一起出现的字段,放到一个独立对象中。


九,基本类型偏执。(Primitive Obsession)


将一串相关的基本类型属性组合成一个对象。不要有使用基本类型的偏执情绪。
如果有一组应该总是放在一起的字段,可以用Extract Class 。
如果在参数列表中看到基本类型,可以试试Introduce Parameter Object 。
如果发现自己正从数组中挑选数据,可以运用Replace Array With Object 。

总之,记住,这是一个对象的世界。


十,switch惊悚现身(Switch Statement)
少用switch case.尝试用多态来替代.
如果只是在单一函数中有些选择事例,而且并不想改动它们,可以用个Relpace Parameter with Explicit Method。如果选择条件之一是null,可以用Introduce Null Object 。

十一,平行继承体系(Parallel Inheritance Hierarchies)

每当你为某个类增加一个子类,必须也要为另一个类相应增加一个子类。如果你发现某个继承体系的类名称前缀与另一个继承体系的类名称前缀完全相同,便是闻到了这种坏味道。
对策:引用另一个实例就好了,然后用Move Method和Move Field,就可以避免平行继承体系.

十二,冗赘类(Lazy Class)

每一个类都应该有价值,理解、维护,都是需要成本的。如果某个类实际价值已经不大了,就放弃吧。


十三,夸夸其谈未来性(Speculative Generality)

有用的就去做,没有用的就搬开。


十四,令人迷糊的暂时字段(Temporary Field)


在变量未被使用的情况下猜测当初其设置目的,会让你发疯的。

使用函数对象。


十五,过度耦合的消息链(Message Chains)


使用Hide Delegate 。


十六,中间人(Middle Man)


过度使用委托,请使用Remove Middle Man ,直接与真正的对象打交道。


十七,狎昵关系(Inappropriate Intimacy)


避免两个类过分探究彼此的private部分。


十八,异曲同工的类(Alternative Classes with Different Interfaces)


如果两个函数做同样的事,但有着不同的签名,请根据用途rename。

但这往往还不够,可能需要反复Move Method。


十九,不完美的类库(Incomplete Library Class)


仅修改类库的一两个函数,可以运用Introduce Foreign Method 。
如果要添加一大堆额外行为,得用Introduce Local Extension 。

二十,纯稚的数据类(Data Class)


他们除了get/set,再无一技之长。他们是不会说话的数据容器,几乎一定被其他类过分细琐的操控着。

如果他们持有容器,请对容器进行合适的封装,不要直接返回容器的引用给外界。


二十一,被拒绝的馈赠(Refused Bequest)


如果子类复用了父类的行为/实现,又不愿意支持父类的接口------请用代理替代继承。


二十二,过多注释(Comments)


如果有些注释的存在,只是为了解释一段又臭又长的代码----请尝试重构,试着让所有注释都变得多余。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值