改善既有代码的设计笔记(四)重新组织方法

2018-07-11  本文已影响6人  红发_SHANKS

Refactor guru
许多重构都致力于正确地编写方法。在大多数情况下, 过长的方法是万恶之源。这些方法中的异常代码隐藏了执行逻辑, 使方法很难理解-甚至更难更改。

此组中的重构技术简化了方法, 删除了重复代码, 并为将来的改进铺平了道路。

提取方法(Extra Method)

问题: 您有一个可以组合在一起的代码片段。

解决方案: 将此代码移到单独的新方法 (或函数) 中, 并使用对该方法的调用替换旧代码。注意新方法要有合适的命名,使代码具有自解释性

// 重构前
void printOwing() {
  printBanner();

  //print details
  System.out.println("name: " + name);
  System.out.println("amount: " + getOutstanding());
}

...

// 重构后
void printOwing() {
  printBanner();
  printDetails(getOutstanding());
}

void printDetails(double outstanding) {
  System.out.println("name: " + name);
  System.out.println("amount: " + outstanding);
}

为什么要抽取方法

注意:
如果有临时变量仅仅被新方法使用,那么将临时变量提取到新方法;
如果临时变量在新方法之前需要修改,将临时变量作为参数传入新方法;
如果临时变量在新方法之后需要修改、使用,将临时变量作为返回值传回源方法。

内联方法(Inline Method)##

问题: 当方法体比方法本身更明显时, 请使用此技术。

解决方案: 用方法内容替换对方法的调用, 并删除方法本身。Intellij IDEA 快捷键 ctrl + alt + n

优点: 使代码更加清晰

Extract Variable(提取局部变量)##

问题: 你有一个很难理解的表达式。

解决方案: 将表达式或其部分的结果放在自解释的单独变量中。

void renderBanner() {
  if ((platform.toUpperCase().indexOf("MAC") > -1) &&
       (browser.toUpperCase().indexOf("IE") > -1) &&
        wasInitialized() && resize > 0 )
  {
    // do something
  }
}

...

// 重构后
void renderBanner() {
  final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
  final boolean isIE = browser.toUpperCase().indexOf("IE") > -1;
  final boolean wasResized = resize > 0;

  if (isMacOs && isIE && wasInitialized() && wasResized) {
    // do something
  }
}

Inline Temp(内联临时变量)
问题: 您有一个临时变量, 它分配了一个简单表达式的结果, 而不是更多。

解决方案: 用表达式本身替换对变量的引用。

boolean hasDiscount(Order order) {
  double basePrice = order.basePrice();
  return basePrice > 1000;
}

...

boolean hasDiscount(Order order) {
  return order.basePrice() > 1000;
}

Replace Temp with Query(以查询取代临时变量)

问题: 将表达式的结果放在局部变量中, 以便以后在代码中使用。

解决方案: 将整个表达式移动到一个单独的方法中, 并从它返回结果。查询方法而不是使用变量。如有必要, 将新方法合并到其他方法中。

double calculateTotal() {
  double basePrice = quantity * itemPrice;
  if (basePrice > 1000) {
    return basePrice * 0.95;
  }
  else {
    return basePrice * 0.98;
  }
}

...

double calculateTotal() {
  if (basePrice() > 1000) {
    return basePrice() * 0.95;
  }
  else {
    return basePrice() * 0.98;
  }
}
double basePrice() {
  return quantity * itemPrice;
}

Split Temporary Variable (分解临时变量)##

问题: 您有一个局部变量, 用于在方法内存储各种中间值 (循环变量除外)。

解决方案: 对不同的值使用不同的变量。每个变量只应负责一个特定的薄

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

...

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

Remove Assignments to Parameters(移除对参数的赋值)

问题: 某些值被分配给方法体内的参数。

解决方案: 使用局部变量而不是参数。

int discount(int inputVal, int quantity) {
  if (inputVal > 50) {
    inputVal -= 2;
  }
  //...
}

...

int discount(int inputVal, int quantity) {
  int result = inputVal;
  if (inputVal > 50) {
    result -= 2;
  }
  //...
}

Replace Method with Method Object(以函数对象取代函数)

问题: 您有一个很长的方法, 其中局部变量如此交织, 无法应用抽取方法。

解决方案: 将方法转换为单独的类, 使局部变量成为类的字段。然后, 可以将该方法拆分为同一类中的多个方法。

class Order {
  //...
  public double price() {
    double primaryBasePrice;
    double secondaryBasePrice;
    double tertiaryBasePrice;
    // long computation.
    //...
  }
}

...


class Order {
  //...
  public double price() {
    return new PriceCalculator(this).compute();
  }
}

class PriceCalculator {
  private double primaryBasePrice;
  private double secondaryBasePrice;
  private double tertiaryBasePrice;
  
  public PriceCalculator(Order order) {
    // copy relevant information from order object.
    //...
  }
  
  public double compute() {
    // long computation.
    //...
  }
}
上一篇 下一篇

猜你喜欢

热点阅读