代码重构

一、为什么要代码重构(Refactoring)

在不改变系统功能的情况下,改变系统的实现方式。为什么要这么做?投入精力不用来满足客户关心的需求,而是仅仅改变了软件的实现方式,这是否是在浪费客户的投资呢?

代码重构的重要性要从软件的生命周期说起。软件不同与普通的产品,他是一种智力产品,没有具体的物理形态。一个软件不可能发生物理损耗,界面上的按钮永远不会因为按动次数太多而发生接触不良。那么为什么一个软件制造出来以后,却不能永远使用下去呢?

对软件的生命造成威胁的因素只有一个:需求的变更。一个软件总是为解决某种特定的需求而产生,时代在发展,客户的业务也在发生变化。有的需求相对稳定一些,有的需求变化的比较剧烈,还有的需求已经消失了,或者转化成了别的需求。在这种情况下,软件必须相应的改变。

考虑到成本和时间等因素,当然不是所有的需求变化都要在软件系统中实现。但是总的说来,软件要适应需求的变化,以保持自己的生命力。

这就产生了一种糟糕的现象:软件产品最初制造出来,是经过精心的设计,具有良好架构的。但是随着时间的发展、需求的变化,必须不断的修改原有的功能、追加新的功能,还免不了有一些缺陷需要修改。为了实现变更,不可避免的要违反最初的设计构架。经过一段时间以后,软件的架构就千疮百孔了。bug越来越多,越来越难维护,新的需求越来越难实现,软件的构架对新的需求渐渐的失去支持能力,而是成为一种制约。最后新需求的开发成本会超过开发一个新的软件的成本,这就是这个软件系统的生命走到尽头的时候。

代码重构就能够最大限度的避免这样一种现象。系统发展到一定阶段后,使用重构的方式,不改变系统的外部功能,只对内部的结构进行重新的整理。通过重构,不断的调整系统的结构,使系统对于需求的变更始终具有较强的适应能力。

二、通过代码重构可以达到以下的目标
2.1 持续偏纠和改进软件设计

重构和设计是相辅相成的,它和设计彼此互补。有了重构,你仍然必须做预先的设计,但是不必是最优的设计,只需要一个合理的解决方案就够了,如果没有重构、程序设计会逐渐腐败变质,愈来愈像断线的风筝,脱缰的野马无法控制。重构其实就是整理代码,让所有带着发散倾向的代码回归本位。

2.2 使代码更易为人所理解

软件的生命周期往往需要多批程序员来维护,我们往往忽略了这些后来人。为了使代码容易被他人理解,需要在实现软件功能时做许多额外的事件,如清晰的排版布局,简明扼要的注释,其中命名也是一个重要的方面。一个很好的办法就是采用暗喻命名,即以对象实现的功能的依据,用形象化或拟人化的手法进行命名,一个很好的态度就是将每个代码元素像新生儿一样命名,也许笔者有点命名偏执狂的倾向,如能荣此雅号,将深以此为幸。

对于那些让人充满迷茫感甚至误导性的命名,需要果决地、大刀阔斧地整容,永远不要手下留情!

2.3 帮助发现隐藏的代码缺陷

重构代码时逼迫你加深理解原先所写的代码。笔者常有写下程序后,却发生对自己的程序逻辑不甚理解的情景,曾为此惊悚过,后来发现这种症状居然是许多程序员常患的"感冒"。当你也发生这样的情形时,通过重构代码可以加深对原设计的理解,发现其中的问题和隐患,构建出更好的代码。

2.4 从长远来看,有助于提高编程效率

当你发现解决一个问题变得异常复杂时,往往不是问题本身造成的,而是你用错了方法,拙劣的设计往往导致臃肿的编码。

改善设计、提高可读性、减少缺陷都是为了稳住阵脚。良好的设计是成功的一半,停下来通过重构改进设计,或许会在当前减缓速度,但它带来的后发优势却是不可低估的。

三、哪些情况需要考虑代码重构

3.1 臃肿的类

类之所以会臃肿,是因为开发者缺乏对最基本的编码原则,即“单一职责原则”(SRP)的理解。这些类往往会变得很臃肿,是由于不同的且在功能上缺少关联的方法都放在了相同的类里面。

3.2 长方法

