第三章和第六章代码大坏味道 函数过长&Extract Method (1)
2011-12-19 17:04
253 查看
1:重复的代码(不仅仅是函数里,还有类之间)
Extract Method是我最常用的重构手法之一。当我看见一个过长的函数或者一段需要注释才能让人理解用途的代码,我就会将这段代码放进一个独立函数中。
有数个原因造成我喜欢简短而有良好命名的函数。首先,如果每个函数的粒度都很小(finely grained),那么函数之间彼此复用的机会就更大;其次,这会使高层函数码读起来就像一系列注释;再者,如果函数都是细粒度,那么函数的覆写(overridden)也会更容易些。
而且只有当你能给小型函数很好地命名时,它们才能真正起作用,所以你需要在函数名称下点功夫。人们有时会问我,一个函数多长才算合适?在我看来,长度不是问题,关键在于函数名称和函数本体之间的语义距离(semantic distance )。如果提炼动作 (extracting )可以强化代码的清晰度,那就去做,就算函数名称比提炼出来的代码 还长也无所谓。
(有点累了,明天再看。)
继续:
1:原来的代码
再往下走,打印details的两条语句用到了一个局部变量outstanding。那么提炼为一个带一个参数的函数,最后变为:
看上面的printOwing函数,计算变量值的那一段代码也可以提炼出来。只不过这个代码里面对于局部变量outstanding赋值了,所以要在提炼出来的方法里声明一个变量作为返回值:
因为Enumeration变量只是在提炼出来的代码中用到,所以整个搬到新函数里,这样的话,看printOwing这个函数,里面只是说明每一步做什么了,非常清晰。
如果outstanding这个变量不是明确的初始化为一个值,而是调用了其它的变量,那么就作为一个参数传进来。
然后再整理下,得到下面的精简的函数:
综上,如果一个函数过于复杂,那么就运用这个方法进行提炼,记住,一个函数最好只是实现一个功能。
Extract Method是我最常用的重构手法之一。当我看见一个过长的函数或者一段需要注释才能让人理解用途的代码,我就会将这段代码放进一个独立函数中。
有数个原因造成我喜欢简短而有良好命名的函数。首先,如果每个函数的粒度都很小(finely grained),那么函数之间彼此复用的机会就更大;其次,这会使高层函数码读起来就像一系列注释;再者,如果函数都是细粒度,那么函数的覆写(overridden)也会更容易些。
而且只有当你能给小型函数很好地命名时,它们才能真正起作用,所以你需要在函数名称下点功夫。人们有时会问我,一个函数多长才算合适?在我看来,长度不是问题,关键在于函数名称和函数本体之间的语义距离(semantic distance )。如果提炼动作 (extracting )可以强化代码的清晰度,那就去做,就算函数名称比提炼出来的代码 还长也无所谓。
(有点累了,明天再看。)
继续:
1:原来的代码
void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; // print banner System.out.println ("**************************"); System.out.println ("***** Customer Owes ******"); System.out.println ("**************************"); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } //print details System.out.println ("name:" + _name); System.out.println ("amount" + outstanding); }这个方法原来是这个样子的,按照作者的说法,不在乎多少代码,而是在于函数之间的语义的距离,所以,首先把打印banner语句提炼出来。
void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } //print details System.out.println ("name:" + _name); System.out.println ("amount" + outstanding); } void printBanner() { // print banner System.out.println ("**************************"); System.out.println ("***** Customer Owes ******"); System.out.println ("**************************"); }
再往下走,打印details的两条语句用到了一个局部变量outstanding。那么提炼为一个带一个参数的函数,最后变为:
void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); } void printDetails (double outstanding) { System.out.println ("name:" + _name); System.out.println ("amount" + outstanding); }
看上面的printOwing函数,计算变量值的那一段代码也可以提炼出来。只不过这个代码里面对于局部变量outstanding赋值了,所以要在提炼出来的方法里声明一个变量作为返回值:
void printOwing() { printBanner(); double outstanding = getOutstanding(); printDetails(outstanding); } double getOutstanding() { Enumeration e = _orders.elements(); double outstanding = 0.0; while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } return outstanding; }
因为Enumeration变量只是在提炼出来的代码中用到,所以整个搬到新函数里,这样的话,看printOwing这个函数,里面只是说明每一步做什么了,非常清晰。
如果outstanding这个变量不是明确的初始化为一个值,而是调用了其它的变量,那么就作为一个参数传进来。
void printOwing(double previousAmount) { double outstanding = previousAmount * 1.2; printBanner(); outstanding = getOutstanding(outstanding); printDetails(outstanding); } double getOutstanding(double initialValue) { double result = initialValue; Enumeration e = _orders.elements(); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); result += each.getAmount(); } return result; }
然后再整理下,得到下面的精简的函数:
void printOwing(double previousAmount) { printBanner(); double outstanding = getOutstanding(previousAmount * 1.2); printDetails(outstanding); }
综上,如果一个函数过于复杂,那么就运用这个方法进行提炼,记住,一个函数最好只是实现一个功能。
相关文章推荐
- 【重构】 代码的坏味道总结 Bad Smell (一) (重复代码 | 过长函数 | 过大的类 | 过长参数列 | 发散式变化 | 霰弹式修改)
- 【重构】 代码的坏味道总结 Bad Smell (一) (重复代码 | 过长函数 | 过大的类 | 过长参数列 | 发散式变化 | 霰弹式修改)
- 代码的坏味道之二 :Long Method(过长函数)
- 代码的坏味道02:过长函数(Long Method)
- 【整理】【代码的坏味道】过长函数(Long Method)
- 重构 之 总结代码的坏味道 Bad Smell (一) 重复代码 过长函数 过大的类 过长参数列 发散式变化 霰弹式修改
- Java String 函数常用操作 & format() 格式化输出,代码详解
- 主动轮廓线模型Snake模型简介&openCV中cvSnakeImage()函数代码分析
- 代码的坏味道04:过长参数列(Long Parameter List)
- 看出笔记-第三章-代码坏味道
- 已安全化的ActiveX控件卸载时出现"DllUnregisterServer函数出错,错误代码:0x80070002"问题解决
- 代码的坏味道之四 :Long Parameter List(过长参数列)
- 代码整洁之道精华——第三章 函数
- 代码中的坏味道-->ruby重构有感(二)--未完待续!
- "Gradient Domain Guided Image Filtering"论文中边缘权重函数matlab实现代码
- 第三章 代码的坏味道(一)
- 第三章 代码的坏味道(二)
- python核心编程第六章题目:python代码实现:设计一个"石头,剪子,布"游戏
- json串中English("")换成Chinese(“”)函数代码
- 重构代码坏味道(优雅,little code) <下>