重构——改进既有代码的筹划

重构——革新既有代码的设计
Refactoring——Improve the Design of Existing Code
作者: 马丁 富勒Martin Fowler

图片 1


晨起,心平如镜。留一点孤寂给自己,做自己喜欢的事,看自己喜爱的书,听自己喜爱的歌,静静地守候着时间,怀揣着时间的的轻叹在诗行里行动摇摆。

一、什么是重构?

所谓重构是这么一个过程在不改变代码外在表现的前提下,对代码作出修改,以千锤百炼程序的内部结构。本质上说,重构就是在代码写好之后革新它的宏图

重构(名词):对软件内部结构的一种调动,目标是在不更改软件可寓目行为的前提下,升高其可精通性,下落其修改花费
重构(动词):运用一密密麻麻重构手法,在不改动软件可观察行为的前提下,调整其社团

重构的目标是使软件更易于被清楚和修改。重构不会变动软件可旁观的一颦一笑——重构之后软件成效仍旧。

重构技术就是以微小的步子修改程序,若是您犯下错误,很简单便足以发现它。


新的一天又开头了。

二、为什么重构?

(1)
重构立异软件设计。即使没有重构,程序的陈设会逐渐堕落变质。重构很像是在重整代码,你所做的就是让拥有东西回到应出的职分上。常常性的重构可以接济维持友好该有的形制。

(2)重构使软件更便于驾驭。重构可以协理大家让代码更易读。

(3)重构协理找到bug。对代码进行重构,可以协理大家深入精晓代码,对代码领悟的越深,就越能帮大家找到bug。重构能够帮我们更使得地写出健康的代码。

(4)重构升高成为速度。重构可以襄助我们更快速地开发软件,因为它阻挡系统腐败变质,它如故仍能增加设计质量。


回溯来路,发现那条年轻的轨道已不可能甄别。咱们给这几个世界和投机留给的,原来并不可以用方便或特困来几乎概括。大家连年来不及反省,来不及演绎,甚至来不及后悔,就已匆匆走完了人生中的一程,走过了年轻最妖媚的一截。

三、哪一天重构?

重构不是一件理当越发拨出时间做的事务,重构应该随时随处举办。不应有为重构而重构,之所以重构,是因为大家想做其余怎样事,而重构可以支持我们把那一个事做好。

五回法则:事不过三,三则重构

(1)充裕职能时重构。
(2)修补错误时重构。
(3)复审代码时重构。


这恐怕是一种经济学,关于生命的农学。可是,我并不一连失望,因为自己自信我并不总是紧缺才智和胆略。我的心一直在跳动,热血始终在焚烧。

四、曾几何时不应当重构?

代码根本不可能工作或者太不佳,重构还不如重写来的简易

在项目的最后时限,应该防止重构


于是,我没有惊叹人生易逝,功名难求;从不老羞成怒,怨事尤人;我从不察观旁人的气色行事。洒脱又自在;自在又简便。

五、代码的坏味道

  • 重复代码(Duplicated Code)
  • 过长函数(Long Method)
  • 过大的类(Large Class)
  • 过长参数列(Long Parameter List)
  • 发散式变化(Divergent Change):一个类受各个转变的熏陶
  • 霰弹式修改(Shotgun Surgery):一种转移引发多个类对应修改
  • 留恋情结(Feature Envy):函数对某个类的趣味高过自己所处类的趣味
  • 数码泥团(Data
    Clumps):相同的若干项数据出现在不一致地点,那些绑在同步出现的多寡应该有属于它们自己的对象
  • 主导项目偏执(Private
    Obsession):很五个人不乐意在小职分上运用小指标
  • switch惊悚现身(Switch
    Statements):switch语句会在许多地点重复出现,一改则需全改
  • 平行继承连串(Parallel Inheritance
    Hierarchies):当你为某一个类增加子类时,也亟须为另一个类对应增添一个类
  • 冗赘类(Lazy Class):倘诺一个类不值得存在,那就让它毁灭
  • 说长道短的前景星(Speculative
    Generality):预留的不行的抽象类,无用的肤浅参数
  • 令人迷惑的临时字段(Temporary
    Field):类中某个字段只为某些特殊情形而设置
  • 过度耦合的新闻链(Message
    Chains):用户向一个对象请求另一个对象,然后再向后者请求另一个对象......
  • 中间人(Middle Man):无用的信托,过多的中间层
  • 性感关系(Inappropriate
    Intimacy):七个类过于亲近,一个类过于关切另一个类的积极分子
  • 如出一辙的类(Alternative Classes with Different
    Interfaces):差距名字的类或函数,笔者相同的事
  • 不周密的库类(Incomplete Library Class):类库设计不容许完美
  • 纯数据类(Data
    Class):一个类具有一些字段以及用于访问那么些字段的函数,除此之外别无长物
  • 被拒绝的遗赠(Refused
    Bequest):子类不想继承超类所有的函数和数码,只想挑几样来玩
  • 过多的注释(Comments)

