重构
重构(名词): 对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。
大型重构
对顶层代码设计的重构,包括:系统、模块、代码结构、类与类之间的关系等的重构,重构的手段有:分层,模块化,解耦,抽象复用组件等。这类重构的工具就是我们学习过的设计思想、原则和模式、这类重构涉及的代码会比较多,影响面比较大,所以,难度也较大,耗时比较长。
小型重构
对代码细节的重构,主要是针对类、函数、变量等代码级别的重构,比如规范命名和注释,消除超大类或者函数、提取重复代码等等。小型的重构更多的是使用统一的编码规范。这类重构要修改的地方比较集中,比较简单,可操作性较强,耗时短,引入bug风险较小。什么时候重构新功能开发、修复bug或者代码review中出现“坏代码味道”,我们就应该及时进行重构。持续在日常开发中进行小重构,降低重构和测试的成本。
代码的坏味道
-
代码重复
实现逻辑相同,执行流程相同
-
方法过长
方法中的语句不在同一个抽象层级
逻辑难以理解,需要大量的注释
面向过程编程而非面向对象
-
过大的类
类做了太多的事情
包含过多的实例变量和方法
类的命名不足以描述所做的事情
-
逻辑分散
发散式变化:某个类经常因为不同的原因在不同的方向上发生变化
散弹式修改:发生某种变化时,需要在多个类中做修改
-
严重的情结依恋
某个类的方法过多的使用其他类的成员
-
数据泥团/基本类型偏执
两个类、方法签名中包含相同的字段或者参数
应该使用类但使用基本类型,比如表示数值与币种的Money类、起始值与结束值的Range类
-
不合理的继承体系
继承打破了封装性、子类依赖其父类中特定功能的实现细节
子类必须跟着其父类的更新而演变
设计模式
创建型
主要解决对象的创建问题,封装复杂的创建过程,解耦对象的创建代码和使用代码
工厂:创建一个或者多个相关的对象,而使用者不用关系具体的实现类
建造者:用于创建一种类型的复杂对象,通过设置不同的可选参数进行“定制化”
结构型
主要通过类或者对象的不同组合,解耦不同功能的耦合
代理:不改变原始类和不使用继承的方式,通过引入代理类来给原始类附加功能
静态代理如果接口新增一个方法,除了所有实现类(真实主题类)需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
代理对象只服务于一种类型的对象,如果要服务多类型的对象。必须要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了
可以通过一个代理类完成全部的代理功能,接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。当接口方法数量较多时,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
动态代理的应用使我们的类职责更加单一,复用性更强。
装饰者:不改变原始类和不适用继承的情况下,通过组合的方式动态扩展原始类的功能
桥接:当类存在多个独立变化维度时,通过组合的方式使其可以独立进行扩展
门面(外观)模式:为子系统的接口定义一个更高层的接口,使得子系统更加容易使用
行为型
主要解决的是类或者对象之间的交互行为的耦合
命令:将不同的请求封装成对应的命令对象,对命令执行进行控制且对使用方法透明