`

何时提炼函数 & 用查询取代临时变量

 
阅读更多

拥有[短函数」(short methods)的对象会活得比较好、比较长。不熟悉面向对象技术的人,常常觉得对象程序中只有无穷无尽的delegation(委托),根本没有进行任何计算。

  

我们遵循这样一条原则:每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名。我们可以对一组或甚至短短一行代码做这件事。哪怕替换后的函数调用动作比函数自身还长,只要函数名称能够解释其用途,我们也该毫不犹豫地那么做。关键不在于函数的长度,而在于函数「做什么」和「如何做」之间的语义距离。

   

如何确定该提炼哪一段代码昵? 一个很好的技巧是:寻找注释。它们通常是指出「代码用途和实现手法间的语义距离」的信号。如果代码前方有一行注释,就是在提醒你:可以将这段代码替换成一个函数,而且可以在注释的基础上给这个函数命名。就算只有一行代码,如果它需要以注释来说明,那也值得将它提炼到独立函数去。

 

以查询取代临时变量  

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

 

方法步骤:

1:找出只被赋值一次的临时变量(如果某个临时变量被赋值超过一次,考虑用split temporary variable将它分割)

2:将临时变量声明为final。(确保变量只是被赋值一次)

3:编译。

4:将对该临时变量赋值的语句等号右侧部分提炼到一个独立函数中。(声明为private,确保这个函数不修改任何的对象内容)

5:在该临时变量身上实施用查询取代临时变量。

  

我们常常使用临时变量保存循环中的累加信息。在这种情况下,整个循环都可以被提为一个独立函数,这也使原本的函数可以少掉几行扰人的循环码。有时候,你可能会用单一循环累加好几个值,就像本书p.26的例子那样。这种情况下你应该针对每个累加值重复一遍循环,这样就可以将所有临时变量都替换为查询式(query)。

   

Example

1   原来代码

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

   

首先把临时变量声明为final,检查是否只是被赋值一次。

double getPrice() { 
    final int basePrice = _quantity * _itemPrice; 
    final double discountFactor; 
    
    if (basePrice > 1000) {
        discountFactor = 0.95; 
    } else {
        discountFactor = 0.98; 
    }
    
    return basePrice * discountFactor; 
} 
  

 

这样一来,如果有任何问题,编译器就会警告我

  

下面一步步来:

首先把basePrice右边的提取到一个函数,然后if里面的引用这个变量的点,改为调用这个函数:

 

double getPrice() { 
    final int basePrice = basePrice(); 
    final double discountFactor; 
    
    if (basePrice() > 1000) {
        discountFactor = 0.95; 
    } else {
        discountFactor = 0.98; 
    }
    
    return basePrice * discountFactor; 
} 
 

 

private int basePrice() { 
    return _quantity * _itemPrice; 
} 

 

 

最后的return语句是对于这个变量的最后一个引用点,所以把临时变量移除,然后改为调用方法:

double getPrice() { 
    final double discountFactor; 
    
    if (basePrice() > 1000) {
        discountFactor = 0.95; 
    } else {
        discountFactor = 0.98; 
    }
    
    return basePrice() * discountFactor; 
} 

    

同理提炼discountFactor,最后函数变为:

 

double getPrice() { 
    return basePrice() * discountFactor(); 
} 
 

 

非常简练了了!!

 

 

19
4
分享到:
评论
7 楼 pywepe 2012-02-19  
  楼主的文章拷贝自 重构

重构一书很强调提炼函数,不过出经常提到物必反的深刻道理,还得自己权衡.
6 楼 五点晨曦 2012-02-18  
函数嵌套得太多一样很麻烦的,我也不喜欢一句话函数。我提取函数的标准是某段代码在两个或以上的地方出现过
5 楼 zui4yi1 2012-02-17  
面向过程有面向过程的优点,面向对象有面向对象的优点。

把参数都提出来,相当于面向对象的思想。虽然我是搞JAVA的,不过我不喜欢一句话的函数,起名字都要累坏。
4 楼 greatghoul 2012-02-17  
greatghoul 写道
觉得没有提炼之前更容易理解一些吧。

不过你介绍的一些方法还是值得一试的
3 楼 greatghoul 2012-02-17  
觉得没有提炼之前更容易理解一些吧。
2 楼 hubeen 2012-02-17  
没看出这样做有什么意义。太多方法调用反而影响可读性和运行速度。求指教
1 楼 j2ee_dll 2012-02-16  
nice,受教了!

相关推荐

    重构改善既有代码的设计第2版.pdf

    6. 第一组重构:包括提炼函数、内联函数、提炼变量、内联变量、改变函数声明、封装变量、变量改名、引入参数对象、函数组合成类、函数组合成变换、拆分阶段等。 7. 封装:包括封装记录、封装集合、以对象取代基本...

    重构_改善既有代码的设计

     6.1 ExtractMethod(提炼函数)110  6.2 InlineMethod(内联函数)117  6.3 InlineTemp(内联临时变量)119  6.4 ReplaceTempwithQuery(以查询取代临时变量)120  6.5 IntroduceExplainingVariable(引入解释...

    book-refactoring2-code:《重构 改善既有代码的设计第二版》中示例代码

    book-refactoring2-code 存储 《重构: 改善既有代码的设计第二版》的一些示例代码 单元测试 使用 作为我们单元测试套件 ...play 变量可以由 performance 变量计算得到, 以查询取代临时变量 内联变量: 使用 pla

    重构:改善既有代码的设计(中文版).

    6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 IntroduceExplainingVariable(引入解释性变量)...

    重构:改善既有代码的设计(中文高清版)

    6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 IntroduceExplainingVariable(引入解释性变量)...

    重构-改善既有代码的设计 中文版

    6.1 Extract Method(提炼函数) 6.2 Inline Method(将函数内联化) 6.3 Inline Temp(将临时变量内联化) 6.4 Replace Temp With Query(以查询取代临时变量) 6.5 Introduce Explaining Variable(引入解释性变量...

    重建——改善既有代码的设计

    6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 IntroduceExplainingVariable(引入解释性变量)...

    重构-改善既有代码的设计

    6.1 Extract Method(提炼函数) 110 6.2 Inline Method(内联函数) 117 6.3 Inline Temp(内联临时变量) 119 6.4 Replace Temp with Query(以查询取代临时变量) 120 6.5 Introduce Explaining ...

    《重构改善既有代码的设计(2010年版)》(Martin Fowler[美] 著,熊节 译)

    6.1 ExtractMethod(提炼函数)110 6.2 InlineMethod(内联函数)117 6.3 InlineTemp(内联临时变量)119 6.4 ReplaceTempwithQuery(以查询取代临时变量)120 6.5 IntroduceExplainingVariable(引入解释性变量)...

    重构:改善既有代码的设计.[美]Martin Fowler.epub【文字版手机格式】

    6.1 Extract Method(提炼函数) 6.2 Inline Method(内联函数) 6.3 Inline Temp(内联临时变量) 6.4 Replace Temp with Query(以查询取代临时变量) 6.5 Introduce Explaining Variable(引入解释性变量) 6.6 Split...

    重构代码笔记1

    过长参数列表(Long Parameter List)可以通过引入参数对象(Introduce Parameter Object)或者以查询取代参数来解决,减少函数调用时的负担,提高可读性。 全局数据(Global Data)和可变数据(Mutable Data)可能...

    C语言须知提问

    C语言的编写需要遵循一定的规则,包括变量声明、函数定义、表达式的使用等。良好的编程习惯有助于提高代码的可读性和维护性。 #### 5. C语言与其它语言的区别 与其他高级语言相比,C语言更接近底层硬件,因此在性能...

    产品中的代码重构.pdf

    1. **提炼函数**:将过长或难以理解的代码段提取成独立的函数,提高代码的可读性。重构前后对比显示,长函数被拆分成多个小函数,每个函数都有明确的职责。 2. **引入解释性变量**:将复杂表达式的结果存储到临时...

    2015春14级面向对象程序设计实验指导书.pdf

    - 代码片段使用了iostream.h头文件,这是一个包含标准输入输出流对象和函数的头文件,虽然在现代C++中已被iostream所取代。 - 函数add是一个简单的整数加法函数,该函数接收两个int类型的参数,并返回它们的和。 ...

    php面试题目及答案

    根据提供的文件信息,以下是从标题、描述、以及部分问题中提炼出的相关IT知识点: ### PHP面试题目及答案 #### 基础题知识点 **1. 表单中GET与POST提交方法的区别** - **GET**:通过URL参数传递信息进行接收。...

    More effective C++

    7. **考虑用运算符的赋值形式(OP=)取代其单独形式(OP)** - 在许多情况下,使用复合赋值运算符(如 +=, -= 等)可以提高代码的效率和可读性。 8. **考虑变更程序库** - 有时候,更换更高效或更适合当前需求的...

    软件工程中的代码重构与性能优化方法.pptx

    - **以查询取代临时变量**:使用查询函数替换含义明确的变量,增强代码清晰度。 - **以管道取代循环**:利用函数式编程的管道操作符代替循环结构,简化代码流程。 **代码重构的工具** - **IntelliJ IDEA** - **...

Global site tag (gtag.js) - Google Analytics