代码重构之重复代码处理

举报
i进击的攻城狮 发表于 2022/04/26 00:16:52 2022/04/26
【摘要】 介绍重复代码的重构方式

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

一、重复代码

定义

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

影响

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

二、重复代码案例

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

三、快捷键总结

在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。