前段时间读过martin fowler的《重构 ,改善既有代码的设计 》,不禁感叹:他老人家绝对对得起大师这个名号啊!对于入行不久的程序员来说,读这本书对提高代码质量肯定有帮助。就重构这个话题,还和部门同事做了次交流,将交流时的文档整理在此仅作备忘。
软件的成本
N 年前, Yourdon 和 Constantine 在 Structured Design 一书中将经济学作为了软件设计的底层驱动力,软件设计应该致力于减少整体成本。
COST total = COST develop + COST maintain
COST maintain = COST understand + COST change + COST test + COST deploy
软件的维护成本占了软件总成本的大部分,想要节约软件成本就要从软件的维护成本下手,而维护成本中理解老代码和修改老代码又占了绝大部分。可见,提高代码可理解性是多么重要,这时重构闪亮登场,为我们改善代码可读性提供了指导性的一些原则和手法。
什么是重构
看看 Martin Fowler的定义:
在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。重构是一种有纪律的、经过训练的、有条不紊的程序整理方法,可以将整理过程中不小心引入错误的机率降到最低。本质上说,重构就是在代码写好之后改进它的设计。
--Martin Fowler
重构 【 名词 】 :对软件内部结构的一种调整,目的是在不改变软件之可察行为 前提下,提高其可理解性,降低其修改成本 。
重构 【 动词 】 :使用一系列重构准则(手法),在不改变软件之可察行为 前提下,调整其结构。
关键的一点是重构离不开单元测试,测试驱动开发的模式。在已有单元测试的基础上进行代码重构,小步前进。
另外一个比较好的建议是 Kent Beck所说的 两顶帽子 :使用重构技术开发软件时,你把自己的时间分配给两种截然不同的行为 : 「添加新功能」和「重构」。
重构的好处
• 使软件更容易理解
• 帮你找到 bug
• 提高编程速度
重构时机
•三次法则
•添加新功能时
•Bugfix 时
•Code review 时
重构与设计
重构与设计并不是矛盾的,而是互为补充的:
•所有的设计都不可能做到滴水不漏,这个时候就需要重构来堵设计的漏洞;
•不能依赖重构而不重视重构。
重构与性能
重构和性能优化是不同维度的手法,重构的目的是提示程序的可理解性和可维护性,而优化则是侧重提升性能。重构为了提高代码可读性往往还会导致性能不是最优,考虑“二八原则”,如果这段代码不会显著导致程序性能严重下降,我们选择重构。
坏味道及应对重构手法
• 重复的代码
– 提炼函数,提炼类,上移函数,塑造模板函数
• 过长函数
– 提炼函数,查询取代临时变量,函数对象取代函数,分解条件表达式
• 过大类
– 提炼类,提炼子类,提炼接口,以对象取代数据值
• 过长参数列
– 函数取代参数,引入参数对象,保持对象完整
• 发散式变化
– 提炼类
• 散弹式修改
– 搬移函数,搬移值域,将类内联
• 依恋情结
– 搬移函数,搬移值域,提炼函数
• 数据泥团
– 提炼类,引入参数对象,保持对象完整
• 基本型别偏执
– 以对象取代数据值,提炼类,引入参数对象,以对象取代数组,以类取代型别码,以子类取代型别码,以 State/Strategy 取代型别码
• Switch 惊悚现身
– 多态取代嵌套条件表达式,以 State/Strategy 取代型别码,以明确函数取代参数
• 平行继承体系
– 搬移函数,搬移值域
• 冗余类
– 内联类,折叠继承体系
• 夸夸其谈未来性
– 折叠继承,将类内联,移除参数,重命名函数
• 令人迷惑的暂时值域
– 提炼类
• 过度耦合的消息链
– 隐藏委托
• 中间转手人
– 消除中间人,将函数内联,以委托取代继承
• 狎昵关系
– 搬移函数,搬移值域,改双向关联为单向,以继承取代委托,隐藏委托
• 异曲同工的类
– 重命名函数,搬移函数
• 不完美的类库
– 引入外加函数,引入本地扩展
• 单纯数据类
– 搬移函数,封装值域,封装集合
• 被拒绝的遗赠
– 以委托取代继承
• 过多的注释
– 提炼函数
重构法则分类
重新组织函数
•提炼函数
•将函数内联化
•将临时变量内联化
•以查询取代临时变量
•引入解释性变量
•剖解临时变量
•移除对参数的赋值操作
•以函数对象取代函数
•替换算法
在对象间搬移特性
•
•搬移函数
•搬移值域
•提炼类
•将类内联化
•隐藏委托关系
•移除中间人
•引入外加函数
•引入本地扩展
重新组织数据
•自封装值域
•以对象取代数据值
•将实值对象改为引用对象
•将引用对象改为实值对象
•以对象取代数组
•将单向关联改为双向
•将双向关联改为单向
•以符号常量或字面常量取代魔法数
•封装值域
•封装集合
•以数据类取代记录
•以类取代型别码
•以子类取代型别码
•以 State/Strategy 取代型别码
•以值域取代子类
简化条件表达式
•
• 分解条件表达式
• 合并条件表达式
• 合并重复的条件判断
• 移除控制标记
•以卫语句取代嵌套条件式
• 以多态取代条件式
简化函数调用
•重新命名
•重新命名函数
•查询和修改分离
•以明确函数取代参数
•保持对象完整 •以函数取代参数
•引入参数对象
•以工厂函数取代构造函数
•以异常取代错误码
• 将查询函数和修改函数分离
处理概括关系
•值域上移
•函数上移
•函数下移
•值域下移
•构造函数本体上移
•提炼子类
•提炼超类
•折叠继承体系
•塑造模板函数
•以委托取代继承
•以继承取代委托
最后,附上ppt。[/size][/size]