`
足至迹留
  • 浏览: 495657 次
  • 性别: Icon_minigender_1
  • 来自: OnePiece
社区版块
存档分类
最新评论

3. 重新组织函数

 
阅读更多
重构,无外乎就是重新组织变量(实例变量,静态变量,局部变量,临时变量),表达式,函数,类,继承机制(extends, implements)等,以提高代码的可读性,可维护性等。代码世界里不希望看到高富帅,一切都以“小”为美。单纯的结构只做一件事,只因一件事而变化,变化时尽量只修改少量的地方,复杂功能也仅仅是借助群体的力量,以组合或集成的方式来扩展。我们这里从函数开始,介绍一些可以达成这种目标的方法。

3.1 Extract Method(提炼函数)
当看见一个过长的函数或者一段需要注释才能让人理解用途的代码,就需要看下是否需要把这段代码放进一个独立函数中。再次说明,函数的长度并不是看有多少行,关键在于函数名称和函数本体之间的语义距离。如果一个函数可以比较方便的定义一个简短又清晰的名字来描述它的功能,那么这个函数的大小就是合适的。
Extract Method最大的困难就是处理局部变量,而临时变量是其中一个主要的困难源头。

1. 局部变量最简单的情况是:被提炼代码段只是读取这些变量的值,并不修改它们。可以简单地把临时变量当做参数传给目标函数
2. 如果被提炼代码段对局部变量赋值,问题就复杂了。被赋值的临时变量也分两种情况。
    (1)较简单的情况是:这个变量只在被提炼代码段中使用,就可以将这个临时变量的声明移到被提炼代码段中。
    (2)另一种情况是:被提炼代码段之外的代码也使用了这个变量。这就需要让目标函数返回该变量改变后的值。
      如果需要返回的变量不止一个,又该怎么办?有几种选择,
      (1)提炼多个函数,每个函数返回一个临时变量。
      (2)提炼工作不好做,可以尝试运用replace temp with query(后面3.4会讲到)减少临时变量。如果即使这样做了,提炼依旧困难重重,就动用replace method with method object(后面3.8会讲到),这个重构手法不在乎代码中有多少临时变量。

3.2 Inline Method(内联函数)
这点与3.1做法相反,而是把函数代码直接写到使用它的地方。有时候我们会遇到某些函数,其内部代码和函数名称同样清晰易读,那么就可以去掉这个函数,直接在需要的地方使用代码。这通常是比较简单的函数,比如一行三元表达式。
另一种需要使用Inline Method的情况是,手上有一群组织部合理的函数。可以将他们内联到一个大型函数中,再从中提炼出组织合理的小型函数。Kent beck发现,实施replace method with method object之前先这么做,往往可以获得不错的效果。

3.3 Inline Temp(内联临时变量)
如果有一个临时变量,只被一个简单表达式赋值一次,而它妨碍了其他重构手法。可以内联临时变量。比如:
double basePrice = anOrder.basePrice();
return (basePrice > 1000);
可以重构为:
return (anOrder.basePrice() > 1000);

也就是消除临时变量。
Inline temp多半是作为replace temp with query的一部分使用的。

3.4 Replace Temp with Query(以查询取代临时变量)
你的程序以一个临时变量保存某一表达式的运算结果。将这个表达式提炼到一个独立函数中,将这个临时变量的所有引用点替换为对新函数的调用。此后,新函数就可以被其他函数使用。

Replace temp with query 往往是运用Extract method之前必不可少的一个步骤。局部变量会使代码难以被提炼,应该尽可能把他们替换为查询式。

3.5 Introduce Explaining Variable(引入解释性变量)
有一个复杂的表达式,将该复杂表达式(或其中一部分)的结果放进一个临时变量,以此变量名称解释表达式的用途。
前面提到的都是在尽量消除临时变量,这一条确实引入临时变量。那么,应该在什么时候使用Introduct explaining variable呢?答案是:在Extract Method需要花费更大工作量时。如果要处理的是一个拥有大量局部变量的算法,那么使用Extract method绝非易事。这时候就会使用Introduct explaining variable来清理代码,然后再考虑下一步该怎么办。搞清代码逻辑之后,总是可以运用repalce temp with query把中间引入的解释性变量给去掉。况且,如果最终使用replace method with method object,那么中间引入的那些解释性临时变量也有其价值。

3.6 Split Temporary Variable (分解临时变量)
程序中有某个临时变量被赋值超过一次,它既不是循环变量,也不被用于收集计算结果。那么可以针对每次赋值,创造一个独立,明确的临时变量,而不是每次使用同一个名称的变量。


3.7 Remove Assignment to Parameters (移除对函数参数的赋值)
方法体内对传入参数进行了赋值操作,这时需要以一个临时变量取代该参数的位置。这里说的赋值是指改变了参数的引用,而不是改变引用的对象的值,后者是完全正常合理的操作。


3.8 Replace method with method Object(以函数对象取代函数)
有一个大型函数,其中对局部变量的使用使你无法采用Extract Method,就可以将这个函数放进一个单独的对象中,如此一来局部变量就成了对象内的字段。然后可以在同一个对象中将这个大型函数分解为多个小型函数。也就是新引入了一个class,根据待处理函数的用途为这个类命名,并且建立一个原函数所在的对象的final引用,其他局部变量也都变成这个class的一个域,这个class就只用来承载method的用途。

3.9 Substitute Algorithm(替换算法)
把某个算法替换为另一个更清晰的算法。

解决问题有好几种方法,但其中肯定有些方法比其他的更简单有效。“重构”可以把一些复杂东西分解为较简单的小块,但有时候必须删掉整个算法,代之以较简单的算法。
使用这项重构之前,请先确定自己已经尽可能分解了原先函数。替换一个巨大而复杂的算法是困难的,只有先分解为教简单的小型函数,才能很有把握地进行算法替换工作。

上面我们发现有些方法是完全相反的,所以代码重构是没有固定法则的,很多时候需要我们分析,反复琢磨之后再做决定,怎样才能更容易理解,更容易后面维护。
  • 大小: 55.1 KB
  • 大小: 34.7 KB
  • 大小: 27.7 KB
  • 大小: 159.3 KB
0
1
分享到:
评论

相关推荐

    精通Windows.API-函数、接口、编程实例.pdf

    13.8.3 组合、比较、移动等操作 426 13.8.4 点击测试(Hit Testing) 427 13.8.5 路径的创建与操作 431 13.8.6 路径转换为区域 432 13.8.7 使用区域和路径进行修剪操作,限制输出 432 13.9 坐标变换 438 ...

    C_Pointer.rar_函数指针

    总结,函数指针是C语言中强大的特性,它可以让我们更加灵活地组织代码,提高程序的可扩展性和可维护性。理解并熟练使用函数指针,对于编写高效、简洁的C程序至关重要。通过以上讲解,你应该对C语言中的函数指针有了...

    Ext.js核心函数详解.pdf

    3. `Ext.applyIf(Object obj, Object config)`: 类似于`Ext.apply`,但只将`config`中对象`obj`尚未存在的属性添加到`obj`。这在希望保留已有属性而不覆盖它们时非常有用。 4. `Ext.addBehaviors(Object obj)`: 此...

    javascript函数式编程 underscore.js

    JavaScript函数式编程是一种编程范式,它强调使用函数来组织代码,将计算视为一系列惰性求值的操作。Underscore.js是一个轻量级的JavaScript实用库,它为开发者提供了大量函数式编程工具,使得在JavaScript中实践...

    组态王命令语言函数手册.rar

    2. 性能优化:如何通过合理的代码组织和函数选择,提升程序运行效率,减少资源占用。 总之,《组态王命令语言函数手册》是一本全面深入介绍组态王编程的宝典,对于希望在工业自动化领域使用组态王的开发人员来说,...

    c语言程序设计函数调用PPT课件.pptx

    函数在C语言中扮演着至关重要的角色,允许程序员将代码组织成可重用的模块,以提高代码的可读性和可维护性。以下是关于C语言函数调用的详细解释: 1. **函数的分类:** - **标准函数**,也称库函数,是由系统提供...

    advance_fit.zip_函数拟合

    3. **自定义拟合函数**:如果内置函数不能满足需求,`advance_fit.m`可能包含了用户定义的复杂函数结构。 4. **优化算法**:可能使用MATLAB的内置优化工具箱如`fmincon`或`lsqnonlin`来寻找最佳参数。 5. **结果展示...

    C语言函数大全.rar

    在C语言中,函数是代码组织的基本单元,它封装了一段具有特定功能的代码,可以在程序的不同位置被调用。函数可以接受输入参数,并返回结果,也可以不接受参数,不返回结果,仅仅执行一些操作。下面我们将详细介绍...

    STM32--moban.zip_函数 STM32

    3. `SYSTEM`:可能包含了与系统初始化相关的代码,如时钟配置、NVIC设置等。 4. `CORE`:可能包含了与Cortex-M内核操作相关的低级函数,比如中断服务函数。 5. `OBJ`:通常存放编译后的对象文件,这些文件在链接阶段...

    C语言函数简介.rar

    C语言函数是编程中的基本构建块,它们是...通过这份“C语言函数简介”的文档,你可以学习到如何有效地利用函数来组织和复用代码,提高程序的可读性和可维护性。熟练掌握这些知识点,将对你的C语言编程能力有显著提升。

    C语言常用函数手册.rar

    在C语言中,函数是代码组织的基本单元,它封装了一段可重用的代码,通过函数调用来执行特定任务。以下是一些C语言中常见的函数类别及其详解: 1. 输入/输出函数:如`printf`用于格式化输出,`scanf`用于从标准输入...

    C语言教程课件Ch08函数-3.ppt

    在C语言中,函数是代码组织的基本单位,用于封装特定任务的执行逻辑。第八章主要讲解了关于函数的多个方面: 1. **概述**:函数是C语言中复用代码和模块化编程的关键元素,它允许我们将代码分成独立的、可重复使用...

    matlab--function非常全的-matlab-函数.rar_matlab 函数

    "matlab--function非常全的-matlab-函数.rar"这个压缩包文件显然是一个针对MATLAB函数的全面参考资料,对于初学者或者经验丰富的用户来说,都是提升效率的好工具。下面将详细介绍MATLAB中的函数及其重要性。 1. **...

    C语言函数的定义、声明以及函数的调用方法_c语言函数学习实例_

    在C语言中,函数是程序的...函数帮助我们将代码组织成可重用的部分,参数传递允许我们在函数之间交换数据,而数组作为参数则允许我们处理集合数据。通过熟练掌握这些概念,你可以编写出更加复杂且富有逻辑的C语言程序。

    c 语言函数表(函数用法)

    函数是C语言中的基本构造块,允许我们将代码组织成可重用的模块,方便代码的管理和维护。下面,我们将深入探讨C语言函数的各个方面,以及如何在实际编程中应用这些知识。 1. **函数定义与声明**: - **函数定义**...

    matlab.zip_变异函数_适应度函数_遗传算法 函数

    在提供的“matlab.doc”文档中,可能详细介绍了如何定义上述操作的MATLAB代码,包括如何编写适应度函数、变异函数,以及如何组织遗传算法的主循环。 总的来说,这个MATLAB实现的遗传算法为解决函数最优化问题提供了...

    MFC-20130617_MFC自用_pk函数parasolid_

    2. **自定义函数设计**:学习如何根据项目需求创建和组织自定义的MFC函数,以提高代码复用性和可维护性。 3. **Parasolid集成**:理解Parasolid内核的工作原理,学习如何通过API接口在MFC应用中读取、写入Parasolid...

    19_函数调用模型_主调函数和被调用函数.zip_C语言

    在C语言中,函数是可重用的代码块,它们执行特定任务并...通过深入理解函数调用模型,我们可以更好地组织和优化C语言程序,提升程序的效率和可读性。在实际编程中,熟练掌握主调函数和被调函数的交互方式是至关重要的。

    MATLAB-函数帮助文档.zip

    8. **函数文件组织**:MATLAB支持函数文件的组织,例如将相关函数放在同一文件夹下形成函数库。函数文件的命名应避免与内置函数冲突。 9. **调试函数**:MATLAB提供了调试工具,如`dbstop`、`dbstep`和`dbquit`,...

    c/c++函数大全(标准函数)

    在C/C++编程语言中,函数是代码组织的基本单元,它们允许我们将一组特定任务封装到一个可重用的模块中。C/C++函数大全通常包括了各种标准库提供的函数,这些函数涵盖了输入/输出、数学运算、字符串处理、内存管理等...

Global site tag (gtag.js) - Google Analytics