重构:一、重新组织方法

来源:互联网 发布:特效照相机软件下载 编辑:程序博客网 时间:2024/05/17 01:42

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

    • 重新组织方法
      • 提炼方法
      • 内联方法
      • 内联临时变量
      • 某些时候可以以查询方式取代临时变量
      • 引入解释性变量
      • 分解临时变量
      • 移除对参数的赋值
      • 以方法对象取代方法
      • 替换算法

重新组织方法

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;}

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

原创粉丝点击