前日一个学员满眼美溢着望着本人:老师,你纪念您说过一句卓殊出色的话吗?

六、构筑测试系统

  1. 重构的主要前提是独具一个可信的测试环境
  2. 假诺写好一点功力,就及时添加测试,并有限援救所有测试都统统自动化,让它们检查自己的测试结果。一套测试就是一个精锐的bug侦测器,能够大大缩减查找bug所急需的时日。
  3. 写作测试代码的最有效时机是在开首编程此前。当您须要添加特性的时候,先写相应测试代码。编写测试代码其实就是在问自己:添加那几个作用要求做些什么。编写测试代码仍能使你把注意力集中于接口而非完结。预先写好的测试代码也为您的行事设置一个斐然的收尾标志:一旦测试代码正常运转,工作就足以截至了。
  4. 多选取单元测试。测试你最操心失误的地方,考虑或者出错的边界条件。不要因为测试不可能捕捉所有bug就不写测试,因为测试的确可以捕捉到半数以上bug。“花合理时间抓出超过一半bug”要好过“穷尽毕生抓出富有bug”。

包蕴自己年龄大了,说过许多话,不明白您纪念的是哪一句?

七、重新组织函数

  1. 提炼函数(Extract
    Method)。你有一段代码可以被集团在一块并独立出来。将那段代码放进一个独门函数中,并将函数名称解释该函数的用处。
  2. 内联函数(Inline
    Method)。一个函数的本体与名称一致清楚易懂。在函数调用点插入函数本体,然后移除该函数。
  3. 内联临时变量(Inline
    Temp)。你有一个临时变量,只被一个简易表明式赋值两遍,而它妨碍了任何重构手法。将兼具对该变量的引用动作,替换为对它赋值的那几个表达式自身。
  4. 以询问取代临时变量(Replace Temp with
    Query)。你的程序以一个临时变量保存某一表明式的演算结果。将以此表达式提炼到一个独门函数中。将这几个临时变量的富有引用点替换为对新函数的调用。此后,新函数就可被其余函数使用。
  5. 引入解释性变量(Introduce Explaining
    Variable)。你有一个错综复杂的表达式。将该复杂表达式(或内部一部分)的结果放进一个临时变量,以此变量名称来诠释表达式用途。
  6. 释疑临时变量(Split Temporary
    Variable)。你的程序有某个临时变量被赋值过五次,它既不是循环变量,也不被用于采集计算结果。针对每一遍赋值,创制一个单身、对应的临时变量。
  7. 移除对参数的赋值(Remove Assignments
    Parameters)。代码对一个参数进行赋值。以一个暂时变量取代参数的岗位。
  8. 以函数对象取代函数(Replace Method with Method
    Object)。你有一个大型函数,其中对有些变量的应用使您无法利用Extract
    Method。将那些函数放进一个单身对象中,如此一来局地变量就成了目标内的字段。然后你能够在同一个对象中将那个特大型函数分解为两个袖珍函数。
  9. 替换算法(Substitute
    Algorithm)。你想要把某部算法替换为另一个更分明的算法。将函数本体替换为另一个算法。

“我的行事就是:等待花开的日子”

