代码重构技巧之重复代码

在我们项目开发的过程中,有时写着写着顺手了,对于一些业务代码,重复编写,导致后来需要修改的时候,得整个项目到处找这些重复代码,这真是一件糟糕的事。

一、重复代码

定义

重复代码并不是指的完全一模一样的代码,只要在一段代码,业务处理上,有相识之处,都能叫做重复代码。

影响

重复代码太多,会造成代码过长,不易阅读,而且如果代码逻辑需要修改,会使得代码容易遗漏、不易维护。

二、重复代码案例

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、将使用这些代码的地方,手动替换成重构后的静态方法。

扫描二维码关注公众号,回复: 13985745 查看本文章

三、快捷键总结

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45171957/article/details/124414857
今日推荐