重构:一、重新组织方法

重构:
在编写完代码后,仔细再去检查,会发现有很多地方都有改进。代码的重构(整理)可以为后期维护带来很好的选择。每个方法的粒度应该尽可能的比较小,这样复用代码重写代码,效率才会偏高。

重新组织方法

1. 提炼方法

提炼方法是最常用也是用的最多的一种手法。将一个过长的方法,提炼成一个主方法下多个子方法。这样的好处是,在后期如果不需要某个逻辑,直接注释其调用即可,如果再需要时,可以再添回来。如果不需要时删除,需要时再写,就重复了。
例如:

//存在伪代码
public void printBill(double amount) {
    double total = 0;

    System.out.println("-----------");
    System.out.println("------顾客账单-----");
    System.out.println("-----------");

    for(Order order : orders){
        total += order.getPrice();
    }

    System.out.println("顾客:" + name);
    System.out.println("付款总额:" + total);
}

上面这个方法,虽然比较简单,但是依然是可以进行提炼的。提炼结果:

public void printBill(double amount) {
    printBillHeader();

    double total = getTotal();

    printDetail(total);
}

private void printBillHeader(){
    System.out.println("-----------");
    System.out.println("------顾客账单-----");
    System.out.println("-----------");
}

private double getTotal(){
    double total = 0;
    for(Order order : orders){
        total += order.getPrice();
    }
    return total;
}

private void printDetail(double total){
    System.out.println("顾客:" + name);
    System.out.println("付款总额:" + total);    
}

提炼成这样的结果后,在阅读方面,易于阅读,在后期维护方面,也更易维护。

提炼原则

  1. 一个大的方法可以进行分解
  2. 分解后的方法用方法名表达方法主体意图

除了将大的方法分解为小的方法外,也可以重新修改变量名,让其名称更能表达其用意。重构的目的是,让计算机理解的程序修改成人可以理解的程序。只要能够清晰表达方法的意图,不在乎方法名的长短。

2. 内联方法

一个提取的方法本体与它的方法名一样清晰易懂,应该移除这个方法,将它内联到原方法中。
例如:

public int getRating(){
    return (moreThanFiveLateDeliveries()) ? 2 : 1;
}
private boolean moreThanFiveLateDeliveries(){
    return numberOfLateDeliveries > 5;
}

因为函数本体就很清楚,所以,可以将它内联到调用方法中。

public int getRating(){
    return numberOfLateDeliveries > 5 ? 2 : 1;
}

这种情况应该很少遇到。

3. 内联临时变量

方法内存在一个简单变量,只被赋值一次,使用一次。

double basePrice = order.getBasePrice();
if (basePrice > 100){}

改变后:

if (order.getBasePrice() > 100) {}

4. 某些时候可以以查询方式取代临时变量

某些时候可以把临时变量变成一种查询方式,虽然这样会调用多次方法,性能上有点影响,但是有些时候把这些变量分开,会让代码提炼的更简洁。举个例子:

public double getPrice(){
    int basePrice = quantity * itemPrice;
    double discountFactor;
    if (basePrice > 1000) {
        discountFactor = 0.95;
    } else {
        discountFactor = 0.98;
    }
    return basePrice * discountFactor;
}

似乎好像没有哪个地方可以提炼的,因为一个临时变量贯穿了整个方法,没有必要把它们分开。但是如果把这个临时变量定义为一个方法的话,就比较好提炼了。

public double getPrice(){
    return getBasePrice() * getDiscountFactor();
}

public int getBasePrice(){
    return quantity * itemPrice;
}

public double getDiscountFactor(){
    if (getBasePrice() > 1000) {
        return discountFactor = 0.95;
    }
    return discountFactor = 0.98;
}

有时候如果一个临时变量比较简单,不涉及太多查询的话,这种方式是可以采取的,因为调用一个方法来获取的时间,基本可以忽略。如果这个值是从数据库中查询的话,不建议使用,因为每次查数据库,消耗都比较大。

5. 引入解释性变量

例:

if (platform.toUpperCase.indexOf("MAC") != -1 &&
        browser.toUpperCase.indexOf("IE") != -1 &&
        resize > 0) {
    //dosomething
}

变更为:

boolean isMac = platform.toUpperCase.indexOf("MAC") != -1;
boolean isIE = browser.toUpperCase.indexOf("IE") != -1;
if(isMac && isIE && resize > 0){
    //dosomething
}

这种方式可以用第一种方式,提炼方法来代替。

6. 分解临时变量

其实就是意义不同不要使用同一个变量。
例如:

double temp = 2 * (width + height);
System.out.println(temp);
temp = width * height;
System.out.println(temp);

要将这个temp分解成两个变量。

double girth = 2 * (width + height);
System.out.println(girth);
double area = width * height;
System.out.println(area);

7. 移除对参数的赋值

也就是说,如果不想改变参数的值,就不要对参数赋值。

8. 以方法对象取代方法

一个比较大的方法,其中局部变量使用方式一的形式进行了提取。如果还有其他比较多的提取方法,将这些方法放入一个单独的类中,其中,局部变量便成了对象的字段,其他方法将是对象的方法。
示例:

public class Account {
    public int gamma(int inputValue, int quantity, int yearToData) {
        int importValue1 = (inputValue - quantity) * delta();
        int importValue2 = inputValue * yearToData + 100;
        if (yearToData - importValue1 > 100 ){
            importValue2 -= 20;
        }
        int importValue3 = importValue2 * 7;
        return importValue3 - 2 * importValue1;
    }
}

把提炼的方法放在一个新的对象中。

public class Gamma {
    private Account account;
    private int inputValue;
    private int quantity;
    private int yearToData;
    private int importValue1;
    private int importValue2;
    private int importValue3;

    public Gamma(Account source, int inputValue, int quantity, int yearToData){
        this.account = source;
        this.inputValue = inputValue;
        this.quantity = quantity;
        this.yearToData = yearToData;
    }

    public int cumpute(){
        //....
    }
}

原来的将变为:
public class Account {
    public int gamma(int inputValue, int quantity, int yearToData) {
        return new Gamma(this, inputValue, quantity, yearToData).cumpute();
    }
}

上面是一个简单示例,如果是一个大的方法,可以采用类似的这种方式。这样做的好处是,整个类会变得比较小。阅读起来更加容易。如果一个类中存放一大堆私有方法,第一眼看上去,就很累赘。

9. 替换算法

如果想把某个算法换成更清晰的算法,直接替换。
示例:

String fondPerson(String[] peoples){
    for(String people : peoples){
        if (people。equals("Don")) {
            return "Don";
        }
        if (people。equals("John")) {
            return "John";
        }
    }
    return null;
}

如果要换另一种写法,直接删了原来的,替换新的即可。

String fondPerson(String[] peoples){
    String[] exist = {"Don", "John"};
    for(String people : peoples){
        if(ArrayUtils.contains(exist, people)){
            return people;
        }
    }
    return null;
}

上面是对方法进行重构的几种手法。方法的重构是比较频繁的,几乎每个人都能遇到,也是最基本的。只是很多人像我一样,写完代码测试通过之后,再就不想回头去修改自己的代码了。在后期慢慢修改这种坏习惯。勤看自己写过的代码,优化以前的代码,使看起来更易懂,维护起来更方便。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值