java 代码细节(Introduce Explaining Variable)




这个观点来自《重构-----改善既有代码的设计》

You have a complicated expression.

Put the result of the expression, or parts of the expression, in a temporary variable with a name that explains the purpose.

if ((platform.toUpperCase().indexOf("MAC") > -1) &&
   (browser.toUpperCase().indexOf("IE") > -1) &&
    wasInitialized() && resize > 0 ) {
         // do something
}
graphics/arrow.gif
final boolean isMacOs     = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIEBrowser = browser.toUpperCase().indexOf("IE")  > -1;
final boolean wasResized  = resize > 0;
 
if (isMacOs && isIEBrowser && wasInitialized() && wasResized) {
     // do something
}

Motivation

Expressions can become very complex and hard to read. In such situations temporary variables can be helpful to break down the expression into something more manageable.

Introduce Explaining Variable is particularly valuable with conditional logic in which it is useful to take each clause of a condition and explain what the condition means with a well-named temp. Another case is a long algorithm, in which each step in the computation can be explained with a temp.

Introduce Explaining Variable is a very common refactoring, but I confess I don’t use it that much. I almost always prefer to use Extract Method if I can. A temp is useful only within the context of one method. A method is useable throughout the object and to other objects. There are times, however, when local variables make it difficult to use Extract Method. That’s when I use Introduce Explaining Variable.

Mechanics

  • Declare a final temporary variable, and set it to the result of part of the complex expression.

  • Replace the result part of the expression with the value of the temp.

    If the result part of the expression is repeated, you can replace the repeats one at a time.
  • Compile and test.

  • Repeat for other parts of the expression.

Example

I start with a simple calculation:

double price() {
    // price is base price - quantity discount + shipping
    return _quantity * _itemPrice -
        Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
        Math.min(_quantity * _itemPrice * 0.1, 100.0);
}

Simple it may be, but I can make it easier to follow. First I identify the base price as the quantity times the item price. I can turn that part of the calculation into a temp:

double price() {
     // price is base price - quantity discount + shipping
     final double basePrice = _quantity * _itemPrice;
 
     return basePrice -
         Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
         Math.min(_quantity * _itemPrice * 0.1, 100.0);
}

Quantity times item price is also used later, so I can substitute with the temp there as well:

double price() {
    // price is base price - quantity discount + shipping
    final double basePrice = _quantity * _itemPrice;
 
    return basePrice -
        Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
        Math.min(basePrice * 0.1, 100.0);
}

Next I take the quantity discount:

double price() {
    // price is base price - quantity discount + shipping
    final double basePrice = _quantity * _itemPrice;
    final double quantityDiscount = Math.max(0, _quantity - 500) * _itemPrice * 0.05;
 
    return basePrice - quantityDiscount + Math.min(basePrice * 0.1, 100.0);
}

Finally, I finish with the shipping. As I do that, I can remove the comment, too, because now it doesn’t say anything the code doesn’t say:

double price() {
    final double basePrice = _quantity * _itemPrice;
    final double quantityDiscount = Math.max(0, _quantity - 500) * _itemPrice * 0.05;
    final double shipping = Math.min(basePrice * 0.1, 100.0);
 
    return basePrice - quantityDiscount + shipping;
}

Example with Extract Method

For this example I usually wouldn’t have done the explaining temps; I would prefer to do that with Extract Method. I start again with

double price() {
    // price is base price - quantity discount + shipping
    return _quantity * _itemPrice -
        Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
        Math.min(_quantity * _itemPrice * 0.1, 100.0);
}

but this time I extract a method for the base price:

double price() {
    // price is base price - quantity discount + shipping
    return basePrice() -
        Math.max(0, _quantity - 500) * _itemPrice * 0.05 +
        Math.min(basePrice() * 0.1, 100.0);
} 
 
private double basePrice() {
    return _quantity * _itemPrice;
}

I continue one at a time. When I’m finished I get

double price() {
    return basePrice() - quantityDiscount() + shipping();
}
 
private double quantityDiscount() {
    return Math.max(0, _quantity - 500) * _itemPrice * 0.05;
}
 
private double shipping() {
    return Math.min(basePrice() * 0.1, 100.0);
}
 
private double basePrice() {
    return _quantity * _itemPrice;
}

I prefer to use Extract Method, because now these methods are available to any other part of the object that needs them. Initially I make them private, but I can always relax that if another object needs them. I find it’s usually no more effort to use Extract Method than it is to use Introduce Explaining Variable.

So when do I use Introduce Explaining Variable? The answer is when Extract Method is more effort. If I’m in an algorithm with a lot of local variables, I may not be able to easily use Extract Method. In this case I useIntroduce Explaining Variable to help me understand what is going on. As the logic becomes less tangled, I can always use Replace Temp with Query later. The temp also is valuable if I end up having to use Replace Method with Method Object.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值