重构:改善既有代码的设计总结 from xichaodong

重构:改善既有代码的设计总结

常用函数
1.提炼函数:大函数提炼成语义清晰的小函数
2.内联函数:过度拆分的小函数合并到大函数中(1的反向重构)
3.提炼变量:当表达式过长时,可以将其拆分成多个临时变量,最后由临时变量组合成表达式,借此表达清晰语义
4.内联变量:当表达式或者临时变量较为简单且能够表达比变量名更清晰的语义时,可以去掉临时变量,将表达式直接放到需要使用临时变量的地方(3的反向重构)
5.改变函数声明:对于函数签名需要语义明确、保证高内聚和低耦合,函数名称需要表达清晰的语义,对于会经常改变的参数列表,需要用类封装参数列表,对于经常复用的函数,尽量使用较少的属性作为参数列表降低耦合程度。
在进行函数签名的改版时,尽量使用IDE的重构功能或手动迁移式的进行,避免直接改动原有函数签名
6.封装变量:如果变量的作用域不止限于本身所在的类时,可以将对变量的直接访问换为封装函数来便于后续的扩展和复用,常见的比如贫血模型中的get/set函数
7.变量改名:变量的名字需要语义清晰表达出所代表的含义,参考spring的命名方式
8.引入参数对象:将参数列表中的某些参数封装成一个类来缩短参数列表和衍生对应的功能类,并且在之后需要加相关参数时也能避免参数列表的变动
9.函数组合成类:当一组函数总是围绕着同一块数据进行操作时,可以将这些函数和数据封装成类,便于函数调用和后续扩展
10.函数组合成变换:类似函数组合成类,当有多处地方需要一块数据计算各种派生信息时,可以将这些计算收拢到一处,然后利用map等结构统一返回出去
11.拆分阶段:当函数不符合单一职责时,需要将其拆分成多个函数,中间的变量使用临时类承接

封装
1.封装记录:对于记录型结构比如map的读取和写入,因为其本身对字段不敏感,建议封装具体的函数或者类对其进行操作,这种手法在建造者模式中常见
2.封装集合:对于集合的增删改查最好建立对应的api,保证对集合数据的封装性,额外要注意的是读接口要返回只读的数据,避免客户端调用时修改引用造成数据不一致的问题
3.以对象取代基本类型:当一个属性的作用不只停留于打印时,最好封装成类,避免之后重复为其编写逻辑
4.以查询取代临时变量:如果一个临时变量每次计算得到的结果都相同的话,可以将其单独拆分到一个函数里,然后配合内联函数的函数将其消去
5.提炼类:当类不符合单一职责时,需要进行拆分
6.内联类:当一个类不足以单独承担职责时,需要和其他的类进行合并(5的反向重构)
7.隐藏委托关系:当存在链式调用时,即需要先通过当前对象获取另一个对象,然后再调用另一个对象的函数时,此时建议通过函数对调用链进行封装
8.移除中间人:7的反向重构,当委托类的函数过多时,我们需要为了隐藏委托关系而创建大量函数,这时候应该去掉封装直接使用链式调用
9.替换算法:当存在比当前函数写法更为简单而且能达到相同目的的函数时,将整个函数都替换掉

搬移特性
1.搬移函数:如果处于一个作用域(类)的函数频繁调用另一个作用域(类)的函数的话,需要考虑是不是函数的职责划分不对,需要将函数换个位置
2.搬移属性:当调用某些函数时发现不仅需要传入一个对象中的属性,还需要传入另一个对象的属性,此时需要考虑是不是字段的划分不正确
3.搬移语句到函数:如果在调用一个函数的多个位置有相同代码的话,应该把这些代码封进函数内部
4.搬移语句到调用者:随着系统的演进,封装在函数中统一的行为有了轻微的偏移,对于这种偏移的语句需要移动到调用者处(3的反向重构)
5.以函数调用取代内联代码:如果有代码能被现成的库函数或者其他函数取代,应该进行替换
6.移动语句:如果相同职能的代码没有在一起的话,应该将其放到一起,本原则是提取函数等其他重构原则的准备工作
7.拆分循环:如果一个循环里做了多件事情,应该将循环拆分使其符合单一职责,拆分后可以进行函数的提取
8.以管道取代循环:用lambda表达式取代对集合类的循环操作增加代码质量
9.移除死代码:对于不使用的代码应该立即移除