方法之所以会变得很长主要是有以下几个原因:

  • 1: 许多没有关联性的、功能复杂的模块的代码都放在相同的方法内。这主要是开发者缺乏SRP的概念
  • 2: 多种条件都放在同一个方法内,这在长方法内经常会发生的。这是由于缺乏McCabe代码复杂度和SRP的概念的比较。
3.3 大量的传参

我经常遇到这几种情况,一些方法跟另一些方法进行交互,或者调用另一些方法的时候传入大量的参数。这就会出现如果更改了其中一个参数,就得在多个方法内进行更改。

3.4 常量值无处不在

经常会发现开发者(尤其是新手)会使用一些具有明确含义的常量值(主要是魔鬼数字),但没有给它们赋予合适的常量变量。这会降低代码的可读性和可理解性。

3.5 模糊的方法名

许多时候,以下取的方法名会影响代码的可读性和可理解性:

  • 1: 模糊的不具有任何意义的方法名
  • 2: 技术性的,却没有提及相关领域的名称

四、重构的方法

4.1 提取类/抽离方法

正如上面提到的,像“臃肿的类”(一个类提供了本该有几个类提供的功能)这种代码异味应该将原有类中的方法和属性移动到适当数目的新类中去。旧类中对应新类的方法和属性应该被移除。另外,有时候一些类过于臃肿是因为它包含了被其他类使用本应该是其他类的成员方法的成员方法。这些方法也应该被迁移到合适的类中。

4.2 提取方法

像上面提到的“过长的方法”这种代码异味可以通过从旧方法中提取代码到一个或多个新方法中消除。

4.3 分离条件

许多时候,一个方法很长是因为包含好几个分支语句(if-else)。这些分支条件可以被提取和移动到几个单独的方法中。这确实能大大改善代码可读性和可理解性。

4.4 引入参数对象/保留全局对象

在我做代码审查时发现另外一个很常见的情况 - 好几个参数被传入方法。问题主要与需要从已有方法中增加或者移除一个方法参数有关。在这种场景,建议将相关方法参数组成一个对象(引入参数对象),让方法传递这些对象而不是每个单独的参数。

4.5 用符号常量替换魔法数字

对于有意义的并且到处被使用的字面常量,应该为它们分配一个命名常量。这能大大增强代码可读性和可理解性。

4.6 重命名方法

正如上面提到的,模糊不清的方法名会影响代码的可使用性。这些模糊不清的名称应该重命名为有意义的可能与业务术语有关的名称,来帮助开发者通过业务上下文更好地理解代码。这很需要技巧并且要求开发者与业务专家一起协作来理清代码需要满足的业务需求。有趣的是,这种重构方法看起来似乎非常容易理解,但是常常被许多开发者忽视,虽然在Eclipse这种IDE的refactor菜单项中经常出现这一项。

五、当重构没有现成的明显的方向时,我们可以遵循下面的原则

1、当属性、方法或类存在任何的需要复用的意向时,归纳提炼它们。

2、不要低估小方法对代码整洁的作用。使用小方法能让你节省很多笔墨。

3、用封装控制可见度。

4、消除依赖。

5、简化构造方法——即使这样做会使代码变复杂。

6、不确定时,将计算操作移入到这些数据的所有者对象里,或将数据移动到执行计算操作的对象里(也就是迪米特法则(Law of Demeter))。

7、使用小对象,松耦合,避免大对象,高聚合。

8、使用代理对象,模拟对象和辅助对象来隔离网络,数据库,文件和用户接口。

9、不确定时,尽量在model里添加代码,必要时才往controler添加代码。view里添加的都应该是便捷功能和简写方法,但不要局限于此。

代码重构

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容

  • 代码重构简介:(英语:Code refactoring)重构就是在不改变软件系统外部行为的前提下,改善它的内部结构...
    TaiXiang阅读 2,936评论 0 2
  • 阅读《重构》的笔记献上。 重构的定义 重构是在不改变软件可观察行为的前提下改善其内部结构。 重构的节奏 以微小的步...
    陈宇明阅读 11,616评论 13 64
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,520评论 25 707
  • 写在文前:大部分程序员都能写出计算机可以理解的代码,唯有优秀的程序员才能写出让人容易理解的代码 最近几个月被分配了...
    niknowzcd阅读 1,988评论 8 5
  • 夜未安阅读 181评论 0 1