读书报告之《修改代码的艺术》 (II)
2014-09-05 23:39
281 查看
今天继续从本书的第二章学习,
昨天我们已经总结了下面三个内容
今天继续第四点
所以测试时,只要在汇点这个地方解开依赖就可以了。
Ø 列表型。一般是长长的switchcase或者很多的处理步骤。
Ø 锯齿型。一般是复杂的ifelse多重嵌套。这种代码很难提炼方法,需要小心。
对列表型的巨型方法,其逻辑总体还是清晰的,可以通过将每一个列表项提炼出单独的方法,从而将巨型方法瘦身。
对锯齿型的巨型方法,其逻辑一般来说就有点反人类了。原书中没给出什么有意义的内容,这里就以自己的切身体会举几个具体的例子。
在正式举例之前,先引用一些大牛的作品, 以免显得井底之蛙。《重构》一书中的关于简化条件表达式的一章,绝对不容错过。然后《effective java》一书中也有关于if else的简化。然后是这篇博文if/else的使用心得。这些都是非常基础的内容,看似直白,其实却是代数中的交换律、结合律、分配律,是大智若愚,是各种技巧的基础。
合并分支。有些分支的执行内容相同,往往意味着可以合并为一个分支
扁平化。基本原理如下
好了,唠嗑就到这。下面第一个例子,这是一个按分数计算成绩等级的方法,也就是分为A,B, C, D, E五个等级。好有熟悉感啊
这个例子是从网上随便搜的一个例子,在改动之前不得不吐槽一下(好像每次拿到别人写得代码时总是不自觉的会这样
) : 这么简单的程序也能写得如此复杂,实在不知道是该夸你还是贬你?
采用扁平化策略,先化简if (score < 80)这个分支。逻辑条件很容易出错,这里建议亦步亦趋的做。先按照扁平化的公式,做一个形式上的变形。
这里我不急着化简if (score < 80 && score < 70)中的逻辑条件,也不急着处理if (score < 80 && score < 70)分支中的内容。 同样,我也不急着处理新增的else
if (score < 80 && !(score < 70))分支,而且这个分支的内容我也只是复制原始分支中的内容。记住,这样做是绝对等价的,因而到目前为止的改动,虽然代码变化很大,但实际上是相当安全的。
接下来,化简if (score < 80 && score < 70) ==> if (score < 70), 同时化简这个分支中的执行代码,实际只要去掉永远不会被执行的语句就可以了
if (score < 80&& score < 70) { ==> if(score< 70)
if (score < 70) { // 这个条件已经没必要了
if (score < 60) {
return"E";
}else{
return"D";
}
}else{
return"C"; // 这个分支永远不会被执行
}
......
对 else if (score < 80 && !(score < 70)这个分支也做同样的简化,于是代码就变成这个样子
最后,else if (score < 70 && score >= 60) 这个条件也是有化简的余地 .因为只有在if (score < 60)不成立时,才会判断这条语句,这就意味着score >=60必然成立,所以可以简化为else if(score < 70)
以上是最终代码,与开始的代码比较,一切的言语和解释都是多余的
最后说一下,这个例子的原始代码 作者愿意是为了性能优化,因为一般情况下,成绩分布总是80分以下占大部分,所以这样写成这样,可以减少条件判断的次数。简单说来就是借用一下霍夫曼编码的思想。这里我只能呵呵了, 直接摘录《C++编程规范》一书中的一节内容:
不要进行不成熟的优化。 优化的第一原则:不要优化。 第二原则(仅适用于专家,不是砖家哦):还是不要优化。再三测试,而后优化。
正确、简单和清晰第一。简单就是美:正确优于速度;简单优于复杂;清晰由于技巧;安全优于不安全
为了这点性能,有必要把程序写成这样吗?难道就没有更好的方法,显然不是了
昨天我们已经总结了下面三个内容
1. 降低修改的风险
2. 需要修改大量相同的代码
3. 时间紧迫,必须修改
今天继续第四点4. 修改时应当测试哪些方法
作者提出了影响结构图的概念。说穿了,就是CallRelation和ReferenceRelation,就是查看某个方法(变量)被哪些方法引用,以及自身又引用了哪些方法,依次类推。这个复杂的关系网实际就是一颗风险评估树(图)。通过这棵树,我们可以知道某个修改会影响到哪些节点。这项参数,既是风险的直接量化指标,同时又是验证修改的测试指标。这是很朴素的思想,不管有意无意,你肯定已经在这么做了,不要告诉我你的boss从来没问过你这样的问题:“这个修改有风险吗?”。5. 多处修改是否将所有相关类解依赖
实际还是上面的问题,上面的风险评估树(图),不同的节点,地位是不一样的。有些节点就显得特别关键,其中,作者归纳了一种叫汇点的概念。汇点就是所有的修改的影响都能从这个点感知,所以只要针对这个点测试就足够了,没必要满大街的测试了。打个比方就是医学上所谓的全息部位,人的耳朵就是人身上的一个全息点,身体的其他部位有任何毛病,都能在耳朵上看出来。所以测试时,只要在汇点这个地方解开依赖就可以了。
6. 修改巨型方法
作者举例了两种常见的巨型方法样式Ø 列表型。一般是长长的switchcase或者很多的处理步骤。
Ø 锯齿型。一般是复杂的ifelse多重嵌套。这种代码很难提炼方法,需要小心。
对列表型的巨型方法,其逻辑总体还是清晰的,可以通过将每一个列表项提炼出单独的方法,从而将巨型方法瘦身。
对锯齿型的巨型方法,其逻辑一般来说就有点反人类了。原书中没给出什么有意义的内容,这里就以自己的切身体会举几个具体的例子。
在正式举例之前,先引用一些大牛的作品, 以免显得井底之蛙。《重构》一书中的关于简化条件表达式的一章,绝对不容错过。然后《effective java》一书中也有关于if else的简化。然后是这篇博文if/else的使用心得。这些都是非常基础的内容,看似直白,其实却是代数中的交换律、结合律、分配律,是大智若愚,是各种技巧的基础。
化简复杂的if else语句,基本的手段就两个:
针对头重脚轻的if else,使用return快速返回,从而减少嵌套层数。合并分支。有些分支的执行内容相同,往往意味着可以合并为一个分支
扁平化。基本原理如下
if (expr1) { if (expr2) { // do something 1 } else { // do something 2 } } else { if (expr3) { // do something 3 } else { // do something 4 } }必然等价于
if (expr1 && expr2) { // do something 1 } else if (expr1 && !expr2) { // do something 2 } else if (expr3) { // do something 3 } else { // do something 4 }
好了,唠嗑就到这。下面第一个例子,这是一个按分数计算成绩等级的方法,也就是分为A,B, C, D, E五个等级。好有熟悉感啊
/** * 按成绩排等级:90分以上A, 80-90 B, 70-80 C, 60-70 D, 60以下 E * @param score * @return string of degree, such as A, B, C, D, E */ String degree(int score) { if (score < 80) { if (score < 70) { if (score < 60) { return "E"; } else { return "D"; } } else { return "C"; } } else { if (score < 90) { return "B"; } else { return "A"; } } }
这个例子是从网上随便搜的一个例子,在改动之前不得不吐槽一下(好像每次拿到别人写得代码时总是不自觉的会这样
) : 这么简单的程序也能写得如此复杂,实在不知道是该夸你还是贬你?
采用扁平化策略,先化简if (score < 80)这个分支。逻辑条件很容易出错,这里建议亦步亦趋的做。先按照扁平化的公式,做一个形式上的变形。
String degree(int score) { if (score < 80 && score < 70) { if (score < 70) { if (score < 60) { return "E"; } else { return "D"; } } else { return "C"; } } else if (score < 80 && !(score < 70)){ if (score < 70) { if (score < 60) { return "E"; } else { return "D"; } } else { return "C"; } } else {
这里我不急着化简if (score < 80 && score < 70)中的逻辑条件,也不急着处理if (score < 80 && score < 70)分支中的内容。 同样,我也不急着处理新增的else
if (score < 80 && !(score < 70))分支,而且这个分支的内容我也只是复制原始分支中的内容。记住,这样做是绝对等价的,因而到目前为止的改动,虽然代码变化很大,但实际上是相当安全的。
接下来,化简if (score < 80 && score < 70) ==> if (score < 70), 同时化简这个分支中的执行代码,实际只要去掉永远不会被执行的语句就可以了
if (score < 80&& score < 70) { ==> if(score< 70)
if (score < 70) { // 这个条件已经没必要了
if (score < 60) {
return"E";
}else{
return"D";
}
}else{
return"C"; // 这个分支永远不会被执行
}
......
对 else if (score < 80 && !(score < 70)这个分支也做同样的简化,于是代码就变成这个样子
String degree(int score) { if (score < 70) { if (score < 60) { return "E"; } else { return "D"; } } else if (score < 80 && score >= 70){ return "C"; } else { if (score < 90) { return "B"; } else { return "A"; } } }继续扁平化,最终就变成
String degree(int score) { if (score < 60) { return "E"; } else if (score < 70 && score >= 60) { return "D"; } else if (score < 80 && score >=70){ return "C"; } else if (score < 90){ return "B"; } else { return "A"; } }
最后,else if (score < 70 && score >= 60) 这个条件也是有化简的余地 .因为只有在if (score < 60)不成立时,才会判断这条语句,这就意味着score >=60必然成立,所以可以简化为else if(score < 70)
String degree(int score) { if (score < 60) { return "E"; } else if (score < 70) { return "D"; } else if (score < 80){ return "C"; } else if (score < 90){ return "B"; } else { return "A"; } }
以上是最终代码,与开始的代码比较,一切的言语和解释都是多余的
最后说一下,这个例子的原始代码 作者愿意是为了性能优化,因为一般情况下,成绩分布总是80分以下占大部分,所以这样写成这样,可以减少条件判断的次数。简单说来就是借用一下霍夫曼编码的思想。这里我只能呵呵了, 直接摘录《C++编程规范》一书中的一节内容:
不要进行不成熟的优化。 优化的第一原则:不要优化。 第二原则(仅适用于专家,不是砖家哦):还是不要优化。再三测试,而后优化。
正确、简单和清晰第一。简单就是美:正确优于速度;简单优于复杂;清晰由于技巧;安全优于不安全
为了这点性能,有必要把程序写成这样吗?难道就没有更好的方法,显然不是了
相关文章推荐
- 读书报告之《修改代码的艺术》 (II)续
- 读书报告之《修改代码的艺术》 (I)
- 读书报告之《修改代码的艺术》 (II)续2
- hdu 1023 Train Problem II 高精训练
- [LeetCode]132 Palindrome Partitioning II
- leetcode-Path Sum II
- 119. Pascal's Triangle II
- SPOJ Count on a tree II(树上莫队)
- HDOJ 1027 Ignatius and the Princess II
- [LeetCode#95]Unique Binary Search Trees II
- LightOj1245 --- Harmonic Number (II)找规律
- SPOJ 1812 Longest Common Substring II(后缀自动机)
- Lintcode70 Binary Tree Level Order Traversal II solution 题解
- Remove Duplicates from Sorted Array II
- Palindrome Partitioning II
- [LintCode] Continuous Subarray Sum II
- Java小程序之高级画板重绘篇II
- leetcode题解-28. Implement strStr() && 521. Longest Uncommon Subsequence I && 522 II
- 线段树合集 II
- [leetcode解题记录]Jump Game和Jump Game II