重新组织数据
1.拆分变量,如果一个变量承担了多个职责,那么应该拆分成多个变量保证单一职责
2.字段改名:字段如果需要改变名称且牵扯较多的话,应提前将其封装成类,并使用渐进式的改动
3.以查询取代派生变量:如果是能通过实时计算获取到的值,尽量不要通过额外的变量来辅助获取这个值
4.将引用对象改为值对象:如果一个类的对象不会在多个地方共享的话但是又是引用对象的话,则可使用值对象,即所有属性都为常量的对象
5.将值对象改为引用对象:如果一个类的对象需要在多个地方共享的话但是又是值对象的话,需要改为引用对象(4的反向重构)

简化条件逻辑
1.分解条件表达式:对于复杂的判断条件使用函数进行封装,如果是ifelse的话,使用函数封装后可换成三目表达式
2.合并条件表达式:如果多个判断分支虽然条件不同但是最后的处理语句相同的话,则可以将条件分支合并然后用函数进行封装
3.以卫语句取代嵌套条件表达式:如果有多层ifelse嵌套,则可以通过卫语句(让函数提前返回的单独判断语句)减少嵌套层数
4.以多态取代条件表达式:如果函数里的条件表达式过于复杂,可以考虑创建子类使用多态来分摊复杂度,然后使用工厂模式封装实现类的注入逻辑
5.引入特例:如果代码中多个地方都在检查同一个值并且在等于此值时做的处理也都相同时,可以为这个判断单独拆分出函数和异常流程处理类,比如Assert类
6.引入断言:对于需要检查数据合理性的地方加入断言,以此来保证代码健壮和表明程序此处的预期

重构API
1.将查询函数和修改函数分离:如果一个函数既有查询也有修改,则需要根据查询和修改分拆成多个函数,以此表明函数有无副作用
2.函数参数化:如果两个函数之间只有一些字面量不同,则可以把两个函数合并成一个,然后把这个字面量作为参数传进去
3.移除标记参数:如果函数的参数列表里有用作标记用途的字段,则可以将需要用标记做分发的逻辑拆成多个函数
4.保持对象完整:如果需要一个函数的多个参数是从同一个对象中获取的,可以用这个对象取代参数列表中的这几个参数,然后在函数内部从对象中取值
5.以查询取代参数:如果函数的参数能够在函数内部自行计算或者获取且成本不大时,可以将参数去掉,在函数内部自行计算
6.以参数取代查询:如果函数的内部有想去掉的依赖,则可以将此依赖作为参数让调用方传进来(5的反向重构)
7.移除设值函数:对于不想调用方修改的属性,应该去除set函数
8.以工厂函数取代构造函数:构造函数本身有诸多限制,比如名称不清晰、只能返回本身不能返回子类等,建议使用工厂函数取代构造函数
9.以命令取代函数:当函数过于复杂时,可以专门为其封装命令类,这样可以把局部变量提升成属性,从而无顾虑的拆分成多个函数
10.以函数取代命令:如果命令类内部的函数不是那么复杂,使用命令类反而增加了复杂度,这时候可以还原成函数(9的反向重构)

处理继承关系
1.函数上移:如果多个子类中有相同的函数,应该将函数上移到父类中
2.字段上移:如果多个子类中有相同的属性,应该将属性上移到父类中
3.构造函数本体上移:如果多个子类的构造器中有相同的构造语句,应该将其上移到父类的构造器中
4.函数下移:如果父类的一个函数不是与所有子类有关,应该将其放进关心它的子类中(1的反向重构)
5.字段下移:如果父类的一个属性不是与所有子类有关,应该将其放进关心它的子类中(2的反向重构)
6.以子类取代类型码:使用子类取代枚举类型,方便之后不同类型有不同行为时的扩展
7.移除子类:如果子类不再被需要,则需要将子类移除(6的反向重构)
8.提炼超类:如果两个类在做类似的事情,应该提炼出父类,然后使用前面的上移手段将公共部分上移到父类
9.折叠继承体系:在演进过程中,随着函数/字段的上移/下移如果父类和子类已经没有太大区别,此时可以将父类和子类进行合并
10.以委托取代子类:由于java之类语言的只支持单继承,且更改父类会影响子类,所以在必要时候建议使用委托取代继承
11.以委托取代超类:如果父类的其中一些函数并不适合子类,此时应该用委托取代父类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值