java 代码细节(Introduce Explaining Variable)

来源:互联网 发布:linux 重命名文件夹 编辑:程序博客网 时间:2024/04/19 13:36




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

You have a complicated expression.

02

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

03
if ((platform.toUpperCase().indexOf("MAC") > -1) &&   (browser.toUpperCase().indexOf("IE") > -1) &&    wasInitialized() && resize > 0 ) {         // do something}
graphics/arrow.gif
04
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

05

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.

06

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.

07

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

08
  • 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

09

I start with a simple calculation:

10
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);}
11

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:

12
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);}
13

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

14
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);}
15

Next I take the quantity discount:

16
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);}
17

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:

18
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

19

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

20
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);}
21

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

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

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

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

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.

26

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.


原创粉丝点击