八、在对象之间搬移特性

  1. 搬移函数(Move
    Method)。你的先后中,有个函数与其所驻之外的另一个类举行越来越多互换:调用后者,或被后人调用。在该函数最常引用的类中创制一个怀有近乎行为的新函数。将旧函数变成一个只有的寄托函数,或是将旧函数完全移除。
  2. 搬移字段(Move
    Field)。你的顺序中,某个字段被其所驻类之外的另一个类更加多地用到。在目的类新建一个字段,修改源字段的兼具用户,令它们改用新字段。
  3. 提炼类(Extract
    Class)。某个类做了应该有多少个类做的事。建立一个新类,将有关的字段和函数从旧类搬移到新类。
  4. 将类内联化(Inline
    Class)。某个类没有做太多工作。将那个类的装有特性搬移到另一个类中,然后移除原类。
  5. 隐藏“委托关系”(Hide
    Delegate)。客户通过一个信托来调用另一个目的。在劳务类上创造客户所需的具备函数,用以隐藏委托关系。
  6. 移除中间人(Remove Middle
    Man)。某个类做了过多的粗略委托动作。让客户直接调用受托类。
  7. 引入外加函数(Introduce Foreign
    Method)。你须求为提供劳务的类伸张一个函数,但您无法修改这一个类。在客户类中树立一个函数,并以第一参数方式传播一个服务类实例。
  8. 引入本地扩充(Introduce Local
    Extension)。你需求为服务类提供一些外加函数,但你不能修改这些类。建立一个新类,使它含有这个额外函数。让那几个扩充品成为源类的子类或包装类。

全班同学都笑洋洋地望着自家……教室里荡漾着冰冷的太阳,我不由得笑起来了。

九、重新社团数量

  1. 自封装字段(Self Encapsulate
    菲尔德)。你直接访问一个字段,但与字段之间的耦合关系逐级变得愚钝。为那些字段建立取值/设值函数,并且只以这个函数来访问字段。
  2. 以目的取代数据值(Replace Data Value with
    Object)。你有一个多少项,要求与其余数据和表现一起行使才有含义。将数据项改成对象。
  3. 将值对象改为引用对象(Change Value to
    Reference)。你从一个类衍生出成千上万互为至极的实例,希望将它们替换为同一个目标。将以此值对象变成引用对象。
  4. 将引用对象改为值对象(Change Reference to
    Value)。你有一个引用对象,很小且不可变,而且不易管理。将它成为一个值对象。
  5. 以目的取代数据(Replace Array with
    Object)。你有一个数组,其中的要素分别代表差别的事物。以目标替换数组,对于数组中的每个元素,以一个字段来代表。
  6. 复制“被监视数据”(Duplicate Observed
    Data)。你有部分天地数据置身GUI控件中,而世界函数需求拜访这几个数据。将该多少复制到一个领域对象中。建立一个Observe情势,用以同步领域对象和GUI对象内的双重数据。
  7. 将单向关系改为双向关联(Change Unidirectional Association to
    Bidirectional)。四个类都急需接纳对方特性,但其中只有一条单向链接。添加一个反向指针,并使修改函数可以同时更新两条链接。
  8. 将双向关联改为单向关系(Change Bidirectional Association to
    Unidirectional)。五个类之间有双向关联,但里面一个类近日不再需求另一个类的风味。去除不须要的涉及。
  9. 以字面常量取代魔法数(Replace Magic Number with Symbolic
    Constant)。你有一个字面数值,带有尤其意义。创设一个常量,根据其意思为它定名,并将上述的字面数值替换为这一个常量。
  10. 封装字段(Encapsulate
    Field)。你的类中存在一个public字段。将它表明为private,并提供对应的走访函数。
  11. 包裹集合(Encapsulate
    Collection)。有个函数重临一个聚众。让这么些函数重临该集合的一个只读副本,并在这一个类中提供丰盛/移除集合元素的函数。
  12. 以数据类取代记录(Replace Record with Data
    Class)。你必要直面传统编程环境中的记录协会。为该记录创设一个“哑”数据对象。
  13. 以类取代类型码(Replace Type Code with
    Class)。类之中有一个数值类行码,但它并不影响类的表现。以一个新的类替换该数值类型码。
  14. 以子类取代类型码(Replace Type Code with
    Subclass)。你又一个不可变的类型码,它会影响类的行事。以子类取代这么些类型码。
  15. 以State/Strategy取代类型码(Replace Type Code with
    State/Strategy)。你有一个类型码,它会潜移默化类的行事,但你不可能通过两次三番手法消除它。以状态对象取代类型码。
  16. 以字段取代子类(Replace Subclass with
    菲尔德s)。你的顺序子类的绝无仅不一致只在“再次来到常量数据”的函数身上。修改这一个函数,使他么重返超类中的某个(新增)字段,然后销毁子类。

