在我们项目开发的过程中,有时写着写着顺手了,对于一些业务代码,重复编写,导致后来需要修改的时候,得整个项目到处找这些重复代码,这真是一件糟糕的事。
一、重复代码
定义
重复代码并不是指的完全一模一样的代码,只要在一段代码,业务处理上,有相识之处,都能叫做重复代码。
影响
重复代码太多,会造成代码过长,不易阅读,而且如果代码逻辑需要修改,会使得代码容易遗漏、不易维护。
二、重复代码案例
2.1 同一个类的多个方法间代码重复
有如下代码,需要 计算水果的价格,普通水管的价格计算公式是水果数量水果价格,折扣商品计算公式是水果数量水果价格*折扣,可以看出,下面的代码,根据水果类型算价格的逻辑是重复的,如果水果价格变动,每个方法都要变动。
/**
* 计算水果总价(同一个类的两个函数含有相同的表达式)
*
*/
public class FruitsCost {
public double computeMoneyWithoutPrivileges(String type, int numbers) {
double prices;
switch (type) {
case "apple":
prices = 5.5;
break;
case "banana":
prices = 4.0;
break;
case "strawberry":
prices = 10.5;
break;
default:
throw new IllegalArgumentException("Illegal type : " + type);
}
return prices * numbers;
}
public double computeMoneyWithPrivileges(String type, double numbers, double discount) {
double prices;
switch (type) {
case "apple":
prices = 5.5;
break;
case "banana":
prices = 4.0;
break;
case "strawberry":
prices = 10.5;
break;
default:
throw new IllegalArgumentException("Illegal type : " + type);
}
return prices * numbers * discount;
}
}
解决方法
对同一个类的多个方法间代码重复,可以使用提炼函数的方式,下面主要介绍如何利用IDEA开发工具去快捷的提炼函数,拒绝手动提炼!
1:选中需要提炼的代码段
2、使用快捷键Ctrl + Alt + M,弹出如下窗口
3、点击确认,一处一处的替换其他相似代码段,选择Replace,一次性替换所有选择All.
重构完的代码如下:
public class FruitsCost {
public double computeMoneyWithoutPrivileges(String type, int numbers) {
double prices = getPrices(type);
return prices * numbers;
}
private double getPrices(String type) {
double prices;
switch (type) {
case "apple":
prices = 5.5;
break;
case "banana":
prices = 4.0;
break;
case "strawberry":
prices = 10.5;
break;
default:
throw new IllegalArgumentException("Illegal type : " + type);
}
return prices;
}
public double computeMoneyWithPrivileges(String type, double numbers, double discount) {
double prices = getPrices(type);
return prices * numbers * discount;
}
}
2.2 互为兄弟的子类代码重复
有时候,两个子类继承了一个相同的父类,子类之间存在相同的代码,我们可以考虑将相同的代码提取到父类当中,也叫函数上移。
代码如下:
/**
* 水果利润(两个互为兄弟的子类含有相同的表达式)
*
*/
class Fruits {
// 成本单价
public double costPrices;
// 出售单价
public double prices;
// 最小出货量
public double minSaleableNum;
}
class Banana extends Fruits {
public Banana(double costPrices, double prices, double minSaleableNum) {
this.costPrices = costPrices;
this.minSaleableNum = minSaleableNum;
this.prices = prices;
}
public double profitMoney(int number) {
return Math.max(0, number - minSaleableNum) * this.prices - this.costPrices * number;
}
}
class Apple extends Fruits {
public Apple(double costPrices, double prices, double minSaleableNum) {
this.costPrices = costPrices;
this.minSaleableNum = minSaleableNum;
this.prices = prices;
}
public double profitMoney(int number) {
return Math.max(0, number - minSaleableNum) * this.prices - this.costPrices * number;
}
}
使用IDEA上移相同的代码到父类:
1、选中需要上移的代码
2、快捷键Ctrl+Alt+Shift+T,选中Pull Members UP
3、点击Refactor
4、当前子类重构后,手动删除其他子类中相同的方法。
2.3 不同类间的代码重复
有时候,重复的代码不在同一个类中,这种情况下也是也是用抽取方法的方式进行重构,但是重构后的方法,一般选中定义为静态方法。
问题代码:
class MonthJudgement {
public boolean judgeMonth() {
Long timeStamp = System.currentTimeMillis(); // 获取当前时间戳
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = sdf.format(new Date(Long.parseLong(String.valueOf(timeStamp))));
String month = date.split(" ")[0].split("-")[1];
return "12".equals(month);
}
}
class YearJudgement {
public boolean judgeYear() {
Long time = System.currentTimeMillis(); // 获取当前时间戳
System.out.println("获得当前时间戳");
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = dateFormat.format(new Date(Long.parseLong(String.valueOf(time))));
return date.startsWith("2021");
}
}
可以分析出,两处代码中,初始化时间的逻辑是相同的,可以把这几行代码抽取出来作为静态方法,步骤如下:
1:选中YearJudgement的输出代码,使用快捷键将其移动到上方,如下动图
2、选中如下代码,再使用快捷键Ctrl+Alt+M
3、选中Declare static和public,取消注解,点击refactor
4、光标移到刚刚在类中创建的静态方法,再使用快捷键Ctrl+Alt+Shift+T,选择Extract Delegate
5、在新的窗口输入类名和类所在的包名
6、将使用这些代码的地方,手动替换成重构后的静态方法。