java feature envy_重构:改善既有代码的设计

重构改进软件设计

只为了短期目的或者在完全理解整体设计之前编写出来的代码,会导致程序逐渐失去自己的结构。这时如果没有重构,程序的设计会逐渐腐败变质,程序员愈来愈难通过阅读源码而理解原本设计。重构很像是在整理代码,你所做的就是让所有东西回到应该的位置上。代码结构的流失是累积性的。愈难看出代码所代表的设计意涵,就愈难保护其中设计,于是该设计就腐败得愈快。经常性的重构可以帮助代码维持自己该有的形态。

只为了短期目的或者在完全理解整体设计之前编写出来的代码,会导致程序逐渐失去自己的结构。这时如果没有重构,程序的设计会逐渐腐败变质,程序员愈来愈难通过阅读源码而理解原本设计。重构很像是在整理代码,你所做的就是让所有东西回到应该的位置上。代码结构的流失是累积性的。愈难看出代码所代表的设计意涵,就愈难保护其中设计,于是该设计就腐败得愈快。经常性的重构可以帮助代码维持自己该有的形态。

重构使软件更容易理解

所谓程序设计,很大程度上就是与计算机交谈:你编写代码告诉计算机做什么事,它的响应则是精确按照你的指示行动。你得及时填补“想要它做什么”和“告诉它做什么”之间的缝隙。这种编程模式的核心就是“准确说出我所要的”。除了计算机外,你的源码还有其他读者:几个月之后可能会有另一位程序员尝试读懂你的代码并做一些修改。我们很容易忘记这第二位读者,但他才是最重要的。计算机是否多花了几个小时来编译,又有什么关系呢?如果一个程序员花费一周时间来修改某段代码,那才关系重大—如果他理解你的代码,这个修改原本只需一小时。

所谓程序设计,很大程度上就是与计算机交谈:你编写代码告诉计算机做什么事,它的响应则是精确按照你的指示行动。你得及时填补“想要它做什么”和“告诉它做什么”之间的缝隙。这种编程模式的核心就是“准确说出我所要的”。除了计算机外,你的源码还有其他读者:几个月之后可能会有另一位程序员尝试读懂你的代码并做一些修改。我们很容易忘记这第二位读者,但他才是最重要的。计算机是否多花了几个小时来编译,又有什么关系呢?如果一个程序员花费一周时间来修改某段代码,那才关系重大—如果他理解你的代码,这个修改原本只需一小时。

重构帮助找到bug

对代码的理解,可以帮助我们找到bug。有些人只要盯着一大段代码就可以找出里面的bug,但大多数人不行。如果对代码进行重构,我们就可以深入理解代码的作为,并恰到好处地把新的理解反馈回去。搞清楚程序结构的同时,也清楚了自己所做的一些假设,从而更加容易把bug揪出来。

对代码的理解,可以帮助我们找到bug。有些人只要盯着一大段代码就可以找出里面的bug,但大多数人不行。如果对代码进行重构,我们就可以深入理解代码的作为,并恰到好处地把新的理解反馈回去。搞清楚程序结构的同时,也清楚了自己所做的一些假设,从而更加容易把bug揪出来。

重构提高编程速度

良好的设计是快速开发的根本──事实上,拥有良好设计才可能做到快速开发。如果没有良好设计,或许某一段时间内你的进展迅速,但恶劣的设计很快就让你的速度慢下来。你会把时间花在调试上面,难以或者甚至无法添加新功能,修改时间愈来愈长,扩展性与可维护性越来越差。因为你必须花愈来愈多的时间去理解系统、寻找重复代码。随着你给最初程序打上一个又一个的补丁,新特性需要更多代码才能实现,最终变成一个恶性循环。

良好的设计是快速开发的根本──事实上,拥有良好设计才可能做到快速开发。如果没有良好设计,或许某一段时间内你的进展迅速,但恶劣的设计很快就让你的速度慢下来。你会把时间花在调试上面,难以或者甚至无法添加新功能,修改时间愈来愈长,扩展性与可维护性越来越差。因为你必须花愈来愈多的时间去理解系统、寻找重复代码。随着你给最初程序打上一个又一个的补丁,新特性需要更多代码才能实现,最终变成一个恶性循环。

重构使单元测试成为可能

