整理自 RefactoringGuru
代码异味——什么?代码如何“闻味道”??
——它没有鼻子...但它肯定会发臭!
代码膨胀【代码膨胀】是代码、方法和类,它们的规模已经增加到了难以处理的地步。通常,这些异味不会立即出现,而是随着程序的演化而积累(尤其是当没有人努力根除它们的时候)。
过长方法
方法包含的代码行太多。一般来说,任何超过十行的方法都会让你产生疑问。
过大的类
一个类包含许多字段/方法/代码行。
基本类型偏执
在简单任务中使用基本类型而不是小对象(例如货币、范围、电话号码的特殊字符串等)
使用常量来编码信息(例如常量USER_ADMIN_ROLE=1表示具有管理员权限的用户。)
在数据数组中使用字符串常量作为字段名。
过长参数列表
一个方法有三个或四个以上的参数。
数据泥团
有时,代码的不同部分包含相同的变量组(例如用于连接数据库的参数)。这些组应该转化为它们自己的类。
面向对象滥用所有这些异味都是面向对象编程原理的不完整或不正确应用。
switch语句
你有一个复杂的switch运算符或if语句序列。
临时字段
临时字段仅在特定情况下获取其值(因此对象需要它)。除此之外,它们是空的。
被拒绝的继承
如果子类只使用从其父类继承的一些方法和属性,那么层次结构就不正常。不需要的方法可能只是不使用,或者被重新定义并发出异常。
具有不同接口的备选类
两个类具有相同的函数,但方法名不同。
更改的阻碍这些异味意味着,如果你需要在代码的某个地方更改某些内容,那么你也必须在其他地方进行许多更改。因此,程序开发变得更加复杂和昂贵。
发散式更改
在更改类的时候,你发现自己必须更改许多不相关的方法。例如,添加新产品类型时,必须更改查找、展示和订购产品的方法。
散弹式更改
修改任何东西都需要对许多不同的类做出许多小的更改。
平行继承体系
每当你为一个类创建一个子类时,你就会发现自己需要为另一个类创建一个子类。
可有可无的东西可有可无的东西是毫无意义和不必要的,如果没有它,代码就会更干净、更高效、更容易理解。
注释
方法中充满了解释性注释。
重复代码
两段代码看起来几乎相同。
冗余类
理解和维护类总是需要花费时间和金钱。因此,如果一个类不足以吸引你的注意力,它应该被删除。
数据类
数据类是指只包含字段和用于访问字段的方法(获取器和设置器)的类。这些只是其他类使用的数据容器。这些类不包含任何附加功能,并且不能独立操作它们所拥有的数据。
死代码
变量、参数、字段、方法或类已不再使用(通常是因为它已过时)。
夸大通用性
存在未使用的类、方法、字段或参数。
耦合器这一组中的所有异味都会导致类之间的过度耦合,或者显示如果耦合被过度委托所取代会发生什么。
功能依赖
一个方法访问另一个对象的数据多于它自己的数据。
过度亲密
一个类使用另一个类的内部字段和方法。
消息链
在代码中可以看到一系列类似于$a->b()->c()->d()的调用。
中间人
如果一个类只执行一个操作,将工作委托给另一个类,那么它为什么存在呢?
其他异味不完善的库类
库迟早会停止满足用户需求。由于库是只读的,所以问题的唯一解决方案,也就是更改库,通常是不可能的。
重构技巧 组合方法很多重构都致力于正确地组合方法。在大多数情况下,过长的方法是万恶之源。这些方法中变幻莫测的代码隐藏了执行逻辑,使得该方法极难理解,甚至更难更改。
这一组中的重构技巧简化了方法,消除了代码重复,并为未来的改进铺平了道路。
提取方法
问题:你有一个可以组合在一起的代码片段。
解决方案:将此代码移动到一个单独的新方法(或函数),并用对该方法的调用替换旧代码。
内联函数
问题:当方法主体比方法本身更明显时,请使用此技巧。
解决方案:用方法的内容替换对方法的调用,并删除方法本身。
提取变量
问题:你的表达式很难理解。
解决方案:将表达式或其部分的结果放在独立的变量中,这些变量是自解释的。
内联临时变量
问题:你有一个临时变量,它被分配了一个简单表达式的结果,仅此而已。
解决方案:用表达式本身替换对变量的引用。
用查询替换临时变量
问题:将表达式的结果放在局部变量中,以便以后在代码中使用。
解决方案:将整个表达式移动到一个单独的方法,并从中返回结果。查询方法,而不是使用变量。如有必要,在其他方法中加入新方法。
拆分临时变量
问题:你有一个局部变量,用于在方法中存储各种中间值(循环变量除外)。
解决方案:对不同的值使用不同的变量。每个变量应该只负责一个特定的事情。
移除参数赋值
问题:某些值被赋给了方法体中的参数。
解决方案:使用局部变量而不是参数。
用方法对象替换方法
问题:你有一个很长的方法,其中局部变量相互交织,以至于你不能应用【提取方法】。
解决方案:将该方法转换为一个单独的类,以便局部变量成为该类的字段。然后可以将该方法拆分为同一类中的多个方法。
替代算法
问题:所以你想用一个新的算法替换现有的算法?
解决方案:用新算法替换实现算法的方法体。
在对象间移动功能即使你在不同的类之间,以不太完美的方式分布了功能,仍然存在希望。
这些重构技术展示了如何在类之间安全地移动功能,创建新的类,以及隐藏实现细节以防公开访问。
移动方法
问题:一个方法在另一个类中使用的次数多于在它自己的类中使用的次数。