《重构:改善既有代码的设计》读书笔记三

发布时间 2023-12-29 23:15:55作者: wrf12

7、Feature Envy(依恋情结)

函数对于某个类的兴趣高过对自己所处类的兴趣。

  • 把这个函数移至另一个地点,移到它该去的地方。Move Method(搬移函数)
  • 如果一个函数用到几个类的功能,则该判断哪个类拥有最多被此函数使用的数据,然后就把这个函数和那些数据摆在一起。Extract Method(提炼函数)Move Method(搬移函数)

8、Data Clumps(数据泥团)

数据项就像小孩子,总喜欢成群结对地的待在一块,如果删掉众多数据中的一项,其他数据因而失去意义,就应该为它们产生一个新对象

  • 如果一个类里有很多有关系的数据Field,那么就要考虑为这些有关系的数据建立一个新家。Extract Class(提炼类) 创建数据新对象
  • 如果函数参数引用很多有关系的Field,那么就要考虑让这些分散的参数变成参数对象。Introduce Parameter Object (引用参数对象)
  • 如果一个函数的参数来自同一个对象的若干个属性,可以考虑引用对象。因为如果被调用的的函数改变参数,必须查找并修改这个函数的所有调用Preserve Whole Object(保持对象完整)

    第二点与第三点类似,只不过第二点需要新建一个类来声明字段,第三点不用

9、Primitive Obsession(基本类型偏执)

简单一句话就是只喜欢在原代码的基础上加基本类型字段,不喜欢提取对象

  • 可以运用Replace Data Value with Object (以对象取代数据值)将原本单独存在的数据值替换为对象。
  • 如果想要替换的数据值是类型码,而它不影响行为,则可以运用Replace Type Code with Class(以类取代类型码)将它换掉。
  • 如果你有与类型码相关的条件表达式可以运用Replace Type Code with SubClasses(以子类取代类型码) 或者 Replace Type Code with State/Strategy (以State/Strategy取代类型码 )加以处理。
  • 如果你有一组总是被放在一起的字段,可以运用Extract Class(提炼类)
  • 如果在参数列中看到基本数据类型,不妨试试Introduce Parameter Object (引用参数对象)
  • 如果你发现自己正从数组中挑选数据,可以运用 Replace Array with Object(以对象取代数组)

10、Switch Statements(Switch惊悚现身)

你常会发现switch语句散布于不同地点。如果要为它添加一个新的case子句,就必须找到所有switch语句并修改它们。面向对象中的多态概念可为此带来优雅的解决办法。

  • 条件表达式,它根据类型的不同而选择不同的行为。Replace Conditional with Polymorphism (以多态取代条件表达式)
  • 有个类型码,它会影响行为,但你无法通过继承的方式消除它,或者类型码的数值在对象的生命周期中发生变化Replace Type Code with State/Strategy (以状态/策略取代类型码)
  • 如果单一函数 有些选择事例,且不想改动它们,那么多态就有点杀鸡用牛刀了。Replace Parameter with Explicit Methods (以明确函数取代参数)

11、Parallel Inheritance Hierarchies(平行继承体系)

平行继承体系其实是散弹式修改的特殊情况。这种情况下,每当你为某个类增加一个子类,必须也为另一个类相应增加一个子类。如果你发现某个继承体系的类名称前缀和另一个继承体系的类名称前缀完全相同,便是闻到了这种坏味道

  • 让一个继承体系的实例引用另一个继承体系的实例,,如果在运用Move Method (搬移函数)Move Field(搬移字段)就可以将引用端的继承体系消弭于无形

12、Lazy Class(冗赘类)

如果一个类的所得并不值其身价,他就应该消失。项目中经常会出现这样的情况:某个类原本对得起自己的价值,但重构使它身形缩水,不再做那么多工作;或开发者事先规划了某些变化,并添加一个类来应付这些变化,但变化实际没有发生。

  • 如果某些子类没有做足够的工作,使用Collapse Hierarchy(折叠继承体系)
  • 对于几乎没用的组件,使用Inline Class(将类内联化)

13、Speculative Generality(夸夸其谈未来性)

如果这段代码当前用不到,就删掉它

  • 如果你的某个抽象类没有太大作用,请用Collapse Hierarchy(折叠继承体系)
  • 不必要的委托可以用Inline Class(将类内联化)除掉
  • 如果函数的某些参数未被用上,可对它实施Remove Parameter(移除参数)
  • 如果函数名带有多余的抽象意味,应该对它实施Rename Method(函数改名)

14、Temporary Field(令人迷惑的暂时字段)

如果类中有一个复杂算法,需要好几个变量,往往就可能导致坏味道令人迷惑的临时字段(Temporary Field)出现。由于实现者不希望传递一长串参数,所以他把这些参数都放进字段。但是这些字段只在使用该算法时才有效,其他情况下只会让人迷惑。

  • 这时可以利用 Extract Class (提炼类)把这些变量和其相关函数提炼到一个独立的类中。

15、Message Chains(过度耦合的消息链)

如果你看到用户向一个对象请求另一个对象,然后在向后者请求另一个对象,然后在请求另一个对象类似: getPerson().getDepartment().getAddress().getStreet() 就是消息链

  • 使用Hide Delegate(隐藏委托关系)。理论上讲可以重构消息链上的任何一个对象,但这么做会把一系列对象都变成中间人(Middle Man)。
  • 先观察消息链最终得到对象来干什么,看能否以Extract Method(提炼函数)把使用该对象的代码提炼到一个独立的函数中,再用Move Method(搬移函数)把这个函数推入消息链

16、Middle Man(中间人)

对象的基本特征之一就是封装——对外部世界隐藏其内部细节.封装往往伴随着委托(delegate)。但人们可能过度运用委托。你也许会看到某个类接口有一半的函数都委托给其它类,这样就是过度运用。

  • 使用Remove Middle Man(移除中间人)直接和真正的负责的对象打交道
  • 如果这样不干实事的函数只有少数几个运用,使用Inline Method(内联函数) 把他们放进调用端
  • 如果这些中间人(Middle Man)还有其它行为,可以运用Replace Delegation with Inheritance(以继承取代委托)把它变成实责对象的子类,这样既可以扩展愿对象行为,又不必担心那么多委托动作。

17、Inappropriate Intimacy(狎昵关系)

有时候你会看到两个类过于亲密,花费太多时间去探究彼此的private成分。

  • 可以采用Move Method(搬移函数)Move Field(搬移字段)帮它们划清界限,从而减少狎昵行径
  • 也可以运用Change Bidirectional Association to Unidirectional(将双向关联改为单向关联)让其中一个类对另一个斩断情丝
  • 如果两个类实在情投意合,可以使用Extract Class(提炼类)把两者共同点提炼到一个安全地点,让它们坦荡使用新类
  • 或者使用Hide Delegate(隐藏委托关系)让另一个类为它们传递相思情

18、Alternative Classes with Different Interfaces(异曲同工的类)

两个函数做同一件事却有不同的签名

  • 使用Rename Method(函数改名)重命名函数,然后反复使用Move Method(搬移函数)将某些行为移入类,直到两者的协议一致为止。如果必须重复而赘余地移入代码才能完成这些,或许可运用Extract Superclass(提炼超类)为你自己赎点罪

19、Incomplete Library Class(不完美的库类)

  • 如果想修改库类的一两个函数,可以运用Introduce Foreign Method(引入外加函数)
  • 如果想加一大堆额外行为,运用Introduce Local Extension(引入本地扩展),好处"函数和数据被统一封装,使得其它类部分过分复杂"