重构——重新组织数据

2016-11-24  本文已影响12人  hklbird

1 Self Encapsulate Field(自封装字段)

直接访问一个字段,会导致字段之间的的耦合关系过于笨拙。为字段建立取值/设值函数,并且只以这些函数来访问字段。
  动机:可以通过覆写函数而改变获取数据的途径。
  做法:

2 Replace Data Value with Object(以对象取代数据值)

数据项需要与其他数据和行为一起使用才有意义。
  动机:当数据开始变得复杂,操作数据的操作开始变多,就会变成这样。
  做法:

3 Change Value to Reference(将值对象改为引用对象)

从一个类衍生出许多彼此相等的实例,希望将它们替换为同一个对象。将这个值对象变成引用对象。
  Motivation:在引用对象和值对象间做选择有时不容易。有时候,你会从一个简单的值对象,在其中保存少量不可修改的数据。而后,你可能会希望给这个对象加入一些可修改数据,并确定对任何一个对象的修改都能影响到所有引用此一对象的地方。这时候需要将对象变成一个引用对象。
  做法:

4 Change Reference to Value

有一个引用对象,很小且不变,而且不易管理。将它变成一个值对象。
  Motivation:如果引用对象开始变得难以使用,也许就应该将它改为值对象。引用对象将会早成很复杂的关联。特别是在分布式系统和并发系统中,不可变的值对象特别有用,因为你无需考虑它们的同步问题。
  做法:

5 Replace Array with Object(以对象取代数组)

数组的各个元素各自代表的意义不同。以对象替换数组,对于数组中的每个元素,以一个字段来表示。
  Motivation:数组应该是用来组织容纳一组相似的对象。如果数组里容纳的对象的意义不同,那么会给带来很臭的味道。

6 Duplicate Observed Data(复制“被监视的数据”)

将该数据赋值到一个领域对象中。建立一个Observer模式,以同步对象和GUI对象内的重复数据。其实就是用Observer模式改造类。
  Motivation:一个分层良好的系统,应该将处理用户界面和处理业务逻辑分开。

7 Change Unidirectional Association to Bidirection

添加一个反向指针,并使修改函数能够同时更新两条链接。
  Motivation:被引用类需要得到其引用者以便进行某些处理。这时候就加入了反向指针。
  做法:

tips:下面是如何决定由哪一个类负责控制关联关系。

1.如果两者都是引用对象,关联是一对多的关系。那就由拥有单一引用的那一方承担控制者角色。
2.如果某个对象是组成另一个对象的部件,那么后者控制关联关系。
3.如果两者都是引用对象,关联是多对多,那么随便选一个,是哪个都无所谓。

8 Change Bidirectional Association to Unidirectional

去掉不必要的关联。
  Motivation:大量双向连接很容易造成“僵尸对象”;此外双向关联也迫使连个类之间有了依赖。
  做法:

9 Replace Magic Number with Symbolic Constant

创建一个常亮,根据其意义为它命名,并将上述的字面数值替换位这个常亮。

10 Encapsulate Field

将类中存在的public字段声明位private,并提供相应的访问函数。

11 Encapsulate Collection

让返回集合的函数返回该集合的一个只读副本,并在这个类中提供添加/移除集合元素的函数。
  Motivation:如果直接返回集合的话,集合发生变化,我们的类是一无所知的,这是很可怕的事情;且暴露集合给用户也就是将类的过多实现细节暴露给用户。如果一个取值函数确实需要返回多个值,它应该避免用户直接操作对象内保存的集合,并隐藏对象内与用户无关的数据结构。另外,不应该位集合提设值函数,应该提供用以为集合添加/移除元素的函数。
  做法:

12 Replace Record with Data Class(以数据类取代记录)

你需要面对传统变成环境中的记录结构,为该记录创建一个‘哑’数据对象。
  Motivation:总有可能遇到记录格式,那么就把记录转换位类把。
  做法:

13 Replace Type Code with Class(以类取代类型码)

类之中有一个数值类型码,但它并不影响类的行为。以一个新的类替换该数值类型码。
  Motivation: 在以C位基础的变成语言中,类型码和枚举值还是很常见的,类型码可读性还是不错。但问题在于,类型码终归是别名,编译器看见的,进行类型检测的还是还是数值。使用类型码的实质其实就是使用一个数值,无法强制使用符号名。这会大大降低代码的可读性,滋生bug。
  做法:

14 Replace Type Code with Subclasses(以子类代替类型码)

有一个不可变的类型码,会影响类的行为。以子类取代这个类型码。
  Motivation:如果面对的是不会影响宿主类的行为,可以使用Replace Type Code with Class。如果类型码会影响宿主类的行为,那么最好的办法就是借助多态去解决它。一般来说这种情况的标志就是像switch这种表达式。这种条件表达式可能有两种表现形式:switch或者是if-then-else结构。这种情况必须重构,用的是Replace Conditional with Polymorphism进行重构。但为了能够顺利进行那样的重构,首先应该将类型码转换为可拥有多态行为的继承体系。这样的一个继承体系应该以类型码宿主为基类,针对每种类型码各建立一个子类。
  做法:

15 Replace Type Code with State/Strategy

有一个类型码,会影响类的行为,但无法继承手法消除。以状态对象取代类型码。
  Motivation:和Replace Type Code with Subclasses很相似,但是类型码在生命期间发生变化或者其他原因宿主不能被继承。可以用此方法重构。主要使用State模式或策略模式。

16 Replace Subclass with Field

你的各个子类的唯一差别只在“返回常量数据”的函数身上。修改这些函数,使它们返回 超类中的某个字段,然后销毁子类。
  Motivation:有一种变化行为叫做“常量函数”,它们会返回一个硬编码的值。若子类只有常量函数,是在没有足够存在的价值,应该去掉以避免额外的复杂性。
  做法:

上一篇下一篇

猜你喜欢

热点阅读