1.代码的改写从大范围到小范围大致可以分为四级:系统级别,功能级别,代码级别,机器级别; 2.代码级别以下改动可视为“重构”,功能级别以上级别只能视为“重写”
3.重构是持续的日常过程,而重写不是
辨析了“重写”与“重构”之后,下面专注地讲一下重构
在不改变可观察行为下,修改代码内部结构
差的设计在后期越来越难以新增功能,好的设计在软件开发的每个阶段新增功能的速度都是差不多的
童子军法则,只要修改完比修改后更易懂,大到设计,小到函数,命名
1. 使用单元测试;分层测试;UI自动化测试
2. 进行可测试性改造:UI分离;Mock;依赖注入
**1. - 函数问题(30s能读懂)**
- 过长函数(Long Method):最好不超过20行
- 过长参数列(Long Parameter List):最好不超过5个《代码整洁之道推荐不超过3个》
- 基本类型偏执(Primitive Obsession)
- 重复的Switch(Repeat Switch)
- 循环问题(Loops)
- 过大的类(Large Class)
- 临时字段(Temporary Field)
- 数据泥团(Data Clumps):大量的数据要用结构组织,不要平铺
- 纯数据类 (Data Class)
- 神秘命名(Mysterious Name)
- 全局变量 (Global Data)
- 可变数据 (Mutable Data)
- 发散式变化(Divergant Change)
- 散弹式修改(Shotgun Surgery)
- 依恋情节(Feature Envy)
- 夸夸其谈通用性(Speculative Generality)
- 过长的消息链(Message Chain)
- 中间人(Middle Man)
- 内幕交易(Insider Trading)
- 被拒绝的馈赠(Refuse Bequest)如子类不需要父类功能特性, **组合而不是继承**
- 注释(Comments): 代码自注释 > 写注释 > 不写注释
- 重复代码(Duplicated Code)
- 冗余元素(Lazy Element)
- 异曲同工的类(Alternative Class with Defenter interface )
- SonarLint 插件 + CodeDog
- IDE Refactor + Complex Method
- 函数提取:即按照逻辑拆分子函数。
- 分解表达式
- 以多态处理堆叠的条件表达式(如switch)
- 状态模式
- 策略模式
- 将条件表达式转换为查找表,使用注解完成映射
- 封装细节
- 保留关键函数路径
- 抽象层次一致
- 最好不要超过10行
- 函数自注释
- 问题
- 调用参数不易传递
- 增加理解难度
- 伴随巨大函数,基本类型偏执
- 解决方案
- 构造参数对象
- 用builder 代替构造器
- 卫语句,即异常case先返回,主要逻辑在后。将嵌套逻辑扁平化
- 管道替代循环,声明式替代命令式
Program to an interface, not an implementation.
组合优于继承
- 代码阅读能力
- 重构方法的掌握
- 时间,如需求倒排
- 抽象
- 继承
- 多态
- 单一职责
- 接口设计
- 依赖倒置原则
- 接口分离原则
- 接口隔离原则
- 一个类要尽可能不依赖外部
- 高内聚、低耦合
- 开闭原则
- 迪米特法则
- 如何处理父子关系
- 里氏替换原则
- 合成、聚合原则
- 3.2.3.1 抽象:提取关键元素
- 三原则
- DRY 原则:Don't Repeat Yourself
- YAGNI 原则:极限编程,不需要抽象那些你不需要的东西
- Rule of three: 原则1,2的取舍方法
- 抽象不足
- God Project:违反了单一职责原则
Android 刚开始开发时,使用MVC,V与C混杂在一起,造就了很多God Object。
- 提取类
- 抽象过度
- 如没有变量,只有方法,则抽象过于具体
- 3.2.3.2 封装:隐藏细节
- 封装细节
- 1. 成员变量,一般设置为private
- 2. 集合:Collections.unmodifiableList
- 3. 函数:暴露较少接口,慎重写public函数
- 封装可预期变化
- 1. 散弹式修改,如每个AIDL调用,新增时非常复杂(使用查找表+注解依赖注入完成自动映射,不必每次新增)
- 3.2.3.3 模块化
- 实现手法
- 通过封装得到模块
- 模块之间使用接口交互
- 常见问题
- 模块接口异常
- 臃肿 如Refuse Bequest
- 多变
- 模块依赖异常
- 循环依赖
- 修改一处,相互影响,产生震荡
- 切断循环依赖
- 继承可能也产生循环依赖
- 中间人依赖
- 依赖方个数 + 被依赖方个数越大,(一般)出现问题可能性越高。
- 3.2.3.4 层次结构
- 常见问题
- 继承关系复杂
- 不恰当的继承(Stack -> vector ,不成立的继承关系)
- 解决方案
- 确保可替换性
- 组合优于继承
- 依赖顺序正确,最好是层级次序
- 继承结构简洁,如2层
工程师素养
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。