美文网首页
重构——重新组织函数

重构——重新组织函数

作者: hklbird | 来源:发表于2016-11-22 23:26 被阅读17次

    函数重构几乎都是源自于Long Methods。这导致了函数包含的信息过多,信息带来的逻辑错综复杂。

    1 Extract Method(提炼函数)

    <b>Summary:</b>将一段代码放进一个独立函数中,并让函数名称解释该函数的用途。
    <b>Motivation:</b>将过长的函数分割成独立的函数,改善代码清晰度。
    <b>Routine:</b>

    • 创造一个新函数,并根据意图命名;
    • 将提炼出的代码从源函数复制到新建的目标函数中;
    • 仔细检查提炼其中是否有源函数作用域的变量。
    • 检查是否有“仅用于被提炼代码段”的临时变量,有则在被提炼函数中将之声明位临时变量。
    • 检查被提炼代码段,看看是否任何局部变量的值被他改变。如果有临时变量的值被改变了,看看是否可将被提炼代码段提炼位一个查询,并将结果赋值给相关变量。如果被修改的变量不止一个,你就不能仅仅将这段代码原封不动地连出来。可能需要用到Split Temporary Variable,然后再尝试提炼。也可以使用Replace Temp with Query。
    • 被提炼代码段中需要读取的局部变量,当做参数传给目标函数。
    • 替代

    2 Inline Method

    <b>Summary</b>:再函数调用点插入函数本体,然后移除该函数。
    <b>Motivation</b>:某些函数其内部结构和函数名同样清晰易读,也肯能是重构之后使其内容和名称变得同样清晰;手底下一些错误拆分的函数内联到一个大型函数中,再重新从中提炼小函数;中间层级过于多,导致了函数只是一个其余函数的代理。这三类是需要使用内联手法进行refacting。
    <b>Routine</b>:

    • 检查函数,确定函数不具有多态性。
    • 找出函数的所有调用点。
    • 替换所有调用点的函数为其本体。
    • 编译,测试。
    • 删除函数定义。

    3 Inline Temp 和 Replace Temp With Query

    3.1 InlineTemp

    <b>Summary:</b>将所有对该变量的引用动作替换位对它赋值的那个表达式自身。
    <b>Motivation:</b>一般是作为Replace Temp with Query的一部分使用的,所以真正的动机是后者。唯一单独使用Line Temp的情况,某个临时变量被赋予某个函数调用的返回值,并阻碍了其他的重构手法。
    <b>Routine:</b>

    • 检查给临时变量赋值的语句,确保等号右侧无副作用。
    • 如果这个临时变量未被声明位final,那就将它声明位final编译,从而验证赋值状况。
    • 找到所有调用点并替换。
    • 编译测试。
    • 删除赋值语句和临时变量。编译测试。

    3.2 Replace Temp With Query(以查询代替临时变量)

    Summary:将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换位对新函数的调用。此后,新函数就可以被其他函数调用。

    double basePrice =_quantity * _itemPrice;
    if(basePrice>1000)
      return basePrice * 0.95;
    else 
      return basePrice * 0.98;
    ……
    double basePrice(){
      return _quantity * _itemPrice;
    }
    

    <b>Motivation:</b>临时变量是暂时的,只能在所属函数内使用。由于临时变量只在所属函数内可见,所以它们会驱使你写更长的函数。如果把临时变量替换位一个查询,那么同一个类中的所有函数都将可以获得这份信息。这将带来极大的帮助,写除清晰的代码。
    <b>Routine:</b>

    • 找出只被赋值一次的临时变量(如果赋值超过一次,可以考虑Split Temporary Variable)。
    • 将临时变量声明位final。
    • 编译。
    • 提炼等号右侧部分到一个独立函数中。
    • 编译,测试。
    • 在该临时变量身上使用Inline Temp。

    4 Introduce Explaining Variable(引入解释性变量)

    <b>Summary:</b>将复杂表达式(或者其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途。
    <b>Motivation:</b>在条件逻辑中,判定条件往往相当复杂,引入解释性变量来对应其意义来明晰代码逻辑;另外,在较长的算法中,可以运用临时变量来解释每一步运算的意义。
    <b>Routine:</b>

    • 声明一个final临时变量,将待分解之复杂表达式中的一部分动作的运算结果赋值给它。
    • 将运算结果的相应部分替换位上述变量。
    • 编译,测试。
    • 重复上述过程。

    5 Split Temporary Variable(分解临时变量)

    <b>Summary:</b>针对每次赋值,创造一个独立,对应的临时变量。
    <b>Motivation:</b>临时变量有各种不同用途,其中某些用途会很自然地导致临时变量被多次赋值。循环变量和循环收集变量就是其中的典型例子。除了这两种情况,还有很多临时变量用于保存一段冗长代码的运算结果,以便稍后使用。这种临时变量应该只有一次赋值,赋值多次就代表这临时变量承担多个责任,就应该被分解替换。
    <b>Routine:</b>

    • 在待分解变量的声明及其第一次被赋值处,修改其名称。(如果是结果收集变量和循环变量则不要分裂)
    • 将新的临时变量声明位final。
    • 以该临时变量的第二次赋值动作位界,修改此前对该临时变量的所有引用点,让它们引用新的临时变量。
    • 在第二次赋值处,重新声明原先那个临时变量。
    • 编译,测试。
    • 重复执行上述过程。

    6 Remove Assignments to Parameters(移除对参数的赋值)

    <b>Summary:</b>以一个临时变量取代该参数的位置。
    <b>Motivation:</b>这会降低代码的清晰度,会让人搞不清楚是参数的值域被修改还是新的被指向的值域被修改。
    <b>Routinue:</b>

    • 建立一个临时变量,把待处理的参数值赋予给它。
    • 以此位置为界,将其后所有对此参数的引用点,全部替换为此临时变量的引用。
    • 修改赋值语句,使其改为对新建值临时变量的赋值。
    • 编译,测试。

    7 Replace Method with Method Object(以函数对象取代函数)

    <b>Summary:</b>将函数放进一个单独对象中,如此一来局部变量就成了对象内的字段。然后可以在一个对象中将大型函数切分位多个小型函数。
    <b>Motivation:</b>如果一个函数之中局部变量泛滥成灾,那么像分解这个函数是非常困难的,当Replace Temp with Query无法更笨上拆解一个函数时,应该用对象。
    <b>Routinue:</b>

    • 建立一个新类,根据职责命名。
    • 在新类中建立一个final字段,泳衣保存原先大型函数所在对象,针对原函数的每个临时变量和参数,在新类中建立对应的字段保存。
    • 在新类的构造函数传入源对象和所有参数。
    • 在新类中建立函数,在函数中粘贴进源代码。
    • 编译。
    • 将旧函数的函数本体替换位创建一个新对象,并调用相应函。

    8 Substitute Algorithm(替换算法)

    <b>Summary:</b>把某个算法替换位更清晰的算法。
    <b>Motivation:</b>替换更好或者更易修改的函数。
    <b>Routinue:</b>

    • 准备好替换算法。
    • 执行新算法。
    • 以旧算法位标准修正新算法。

    相关文章

      网友评论

          本文标题:重构——重新组织函数

          本文链接:https://www.haomeiwen.com/subject/ihdmpttx.html