真是如此吗。

十、简化条件表明式

  1. 诠释条件表达式(Decompose
    Conditional)。你有一个繁杂的准绳(if-then-else)语句。从if、then、else三分段落中分别提炼出独立函数。
  2. 统一条件表明式(Consolidate Conditional
    Expression)。你有一三种标准测试,都赢得相同结果。将那个测试合并为一个口径表明式,并将这一个标准表明式提炼成为一个单独函数。
  3. 统一重复的准绳片段(Consolidate Duplicate Conditional
    Fragments)。在尺度表明式的每个分支上富有一样的一段代码。将那段重复的代码搬移到条件表达式之外。
  4. 移除控制标记(Remove Control
    Flag)。在一种类布尔表达式中,某个变量带有“控制标记”的职能。以break语句或return语句取代控制标记。
  5. 以卫语句取代嵌套条件表明式(Replace nested Conditional with
    Guard
    Clauses)。函数中的条件逻辑使人为难判定正常的实施路径。使用卫语句表现有所的奇特景况。
  6. 以多态取代条件表明式(Replace Conditional with
    Polymorphism)。你手上有个标准化表达式,它根据目的类型的例外接纳不一致的表现。将以此标准表达式的种种分支放进一个子类内的覆写函数中,然后将原始函数声明为架空函数。
  7. 引入Null对象(Introduce Null
    Object)。你必要反复检查某目的是还是不是为null。将null值替换为null对象。
  8. 引入断言(Introduce
    Assertion)。某一段代码必要对程序状态做出某种如若。以断言明确表现那种若是。

初中阶段是孩子毕生里延续小学送往高中的一段青葱年少的较为波折的路,在这一个等级随着课业的深化,和自我意识的日趋觉醒,渐渐有了整整要求自家做主的决断能力,也有局地孩子因为成长环境影响,原生家庭里样样的难题等等,孩子初步进入叛逆、区其余等级,工作中的琐碎,重复甚或混乱都会让导师自己乱了细微。那亟需多多大耐力和静守,等他们得手的度过梗起脖颈回首看到教授宽容的笑脸……那是用时间堆砌起来的爱和教导。过了过多年,回到校园来探视大家的,那几个调皮捣蛋的学习者众多,他们跟老师的熟络、默契、亲昵甚至你刚端起茶杯他会马上填满你的茶水,那是代表了稍稍略去的万语千言呀……由此,我跟她们说,我比其外人幸运,我的行事是:等待花开的生活,又性感又劳苦又美丽!

