《重构改善既有代码的设计》感想

      《重构改善既有代码的设计》 ,作者是Martin Fowler,被软件开发者称为“教父”,其建立的敏捷开发彻底改变了人类开发软件的模式,从传统的以文档为驱动的、笨重的软件开发模式转化为以核心需求为中心,”可以让汽车一边跑,一边换轮子“的敏捷开发模式,《重构》也被称为是软件开发的不朽经典,被誉为金字塔顶端的书,在分析重构原理和具体实践方式的同时,向程序员提供了一种优秀的编程习惯和编程态度。

 

1、什么是重构---what?

  • 重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。

  • 重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。

    一个任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员。重构,不仅仅是整理代码,更像是“擦掉窗户上的污垢,使你看得更远“。

 

2、为什么要重构---why?

  • 无法快速承接新的需求,在全新系统做两周的需求,在现有系统中需要1个月或者持平。

  • 代码中存在太多的”坏味道“,牵一发而动全身,只要发布新功能上线就会出问题。

  • 重构的意义在于将眼光放长远,而不仅限于当前暂时的提高开发效率。

  • 重构改进软件设计,使代码具有更强的可读性(一段时间后,自己可能会忘了自己之前写代码的逻辑,或是不久之后有其他程序员需要修改你的代码)

  • 提高代码的可扩展性(添加新功能,可以尽可能的不修改原有的代码,提高编程速度);

  • 降低复杂性(过于冗余的代码,很容易让人看的头昏脑涨);

     

3、如何进行重构---how?

  • 重构的基础---->可靠的测试环境,“小步快跑,快速验证”

  • 重构的分类:

    1)重新组织函数:

    很多时刻,代码中的”坏味道“来源于过长的类,包含太多信息,又被函数错综复杂的逻辑掩盖,不一鉴别。

    分类

    方法

    使用说明

     

     

     

     

    重新组织函数

     

     

    提炼函数:将一段代码放进一个独立的函数中,并用函数名称解释该函数的用途

    处理临时变量:

    1、消灭临时变量:分解临时变量(针对每次赋值,创造一个独立的临时变量)或者以查询取代临时变量(如果临时变量保存某一表达式的结果,将表达式提炼到独立函数中);

    2、临时变量难以替换:以函数对象取代函数(将函数放进单独的对象,在对象中分解小的函数)

    内联函数:函数的本体和名称同样清楚,在函数调用点插入函数本体,然后移除该函数

    对于递归调用等复杂情况,不建议使用该重构

    以函数对象取代函数(将函数放进一个单独的对象中,然后可以在同一个对象中将这个大型函数分解为多个小型函数)

    如果临时变量只被赋值一次,可先使用内联临时变量

    如果临时变量被赋值超过一次,先使用分解临时变量

    替换算法:将函数本体替换为另一个算法

     

     

    2)在对象之间搬移特性:

    ”决定把责任放在哪儿?“是对象设计过程中很重要的一件事。

    分类

    方法

    使用说明

     

     

    在对象之间搬移特性

    提炼类:某个类做了两个类做的事情,建立一个新类,将相关字段和函数从旧类搬移到新类

    对于每一个字段:搬移字段

    对于必要的函数:搬移函数

    将类内联化:某个类没有做太多事情

    隐藏委托关系:客户通过一个委托类来调用另一个对象,在服务类上建立客户所需的所有函数,用以隐藏委托关系

    与此相反,如果某个类做了太多的简单委托动作,需要让客户直接调用受委托类:移除中间人

     

    3)重新组织数据:

    处理数据的重构手法

    分类

    方法

    使用说明

     

     

     

     

    重新组织数据

    针对简单数据类型:

    以对象取代数据值(将数据项变成对象)
    将值对象改为引用对象(从一个类中衍生出许多彼此相等的实例,替换为同一个对象)

    将引用对象改为值对象(引用对象很小且不变,不易管理的情况下,变为一个值对象)

     

    使用过程中,常用到自封装字段,为字段建立取值/设值函数,并且只以这些函数来访问字段

    针对魔法数:以字面常量取代魔法数

    如果魔法数是类型码,使用以类取代类型码

    针对封装的数据:

    封装字段封装集合

    如果一个类公开了任何public的数据,应该使用封装将其包装起来,如果是集合,使用封装集合,如果是一整条记录,以数据类取代记录(类似于PO类)

    针对类型码:(与实例所属之类型相关的某些东西)

    以类取代类型码以子类取代类型码

    类型码不影响宿主类的行为,用类取代即可,但如果影响,需要借助以多态取代表达式来处理,在此之前,需要为每一种类型码建立一个子类;

    魔法数:拥有特殊意义,却又不能明确表现出这种意义的数字。

  • 4)简化条件表达式

    分类

    方法

    使用说明

     

     

    简化条件表达式

     

    分解条件表达式(从if、else中分别提炼出独立函数)

     

    如果存在嵌套的条件逻辑,可以使用以卫语句取代嵌套条件表表达式(标示出特殊情况后,以break或return语句取代控制标记)

    合并条件表达式(将有相同结果的条件表达式合并为一个)

    合并后可以使用提炼类来进行进一步重构

    以多态取代表达式(将条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明为抽象函数)

    使用之前,必须要继承结构,建立继承可以使用以子类取代类型码

    卫语句:如果某个条件极为罕见,就应该单独检查该条件,并在该条件为真时立刻从函数中返回,这样的检查称为”卫语句“。

     

  • 5)简化函数调用---接口

    分类

    方法

    使用说明

     

     

     

     

    简化函数调用

     

    更改函数声明:

    函数改名、添加参数、移除参数

    过程中可以使用保持对象完整来缩短参数列;

    如果不存在该参数,可以引入参数对象

    如果函数的参数来自该函数可获取的一个对象,可以以函数取代参数

    如果函数完全取决于参数值而采取不同行为,针对该参数的每一个可能值建立独立函数;(以明确函数取代参数)

    使用令函数携带参数来为数个相似函数添加参数,将它们合并在一起;

    构造函数:

    以工厂函数取代构造函数

    在派生子类的过程汇总以工厂函数取代类型码

    结构改进:

    将查询函数和修改函数分离

    移除设置函数、隐藏函数(private)

    对于既返回对象状态又返回对象状态值的函数分开;

    类中某个字段在对象创建时设置,将不再改变,去掉该字段的所有设置函数;

    处理异常:

    以异常取代错误码以测试取代异常

    受控异常--->可以建立一个合适的异常;非受控异常--->抛出

     

    6)处理继承关系

    分类

    方法

    使用说明

     

     

     

    处理继承关系

    移动:

    字段上移字段下移函数上移函数下移

    构造函数本体上移

    处理继承关系主要是字段及函数在继承体系之中移动,对于构造函数,如果在各子类中的构造函数本体几乎完全一致,可以构造函数本体上移,对于构造函数下移,可以使用以工厂函数取代构造函数

    建立新类:

    提炼超类、提炼子类、提炼接口、折叠继承体系

    使用过程中会涉及到移动,参见上一栏;如果有一些子类以相同的顺序执行类似的操作,可以塑造模板函数。

    修改继承为委托:

    以委托取代继承、以继承取代委托

    某个子类只是用超类接口中的一部分--->以委托取代继承

    需要使用受委托中的所有函数--->以继承取代委托

    需要使用受委托中的部分函数--->提炼超类或者移除中间人

     

    另外IntelliJ和Eclipse中也有重构菜单栏,里面包含了一些上面常用到的重构手法:

     

    7)大型重构:

分类

方法

使用说明

处理混乱的继承体系

梳理并分解继承体系(Tease Apart Inheritance)

某个继承体系同时承担两项责任:建立两个继承体系, 并通过委托关系让其中一个可以调用另一个。

处理过程式代码

将过程化设计转化为对象设计(Convert Procedural Design to Objects)

有一些传统过程化风格的代码:将数据记录变成对象, 将大块的行为分成小块, 并将行为移入相关对象中.

处理复杂的类

提炼继承体系(Extract Hierarchy)

某个类做了太多工作, 其中一部分工作是以大量条件表达式完成的:建立继承体系, 以一个子类表示一种特殊情况.

 

4、何时何地重构---when and where?

  • ”两顶帽子“理论:添加新功能、重构,时刻谨记所要做的事情是什么,不要边写代码边重构,带上写代码的帽子,觉得需要重构了,再带上重构的帽子去做,如此反复。

  • 三次法则:事不过三,三则重构。第一次做某件事情的时候只管去做,第二次做类似的事情的时候会产生反感,但无论如何还是可以去做,第三次再做类似的事,就应该重构。

    坏味道

    常用重构

    注意事项

    重复代码

    1、同一个类两个函数含有相同的表达式--->提炼函数

    2、两个互为兄弟的子类含有想同的表达式--->提炼函数,然后函数上移;如果只是相似,并非完全相同,可以先提炼函数,然后可以构造模板函数

    3、两个毫不相关的类--->提炼类

     

    过长函数

    1、大多数场合--->提炼类

    2、如果函数内有大量的参数和临时变量--->以查询取代临时变量消除临时变量;或引入参数对象保持对象完整简化过长的参数列;或以函数对象取代函数

    3、提炼条件表达式时候--->分解条件表达式

    1、遵循原则:每当感觉需要以注释来说明点什么的时候,就需要把说明的东西写到独立函数中,并以用途命名。

    2、注释、条件表达式、循环是提炼的信号;

    过大的类

    提炼类、提炼子类、提炼接口

     

    过长的参数列

    以函数取代参数保持对象完整引入参数对象

     

     

  • 把握重构节奏:何时开始、何时结束、何时前进、何时等待?

    1) 发现痛点果断重构。重构分大小,不要把重构想象成都是庞大、旷日持久的工程而不愿开始,每天甚至每个小时都可以完成一项小重构。

    2)”没有任何度量规矩比得上一个坚实广博者的直觉“,《重构》这本书只能帮助我们发现”这里有一个可以用重构解决的问题“,但决定何时开始重构、何时停止重构还需要培养自己的判断力,一个不断积累的过程。

     

  • 代码质量是系统稳定性的根基:

    1)意识:团队成员的共同责任,系统代码质量关系到每个人工作成果产出。如果代码质量不高,新功能也很难写出高质量的代码。

    2)能力:学习改进系统质量的方案。关键系统质量:可用性、可修改性、性能、安全、可测试性和易用性;学习系统架构设计。明确系统架构目标(高可用SLA、高扩展性AKF)和商业架构目标(低成本、高收益:系统生命周期长。多快好省:缩短上市时间、减少开发时间、重用现有元素)

    3) 行动:系统升级不断维护现有系统,根据业务不断修正和发现潜在的问题,保证系统质量,在关键新功能排期的时候,必须为现有系统改造流出必要的时间。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值