Android作为对单元测试最不友好的系统环境,大多数开发者在刚开始接触时都会直观地把和当前界面有关的所有逻辑都放在Activity或者Fragment等视图里面,造成View层与逻辑层甚至数据层深度耦合,而单元测试对View的测试非常乏力,也不值得花大量时间在这上面,同时因为逻辑的过度耦合,每一个类里面有非常多的私有依赖无法进行mock,从而无法达到尽可能全面测试的目的。但是单元测试可以测出整个测试流程中80%的bug,这是对代码质量的一个重大保障。

Android作为对单元测试最不友好的系统环境,大多数开发者在刚开始接触时都会直观地把和当前界面有关的所有逻辑都放在Activity或者Fragment等视图里面,造成View层与逻辑层甚至数据层深度耦合,而单元测试对View的测试非常乏力,也不值得花大量时间在这上面,同时因为逻辑的过度耦合,每一个类里面有非常多的私有依赖无法进行mock,从而无法达到尽可能全面测试的目的。但是单元测试可以测出整个测试流程中80%的bug,这是对代码质量的一个重大保障。

重构应该是开发人员的必备技术手段

一名开发人员的良好发展路线应该是由会写代码转为写好代码,也是从一名实现者到架构者的转变,甚至即使是单纯的实现者,也应该追求自己能写出越来越优雅和高效的代码。业务需求与技术需求不应该是对立面,技术需求最终也是服务于业务需求,更好的代码结构才能帮助项目更快速地开发。

一名开发人员的良好发展路线应该是由会写代码转为写好代码,也是从一名实现者到架构者的转变,甚至即使是单纯的实现者,也应该追求自己能写出越来越优雅和高效的代码。业务需求与技术需求不应该是对立面,技术需求最终也是服务于业务需求,更好的代码结构才能帮助项目更快速地开发。

重构不是一件应该特别拨出时间做的事情,重构应该随时随地进行。不应该为重构而重构,之所以重构,是因为我们想做别的什么事,而重构可以帮助我们把那些事做好。

添加功能时重构。

修补错误时重构。

复审代码时重构。

三次法则:事不过三,三则重构。

添加功能时重构。

修补错误时重构。

复审代码时重构。

三次法则:事不过三,三则重构。

代码根本无法工作或者太糟糕,重构还不如重写来的简单。

在项目的最后期限,应该避免重构。

代码的坏味道重复代码(Duplicated Code)

同一个类的两个函数还有相同的表达式,这时需要提炼出重复代码。

两个互为兄弟的子类内含有相同的表达式,可以提炼相同代码,并放到父类中。如果只是代码间相似,并非完全相同,那么可以将相似部分和差异部分拆开,构成单独的函数。然后你可以使用模板方法的设计模式。

如果两个毫不相关的类中出现重复代码,则可以将重复代码提炼成一个函数放到一个独立类中或者只放在某一个类中(总之要放在合适的地方),然后其他类都去调用这个函数。

同一个类的两个函数还有相同的表达式,这时需要提炼出重复代码。

两个互为兄弟的子类内含有相同的表达式,可以提炼相同代码,并放到父类中。如果只是代码间相似,并非完全相同,那么可以将相似部分和差异部分拆开,构成单独的函数。然后你可以使用模板方法的设计模式。

如果两个毫不相关的类中出现重复代码,则可以将重复代码提炼成一个函数放到一个独立类中或者只放在某一个类中(总之要放在合适的地方),然后其他类都去调用这个函数。

原则:每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名。哪怕替换后的函数调用动作比函数自身还长,只要函数名称能够解释其用途,我们也该毫不犹豫的那么做。关键不在于函数的长度,而在于函数“做什么”和“如何做”之间的语义距离。

过大的类(Large Class)

类内如果有太多代码,也是代码重复、混乱并最终走向死亡的源头。最简单的解决方案是把多余的东西消弭于类内部。如果有五个“百行函数”,它们之间很多代码都相同,那么或许你可以把它们编程五个“十行函数”和十个提炼出来的“双行函数”。

过长参数列(Long Parameter List)

有了对象,就不必把函数需要的所有东西都以参数传递给它了,只需传给它足够的、让函数能从中获得自己需要的东西就行了。函数需要的东西多半可以在函数宿主类中找到。如果将对象传递给函数,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值