十一、简化函数调用

  1. 函数改名(Rename
    Method)。函数的称呼不可能揭露函数的用途。修改函数的称谓。
  2. 丰富参数(Add
    Parameter)。某个函数须求从调用端获得越来越多音信。为此函数添加一个目的参数,让该目的带进函数所需新闻。
  3. 移除参数(Remove
    Parameter)。函数本体不再须要某个参数。将该参数去除。
  4. 将查询函数和修改函数分离(Separate Query from
    Modifier)。某个函数既再次回到对象景况值,又修改对象景况。建立八个例外的函数,其中一个负担查询,另一个负责修改。
  5. 令函数带领参数(Parameterize
    Method)。若干函数做了看似的工作,但在函数本体中却富含了不相同的值。建立单一函数,以参数表明那多少个分歧的值。
  6. 以明确函数取代参数(Replace Parameter with Explicit
    Methods)。你有一个函数,其中完全在于参数值而选用不相同行为。针对该参数的每一个可能值,建立一个单身函数。
  7. 保险对象完整(Preserve Whole
    Object)。你从某个对象中取出若干值,将它们作为某三回函数调用时的参数。改为传送整个对象。
  8. 以函数取代参数(Replace Parameter with
    Methods)。对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数本身也可以调用前一个函数。让参数接受者去除该项参数,并间接调用前一个函数。
  9. 引入参数对象(Introduce Parameter
    Object)。某些参数总是很自然地同时出现。以一个对象取代这几个参数。
  10. 移除设值函数(Remove Setting
    Method)。类中的某个字段应该在目标创制时被设值,然后就不再改变。去掉该字段的有所设值函数。
  11. 隐藏函数(Hide
    Method)。有一个函数,一直没有被其它任何类用到。将以此函数修改为private。
  12. 以工厂函数取代构造函数(Replace Constructor with Factory
    Method)。你指望在创制对象时不仅是做不难的营造动作。将营造函数替换为工厂函数。
  13. 包装向下转型(Encapsulate
    Downcast)。某个函数重回的目的,须求由函数调用者执行向下转型。将向下转型动作移到函数中。
  14. 以老大取代错误码(Replace Error Code with
    Exception)。某个函数再次回到一个一定的代码,用以代表某种错误情况。改用十分。
  15. 以测试取代非常(Replace Exception with
    Test)。面对一个调用者能够先行检查的标准,你抛出了一个更加。修改调用者,使它在调用函数在此之前先做检查。

没悟出,他们那么享受这一句话!因了他的一句话,让自家那两日一直在回顾,回首这几十年的风风雨雨的行途,回首来路,就让一行行失去的脚印在大脑的深处复活,一幕幕青春的戏剧重演,一幅幅人生的山山水水再次出现,其实那就是本人的工本。

十二、处理蕴含关系

  1. 字段上移(Pull Up
    Field)。四个子类拥有相同的字段。将该字段移至超类。
  2. 函数上移(Pull Up
    Method)。有些函数,在逐个子类中暴发完全相同的结果。将该函数移至超类。
  3. 构造函数本体上移(Pull Up Constructor
    Body)。你在一一子类中具有一些构造函数,他们的本体大概完全一致。在超类中新建一个构造函数,并在子类构造函数中调用它。
  4. 函数下移(Push Down
    Method)。超类中的某个函数只与一些(而非全部)子类有关。将这几个函数移到有关的那个子类去。
  5. 字段下移(Push Down
    Field)。超类中的某个字段只被一些(而非全体)子类用到。将以此字段移到须要它的这个子类去。
  6. 提炼子类(Extract
    Subclass)。类中的某些特征只被某些(而非全体)实例用到。新建一个子类,将下面所说的那部分风味移到子类中。
  7. 提炼超类(Extract
    Superclass)。多个类有相似特性。为那八个类建立一个超类,将一律特性移至超类。
  8. 提炼接口(Extract
    Interface)。若干客户使用类接口中的同一子集,或者多少个类的接口有一些雷同。将同一的子集提炼到一个独自接口中。
  9. 折叠继承体系(Collapse
    Hierarchy)。超类和子类之间无太大差异。将它们合为一体。
  10. 培训模板函数(Form TemPlate
    Method)。你有局地子类,其中相应的一点函数以同一顺序执行类似的操作,但顺序操作的细节上具备分歧。将这么些操作分别放进独立函数中,并保险它们都有相同的签字,于是原函数也就变得千篇一律了。然后将原函数上移至超类。
  11. 以委托代表继承(Replace Inheritance with
    Delegation)。某个子类只利用超类接口中的一局地,或是根本不必要一连而来的多寡。在子类中新建一个字段用以保存超类;调整子类函数令它改而委托超类;然后去掉两者之间的继承关系。
  12. 以一而再取代委托(Replace Delegation with
    Inheritance)。你在七个类之间采纳委托关系,并寻常为所有接口编写许多极不难的寄托函数。让委托类来继承受托类。

