1、Extract Method(提炼函数)
将一段代码放进一个独立函数中,并用函数名解释该函数的用途。通常当你想给一段代码加注释来表明他的用途的时候,就可以思考是否可以 Extract Method。
动机:首先,如果每个函数的粒度都很小,那么函数之间彼此复用的机会就更大;其次,这会使高层函数码读起来就像一系列注释;再者,如果函数都是细粒度,那么函数的覆写会更容易些。
2、Inline Method(将函数内联化)
如果一个函数函数,其内部代码和函数名称同样清晰易读,那就应该去掉这个函数,直接把其代码变为内联函数,因为非必要的间接性会影响理解。
3、Inline Temp(将临时变量内联化)
如果一个临时变量声明后只赋值了一次,可以考虑将这个变量直接放进引用它的地方。
Tip:想检验变量是否只被赋值了一次,可以先将其设置为final,看编译器是否报错。
4、Replace Temp with Query(用查询函数替代临时变量)
把临时变量的计算式放进函数中,函数返回值返回计算结果。
动机:1.同一个class中的所有函数都将可以使用这个新函数简化代码。
2.局部变量会阻碍你 Extract Method。
5、Introduce Explaining Variable(引入解释性变量)
表达式有可能非常复杂而难以阅读。这时可以将一个复杂表达式的值赋给一个临时变量,用临时变量的变量名来解释表达式的意图。例如:
final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1; // 这里用 isMacOs变量,清晰地解释了后面的句子是干嘛的。
6、Split Temporary Variable(剖解临时变量)
如果有个临时变量被赋值超过一次,但它既不是循环变量,也不是一个集用临时变量(保存一系列计算过程的结果)。则说明它们承担了一个以上的责任,
例如如下的代码,temp变量就承担了两个不同的责任,应该新建一个新的变量,而不是对temp重复赋值。
7、Remove Assignments to Parameters(移除对参数的赋值动作)
不要在函数里对参数进行赋值。需要时可以考虑新建一个相同类型的局部变量,让这个局部变量copy需要的参数。
如下图一,对参数 inputValue 进行了修改,正确做法如图二所示。
8、Replace Method with Method Object(以函数对象取代函数)
如果一个大型函数,其中对局部变量的使用使你无法釆用 Extract Method。那么可以将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域(field) 然后你可以在同一个对象中将这个大型
函数分解为数个小型函数。
作法:
1、建立一个新class,根据旧函数的用途,为这个class命名。
2、在新class中建立一个final值域,类型是旧函数所属的类。我们将这个值域称为源对象。同时,针对旧函数的每个临时变量和每个参数,在新class中建立一个个对应的field。
3、在新class中建立一个构造函数,接收源对象及原函数的所有参数作为参数。
4、在新class中建立一个compute()函数。将原(旧)函数的代码拷贝到compute()函数中。如果需要调用源对象的任何函数,则通过源对象调用。
5、将旧函数的函数本体替换为:创建上述新对象, 并调用其中的compute()函数。
示例:
将下面的 method 变成 method Object
先构建 method object,并在源对象里引用这个创建并引用这个新object
现在可以方便地对 method 进行重构而不用受制于局部变量了
9、Substitute Algorithm(替换你的算法)
如果发现一个函数可以有更清晰的实现方式,就应该以较清晰的方式取代复杂方式。
作法:
构建安全网,对原算法撰写完善的测试。
对新算法执行测试。如果结果与原本结果相同,重构结束。
如果测试结果不同于原先,在测试和调试过程中,以旧算法为比较参照标准。
对于每个test case(测试用例),分别以新旧两种算法执行,并观察两者结果是否相同。这可以帮助你看到哪一个test case出现麻烦,以及出现了怎样的麻烦。