Separate Query from Modifier(将查询函数和修改函数分离)
某个函数既返回对象状态值,又修改对象状态;建立两个不同的函数,其中一个负责查询,另一个负责修改。
动机
如果某个函数只是向你传递一个值,没有任何看得到的副作用。那么你就可以任意调用这个函数,也可以把调用动作搬到函数的其他地方,简而言之,需要操心的事情少了。
对于有副作用和无副作用两种函数之间的差异,下面是一条好规则:任何有返回值的函数,都不应该有看得到的副作用;
对于看得到的副作用,最常见的优化办法是:将查询所得结果缓存于某个字段中,这样后续的查询就可以大大加快速度。
Parameterize Method(令函数携带参数)
若干函数做了类似的工作,但在函数本体中却包含了不同的值。建立单一函数,以参数表达那些不同的值。
动机
如果两个函数,它们做着类似的工作,但因少数几个值致使行为略有不同。这种情况下,你可以将这些各自分离的函数统一起来,并通过参数来处理那些变化情况,用以简化问题。这样可以去除重复代码并提高灵活性。
Replace Paramter with Explicit Methods(以明确函数取代参数)
你有一个函数,其中完全取决于参数值而采取不同行为,针对该参数的每一个可能值,建立一个独立的函数。
动机
如果某个参数有多种可能的值,而函数内又以条件表达式检查这些参数值,并根据不同参数值做出不同的行为,那么就应该使用本项重构。调用者原本必须赋予参数适当的值,以决定该函数做出何种响应。
Preserve Whole Object(保持对象完整)
你从某个对象中取出若干值,将它们作为一次函数调用时的参数,将取出的多个参数改为传递整个对象。
动机
如果将来自同一个对象的若干数据作为参数,传递给某个函数。这样做的问题在于:万一将来被调用函数需要新的数据项,你就必须查找并修改对此函数的所有调用。
-
如果把这些数据所属的整个对象传给函数,可以避免这种尴尬的处境,因为被调用函数可以向那个参数对象请求任何它想要的信息。
-
除了可以是参数列更稳固之外,本重构往往还能提高代码的可读性。这样可以避免过长的参数,因为调用者和被调用者都必须记住这些参数的用途。
-
不使用完整对象也会造成重复代码,因为被调用函数无法利用完整对象中的函数来计算某些中间值。
但是,如果被调用函数使用来自另一个对象的很多数据,这可能意味着该函数实际上应该被定义在那些数据所属的对象中。此时应该考虑转移方法。
Replace Parameter with Methods(以函数取代参数)
对象调用某个函数,并将所得结果作为参数,传递给另一个函数,而接受该参数的函数本身也能够调用前一个函数。让参数接受者去除该项参数,并直接调用前一个函数。
动机
如果函数可以通过其他途径获得参数值,那么它就不应该通过参数取得该值。过长的参数列会增加程序阅读者的理解难度,因此应该尽可能缩短参数列的长度。
缩短参数列的办法之一就是:看看参数接收端是否可以通过与调用端相同的计算来取得参数值。如果调用端通过其所属对象内部的另一个函数来计算,并在计算过程中未曾引入调用端的其他参数,那么你就应该可以将这个计算过程转移到被调用端内,从而取出该项参数。
如果你所调用的函数隶属另一个对象,而该对象拥有调用端所属对象的引用,则同样适用。
如果参数值的计算过程依赖于调用端某个参数,那么你就无法去掉被调用端的参数。参数的存在是为了将来的灵活性,所以只在必要关头才添加参数。
Introduce Paramter Object(引入参数对象)
某些参数总是很自然地同时出现,以一个对象取代这些参数。
你常会看到特定的一组参数总是一起被传递,可能有好几个函数都使用这一组参数,这些函数可能隶属同一个类,也可能隶属不同的类。这种参数被称为数据泥团,可以运用一个对象包装所有这样的数据,再以该对象取代它们。
本项重构还可以带给你更过好处,当你把这些参数组织到一起后,往往很快可以发现一些可被移至新建类的行为,通常,原本使用那些参数的函数对这一组参数会有一些共通的处理,如果将这些共通行为移到新对象中 ,你可以减少很多重复代码。
Remove Setting Method(移除设值函数)
类中的某个字段应该在对象创建时被设值,然后就不在改变,去掉该字段的所有设值函数。
动机
如果你为某个字段提供设值函数,这就暗示这个字段值可以被改变,如果你不希望在对象创建后此字段还有机会被改变,就不要为它提供设值函数。这样意图会更加清晰,并且可以排除其值被修改的可能性。
Replace Error Code with Exception(以异常取代错误码)
某个函数返回一个特定的代码,用以表示某种错误情况。
做法
- 决定应该抛出受控(checked)异常还是非授控(unchecked)异常;
如果调用者有责任在调用前检查必要状态,就抛出非受控异常;
如果想抛出受控异常,你可以新建一个异常类,也可以使用现有的异常类;
- 找到该函数的所有调用者,对它们进行相应调整,让它们使用异常;
如果函数抛出非受控异常,那么就调整调用者,使其在调用函数前做适当检查,每次修改后,编译并测试。
如果函数抛出受控异常,那么就调整调用者,使其在try区段中调用该函数。
- 修改该函数签名,令它反映出新用法;