忆起,已不再是惨痛楚灵的流浪。

十三、大型重构

  1. 梳理并分解继承种类(Tease Apart
    Inheritance)。某个继承种类同时背负两项权利。建立三个持续连串,并透过委托关系让其中一个方可调用另一个。
  2. 将进程化设计转化为对象设计(Convert Procedural Design to
    Objects)。你手上有一部分观念进度化风格的代码。将数据记录变成对象,将大块的一言一动分成小块,并将表现移入有关对象之中。
  3. 将世界和发挥/突显分离(Separate Domain from
    Presentation)。某些GUI类之中包涵了世界逻辑。将世界逻辑分离出来,为它们建立单独的天地类。
  4. 提炼继承连串(Extract
    Hierarchy)。你有某各项做了太多做事,其中有的办事是以大气准绳表明式完毕的。建立继续体系,以一个子类表示一种新鲜情状。

追忆,已不复是恒久败北的表象。

十四、经典句子

  1. Any fool can write code that a computer can understand. Good
    programmers write code that humans can understand.
    ——Martin
    Fowler

    其他一个傻子都能写出总计机可以领略的代码。只有写出人类简单明白的代码,才是突出的代码。
    ——马丁 Fowler
  2. I'm not a great programmer; I'm just a good programmer with
    great habits.
    ——Kent Beck
    自己不是个高大的程序员,我只是一个富有一些得天独厚习惯的好程序员。
    ——Kent Beck
  3. Computer Science is the discipline that believes all problems
    can be solved with one more layer of indirection.
    ——Dennis
    DeBruler

    统计机科学是那样一门科学:它相信所有难题都可以经过增加一个直接层来化解。——Dennis
    DeBruler

纪念,使我清楚了侧重;使自己感受了采暖;使自己精通了情味;是自己驾驭了追求的意思;使我想到了活着的真谛。

自身的感受:

  1. 读者最好有自然的花色经验,或者了然过一些代码风格、设计格局、代码设计教育学等。
  2. 那是一本以java语言来讲重构的书,读者最好懂面向对象的基本知识,精晓java、C++等面向对象的语言。
  3. 自身不是作java开发的,但是本人询问面向对象,精通C++,java。书中的一些理论和指点在任何安插语言上也有很大的扶持,并且我发现,在项目中本身此时就在动用着一些重构方法。书中那多少个过于结合面向对象的包裹、继承、多态等学问的重构方法,可能就只适用于面向对象的言语吧。
  4. **你值得一读。反复看,反复读。 **

追忆能使自己痛快地笑,痛快地哭,幽幽地叹气,寂寂地发呆。然后尽情的扬起笑靥,坚强的翘起口角,轻咬嘴唇,给自己一次次经验风雨洗礼的机会,找寻一朵朵属于自己的向阳花。

本身的文不对题:

  1. 被你们发现了,其实我也是一个程序员,仍旧低档程序员。
  2. 那本书据说是java进阶不可不看,也是程序员一定要看的经典图书。设计语言本身可能有分别,造成部分风味也会有分别,可是某些思想如故相通的。所有,非java、C++语言工作者,也迟早要读一下。
  3. 据称stack
    overflow.com上登出的一篇《哪一本书最具影响力,是各类程序员都应该读的?》。《重构》那本书就名次前十,貌似是第六名。

重构——改变既有代码的设计.jpg


ps:我的笔记只记录了理论部分,书上每种重构方法都配有实例代码来讲解,大家可以细细研究。

每一个后天都是财富,每一个前几日都是希望。我庆幸自己爱回首,我道谢我永久有希望的心,不去争辩或浓或淡。

回看逝去这几十年的每一天,照旧令自己那样痴迷。

转第三回望,真实的太阳照旧挂在天上,赏心悦目的彩云五彩而灿烂。

新一年温暖的青春又要过来了。

图片 2

相关文章

Comment ()
评论是一种美德,说点什么吧,否则我会恨你的。。。