- 浏览: 68921 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
bo_hai:
assembly:single 不包含源代码,只包含依赖的cl ...
关于创建可执行的jar文件 -
lsy:
相当详细的好文!
关于创建可执行的jar文件 -
steven0lisa:
学习了。不过在有动态代码生成的项目中,就要谨慎用了。
Hide Method(隐藏方法) -
steven0lisa:
好久没看源代码了,没记错的话,因为是由以下原因造成的:1.ke ...
编码最佳实践系列之二 -
steven0lisa:
最后一点确实很有艺术,学习了~~~
编码最佳实践系列之一
WHAT
在循环中,一次循环做了两件事情,将循环分解,重复这个循环,每次只做一件事情
潜在问题:性能问题,如果遇到性能问题,先让代码清晰可读,让你更快找到性能优化点,再做优化
本次重构涉及的基本重构较多,主要有:
- Split Loop(分解循环)
- Extract Method(提炼方法)
- Inline Temp(内联临时变量)
- Replace Temp With Query(用查询函数代替临时变量)
- Rename Temp(重命名临时变量)
- Split Temporary Variable(分解临时变量)
HOW
重构前的代码清单
Student类是一个哑对象,表示一个学生,有年龄(age)和成绩(grade)两个属性
package split.loop; public class Student { /** * 年龄 */ private int age; /** * 成绩 */ private int grade; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getGrade() { return grade; } public void setGrade(int grade) { this.grade = grade; } }
下面方法printValues(),用于计算学生们的平均年龄和总成绩
package split.loop; public class SomeClass { private Student[] students; void printValues() { double averageAge = 0; // 平均年龄 int totalGrade = 0; // 总成绩 for (int i = 0; i < students.length; i++) { averageAge += students[i].getAge(); totalGrade += students[i].getGrade(); } averageAge = averageAge / students.length; System.out.println(averageAge); System.out.println(totalGrade); } }
重构步骤
- (手动)拷贝for循环语句,并除掉各自不相干部分代码,重构后的代码清单
package split.loop; public class SomeClass { private Student[] students; void printValues() { double averageAge = 0; // 平均年龄 int totalGrade = 0; // 总成绩 for (int i = 0; i < students.length; i++) { averageAge += students[i].getAge(); } for (int i = 0; i < students.length; i++) { totalGrade += students[i].getGrade(); } averageAge = averageAge / students.length; System.out.println(averageAge); System.out.println(totalGrade); } }
- (手动)重新组织语句,让语义相近(for循环中使用到的局部变量)的语句放在一组,为其他重构做好准备,重构后的代码清单
package split.loop; public class SomeClass { private Student[] students; void printValues() { double averageAge = 0; // 平均年龄 for (int i = 0; i < students.length; i++) { averageAge += students[i].getAge(); } averageAge = averageAge / students.length; int totalGrade = 0; // 总成绩 for (int i = 0; i < students.length; i++) { totalGrade += students[i].getGrade(); } System.out.println(averageAge); System.out.println(totalGrade); } }
延伸重构
- 本次重构,到此本应该结束,但是,我们还可以继续重构,让代码更优雅。我们观察到,上述代码清单中,printValues方法仍旧很长,到处充满了局部解释性变量(令人疑惑的东西),可以使用Replace Temp with Query(用查询函数代替临时变量,其实这个重构手法应用了两个基本的重构手法:Extract Method(提炼方法)和Inline Temp(内联临时变量)),我们可以一步步来操作
- 首先处理临时变量:averageAge,对上一组方法 Extract Method(提炼方法),使用快捷键(Alt + Shift +M)或者上下文菜单(Refactor -> Extract Method...),这里 averageAge ,在for循环前初始化,并在for循环中赋值,最后在for循环结束后,再次赋值。因此我们选中for循环以及前后语句,一起提炼,并给方法取个好名字( averageAge ,这个方法是干什么的),提炼后的代码清单
package split.loop; public class SomeClass { private Student[] students; void printValues() { double averageAge = averageAge(); int totalGrade = 0; // 总成绩 for (int i = 0; i < students.length; i++) { totalGrade += students[i].getGrade(); } System.out.println(averageAge); System.out.println(totalGrade); } private double averageAge() { double averageAge = 0; // 平均年龄 for (int i = 0; i < students.length; i++) { averageAge += students[i].getAge(); } averageAge = averageAge / students.length; return averageAge; } }
-
- 接下来,处理新提炼出来的方法averageAge,按照惯例,我们把方法的返回值命名为result,使用快捷键(Alt + Shit + R)或者上下文菜单(Refactor > Rename ...),改名之后,直接回车即可,代码清单
package split.loop; public class SomeClass { private Student[] students; void printValues() { double averageAge = averageAge(); int totalGrade = 0; // 总成绩 for (int i = 0; i < students.length; i++) { totalGrade += students[i].getGrade(); } System.out.println(averageAge); System.out.println(totalGrade); } private double averageAge() { double result = 0; // 平均年龄 for (int i = 0; i < students.length; i++) { result += students[i].getAge(); } result = result / students.length; return result; } }
-
- 在往下,这里又涉及到一个问题,就是对局部变量赋值了多次,这时,需要应用Split Temporary Variable(手动操作,在第二次赋值的地方,重新声明变量,并更新接下来的引用),重构后的代码清单
package split.loop; public class SomeClass { private Student[] students; void printValues() { double averageAge = averageAge(); int totalGrade = 0; // 总成绩 for (int i = 0; i < students.length; i++) { totalGrade += students[i].getGrade(); } System.out.println(averageAge); System.out.println(totalGrade); } private double averageAge() { double result = 0; // 平均年龄 for (int i = 0; i < students.length; i++) { result += students[i].getAge(); } double result1 = result / students.length; return result1; } }
-
- 这时,我们注意到,result1变量只被赋值一次,我们将它内联,应用Inline temp (内联临时变量 ),选中变量,使用快捷键(Alt +Shift + I)或者上下文菜单(Refactor > Inline ...) ,重构后的代码清单
package split.loop; public class SomeClass { private Student[] students; void printValues() { double averageAge = averageAge(); int totalGrade = 0; // 总成绩 for (int i = 0; i < students.length; i++) { totalGrade += students[i].getGrade(); } System.out.println(averageAge); System.out.println(totalGrade); } private double averageAge() { double result = 0; // 平均年龄 for (int i = 0; i < students.length; i++) { result += students[i].getAge(); } return result / students.length; } }
-
- 这时,我们回到调用处,发现printValues方法中,averageAge 变量只被赋值一次,我们也把它Inline掉,重构后的代码清单
package split.loop; public class SomeClass { private Student[] students; void printValues() { int totalGrade = 0; // 总成绩 for (int i = 0; i < students.length; i++) { totalGrade += students[i].getGrade(); } System.out.println(averageAge()); System.out.println(totalGrade); } private double averageAge() { double result = 0; // 平均年龄 for (int i = 0; i < students.length; i++) { result += students[i].getAge(); } return result / students.length; } }
- 接下来,同样方法处理这个变量:totalGrade
- 首先,提炼方法,并重名返回结果变量名
package split.loop; public class SomeClass { private Student[] students; void printValues() { int totalGrade = totalGrade(); System.out.println(averageAge()); System.out.println(totalGrade); } private double averageAge() { double result = 0; // 平均年龄 for (int i = 0; i < students.length; i++) { result += students[i].getAge(); } return result / students.length; } private int totalGrade() { int result = 0; // 总成绩 for (int i = 0; i < students.length; i++) { result += students[i].getGrade(); } return result; } }
-
- 在调用处,inline临时变量totalGrade,重构后的的代码清单
package split.loop; public class SomeClass { private Student[] students; void printValues() { System.out.println(averageAge()); System.out.println(totalGrade()); } private double averageAge() { double result = 0; // 平均年龄 for (int i = 0; i < students.length; i++) { result += students[i].getAge(); } return result / students.length; } private int totalGrade() { int result = 0; // 总成绩 for (int i = 0; i < students.length; i++) { result += students[i].getGrade(); } return result; } }
- 这时,代码已经相当清晰了,我们不需要看方法注释,以及方法内部实现,就可以知道printValues这个方法做了哪些事情,这就是重构的魅力,小步慢跑,一步一前进,但是,最最重要的前提是:我们在重构之前,必须有一个运行良好且速度较快的单元测试,让我们在测试、编码、重构不断地切换角色,更换帽子
总结
本重构虽然很简单,一些很小的改动,能够使代码可读性更强,更易维护,希望本实践对你有益,希望大家和我一起动手做重构,也希望你提出宝贵意见或反馈
发表评论
-
Encapsulate Classes with Factory(用工厂封装类)
2012-09-09 16:57 0TODO -
Compose Method(组合方法)
2012-09-09 16:55 0就是Extract Method()的运用 -
Chain Constructors(链构造函数)
2012-09-09 16:53 0同一个类中的各个构造函数,存在重复代码 做法 -
Substitute Algorithm(替换算法)
2012-09-09 14:30 0Substitute Algorithm -
Split Temporary Variable(分解临时变量)
2012-09-09 14:29 0Split Temporary Variable -
Separate Query from Modifier(将查询方法与修改方法分离)
2012-09-09 14:28 0Separate Query from Modifier ... -
Self Encapsulate Field(自封装字段)
2012-09-09 14:27 0Self Encapsulate Field -
Reverse Conditional(颠倒条件表达式)
2012-09-11 00:00 1224WHAT 如果只有一个then,而没有else的分支条件表达 ... -
Replace Type Code with Subclasses(用子类代替类型码)
2012-09-09 14:25 0Replace Type Code with Subcl ... -
Replace Type Code with State/Strategy(用 State/Strategy代替类型码)
2012-09-09 14:24 0State/Strategy -
Replace Type Code with Class(用类代替类型码)
2012-09-09 14:23 0Replace Type Code with Class ... -
Replace Temp with Query(用查询方法代替临时变量)
2012-09-09 14:23 0Replace Temp with Query -
Replace Subclass with Fields(用字段代替子类)
2012-09-09 14:22 0Replace Subclass with Fields ... -
Replace Static Variable with Parameter(用参数代替静态变量)
2012-09-09 14:21 0Replace Static Variable with ... -
Replace Recursion with Iteration(用迭代代替递归)
2012-09-09 14:20 0Replace Recursion with Itera ... -
Replace Record with Data Class(用数据类代替记录)
2012-09-09 14:19 0Replace Record with Data Cla ... -
Replace Parameter with Method(用方法代替参数)
2012-09-09 14:19 0Replace Parameter with Metho ... -
Replace Parameter with Explicit Methods(用显示方法代替参数)
2012-09-09 14:18 0Replace Parameter with Expli ... -
Replace Nested Conditional with Guard Clauses(用守卫语句代替嵌套条件语句)
2012-09-09 14:17 0Replace Nested Conditional w ... -
Replace Method with Method Object(用方法对象代替方法)
2012-09-09 14:16 0Replace Method with Method O ...
相关推荐
经验模态分解(Empirical Mode Decomposition,简称EMD)是一种强大的数据分析技术,尤其适用于处理非线性、非平稳信号。EMD由Nasa的科学家Hilbert和Huang在1998年提出,其核心思想是将复杂的信号自适应地分解为一...
本实验利用MATLAB2015进行编程,调用系统小波函数对信号进行分解,实现Mallat分解与重构算法对一维信号进行多层分解和重构。对信号进行多层分解可实现对信号的去噪和数据压缩处理,分解为小波函数的线性组合,阶数高...
标题中的"【EMD重构】.rar"指的是包含EMD重构过程的压缩文件,而"EMD重构函数"是指在处理EMD分解后的IMF分量时使用的特定函数。"IMF变量重构"则是指将分解得到的各个IMF重新组合成原始信号的过程。"tomorrowi4n"可能...
在这个主题中,"POD.rar_POD 重构_POD正交分解_we75t_本征正交分解_流场重构" 提到了一种名为“主成分分析”(Principal Component Analysis,PCA)在流体力学中的应用,通常称为“正交分解”(Proper Orthogonal ...
四层分解,低频重构小波db4分解与重构.zip 小波db4分解与重构,四层分解,低频重构小波db4分解与重构.zip 小波db4分解与重构,四层分解,低频重构小波db4分解与重构.zip 小波db4分解与重构,四层分解,低频重构小波...
eemd分解得到各阶imf分量对信号重构
资源名:用于信号的EMD、EEMD、VMD分解_vmd重构_故障诊断emd_故障诊断_故障重构_VMD信号重构 资源类型:matlab项目全套源码 源码介绍:用于信号的分解、降噪和重构,实现故障诊断 源码说明: 全部项目源码都是经过...
标题中的“用于信号的EMD、EEMD、VMD分解_vmd重构_故障诊断emd_故障诊断_故障重构_VMD信号重构_源码.rar.rar”揭示了该压缩包文件包含的是与信号处理相关的源代码,特别是涉及了三种重要的信号分解方法:Empirical ...
信号的小波分解与重构原理 小波分解是一种信号处理技术,它可以将信号分解成多个分量,每个分量对应一个特定的频率范围。小波分解的主要应用包括信号压缩、去噪、特征提取等。在小波分解中,我们通常使用离散小波...
【标题】:“HHT_HHT变换实例_HHTMATLAB_hht_emd分解重构_EMD分解_”这个标题指的是关于HHT(Hilbert-Huang变换)的一个实际应用案例,使用MATLAB编程语言进行实现。HHT是一种先进的信号处理技术,主要用于非线性、...
基于数字信号的小波包的分解与重构代码,适合初学者学习
如果NMF分解得当,重构后的图像应该与原始图像非常相似,尽管可能会有一些失真。 在计算机视觉领域,NMF的应用广泛,包括但不限于: 1. 图像分类:通过提取图像的非负特征,可以用于分类任务。 2. 图像去噪:NMF...
与分解类似,重构同样需要通过循环来逐步恢复信号,但方向相反。从最底层的细节信号开始,逐步向上合并,最终得到原始信号。重构过程中,信号长度逐渐增加,直至恢复到原始信号长度。 ### 代码解析 给出的代码示例...
小波分解与重构是信号处理领域中的重要技术,它结合了频域分析和时域分析的优势,能够在不同尺度和时间分辨率下对信号进行分析。在本案例中,使用的是db10小波函数进行数据的分解,分解层数达到9层,这允许我们深入...
小波分解和重构是信号处理领域中的重要技术,特别是在图像分析和压缩中有着广泛应用。MATLAB作为一种强大的数学计算和数据分析工具,提供了丰富的函数库来支持小波分析。本程序主要针对MATLAB内置小波函数非2:1抽样...
本文将深入探讨标题和描述中提及的“小波修改”、“傅里叶重构”以及“对信号分解和重构”的概念,并结合快速傅里叶变换(FFT)进行阐述。 首先,让我们了解小波分析。小波分析是一种数学方法,它能够同时在时间和...
在实现一维信号的分解与重构过程中,首先,我们需要对原始信号进行层次分解。这通常包括以下步骤: 1. **分解**:从最高分辨率(原始信号)开始,通过应用Haar小波滤波器,将信号分解为细节(高频)和近似(低频)两...
在这个主题“小波变换分解与重构”中,我们主要关注如何利用小波变换对图像进行模糊处理、噪声添加以及恢复,以及在三级重构过程中的LL1、LL2、LL3层的应用。 首先,图像的模糊通常是通过应用平均滤波器来实现的。...
一维信号的小波分解重构,其中matlat的源代码是对序列做了扩展的