Posted by Yinode Blog on Monday, January 1, 0001

TOC

refactoring

快速回忆,不追求细节,一句话表达意图

坏味道

神秘命名

好的命名很难,多想多重构

重复代码

多提炼

过长函数

过长参数列表

全局数据

可变数据

发散变化

程序的变化应该集中,要修改的时候应该尽可能少的触碰其他代码

散弹修改

改起来到处都是细小的更改点

依恋情节

模块过于亲密

数据泥团

总是成群结队的三两个数据,尝试把数据改成对象

基本类型偏执

尽量自己构建一些基本类型,不要天天用字符串和number

重复的switch

要是增加一个可选项,直接爆炸

循环语句

少用循环多Map

夸夸其谈通用性

过于离谱的通用型设计

临时字段

特例情况的字段要干掉

过长的消息链

猛委托谁顶得住呢?隐藏起来吧,对外不暴露委托对象

中间人

一半的函数都委托给别人,可以考虑直接暴露委托,或者把委托对象直接进行应用

内幕交易

两个模块过于高频率的交换数据

过大的类

多抽离

异曲同工的类

相似的类接口最好一致

纯数据类

只拥有数据的类一般都会过渡耦合,最好是尝试把一些操作函数搬移到数据类里

被拒绝的遗增

父类的某些东西子类不想要,需要对继承体系进行重构

注释

让注释变得更有意义

基本手法

提炼函数

写颗粒度足够细的函数,可以消除注释

提炼变量

将长表达式内部的子表达式抽离成解释性变量

封装变量

针对全局数据建立get set函数 更好的控制访问

引入参数对象

将常见的参数组合成一个对象或者结构,比如 iOS中的 CGFloat CGRect CGPoint 通常都是含有 x y 等值

函数组合成类

如果一组函数+一组变量高频率的出现,抽离成一个类

拆分阶段

将一个函数拆分成多个阶段,并建立起 第一阶段的输出是第二阶段的输入这一过程。可以建立一个中转数据结构

封装

封装其实就是让程序的某一个子模块尽可能少的了解程序的其他部分

封装记录

将基本的记录结构(Map/Set etc)转换成更加具有解释性意义的类,让这种结构更加直观

封装集合

对某个类内部集合的操作进一步细化,一方面要让内部集合不可以直接被修改。一方面提供更加语义化的修改API

用对象取代基本类型

把常用类型转换成更加强大的结构

比如说手机号,优先级,地区,可以扩展函数来增加各种相关功能

用查询取代临时变量

利用计算属性或者方法等功能,消除临时变量。

提炼类

当一个类中的逻辑越来越复杂,责任不够单一,尝试抽离出一个与之配合的类。

拥有反向重构 内联内。具体看类内部的责任分配

隐藏委托关系

通过隐藏某个类内部的委托对象,来尽可能减少类内部实现的暴露。

如果内部需要委托的部分太多,需要反向重构 移除中间人

替换算法

在没有明显性能要求的情况下,尽可能用更简单,简短,自解释的算法来达成目的。

搬移函数

根据函数的通用性,上下文访问情况,将函数搬移到更合适的位置

越亲密的东西应该越放在一起

搬移字段

将数据结构移动到更合适的类中,让数据更加唯一,更加贴合类的职责

搬移语句到函数

将一些语句放到某个函数中,从而消除重复,让函数更整体

反向重构为搬移语句到调用者。适合边界开始模糊的情况

用函数调用取代内联代码

尽可能多利用已有的函数,比如List 提供 contain findIndex

避免更加基础的循环等语句

移动语句

将关联的语句放在一起 声明变量语句可以放到靠近使用的地方

拆分循环

一个循环只做一件事

用管道取代循环

尽可能的利用map filter some every 这样的函数,简洁富有表达力

移除死代码

删就完事了,用不到的都得删

重新组织数据

拆分变量

一个变量应该只承担一个责任,如果出现重复,那么拆分成多个变量

字段改名

不赘述

用查询取代派生变量

如果某个变量是通过一些基本变量结合计算而来,那么把这个变量变成一个计算属性。 可以避免复杂的维护

将引用对象改成值对象

通过改成值对象来加强数据不可变性,前提是不需要进行共享

将值对象改成引用对象

多实例内部共享同一个引用对象,可以利用对象仓库实现

简化条件逻辑

分解条件分支语句

将条件语句到每个部分进行函数提炼

合并条件表达式

条件不同,最终行为相同 ,那么可以考虑合并条件,或者进一步使用函数提炼

前提是 a b c 两者条件是有关联的

使用卫语句取代嵌套条件表达式

如果是If语句包涵优先级关系,比如一些提前退出,异常情况,特殊情况, 对于这些相对少见的情况,应该使用卫语句

利用多态改写条件语句

用多态承载不同的行为,把不同的行为封装到不同的子类中去,调用同一类接口

同样可以使用多态来抽离一些类似的类,不一样非得通常意义上的继承,也可以是比较抽象的继承

引入特例对象

把对特殊对象(比如空对象,错误对象)的操作都放到一个特例类中,从而消除各种处理语句

重构API

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

明确函数的副作用,将函数的修改部分和查询部分分离,强调每个有返回值的函数都不应该有返回值

函数参数化

将一组相似的函数,通过增加参数的方式进行合并

保持对象完整

避免把对象里面的值析构出来,又重新组装的情况。

用查询取代参数

将查询逻辑内嵌到函数中去,纯函数可以不用

反向重构为用参数取代查询

这里的关键是你是否希望参数耦合,如果不喜欢,那么拆分参数,如果可以接受,那么可以全部用查询

移除设值函数

明确其不可变性

用工厂函数取代构造函数

用更加灵活多样的工程函数来创建对象

用命令取代函数

面对过于复杂的函数,可以建立一个命令对象,拆分其内部的逻辑

反向重构为用函数取代命令,边界在于函数的复杂度

处理继承关系

函数上移

如果子类里面的函数重复,那么移动到父类

有反向重构函数下移

适用于只有一部分子类需要这个函数

字段上移

相同

也有反向重构字段下移

构造函数本体上移

可以移动一部分的构造函数 移动到父类 比如初始化某个字段

用子类取代类型码

如果某个类型的特定处理逻辑太多,抽子类可以用多态消除这些条件逻辑

有方向重构移除子类,原因大多是子类过于单薄

提炼超类

如果两个类过于相似,那么可以尝试提炼,通常是组合运用上移手法

折叠继承体系

如果子类和超类过于相似,那么可以合并成一个

用委托取代子类

组合比继承更轻量,不容易出错,可以建立一个委托类,委托类可以承载与父类不同的逻辑

用委托取代父类

将一些共享的逻辑抽离成一个委托对象,作为变量持有,如果喜欢同类型共享,可以考虑使用引用方式改写,也就是值对象转换成引用对象。