본문 바로가기

프로그램언어/Refactoring

[ Refactoring ] Introduce Explaing Variable

복잡한 수식이 있는 경우에는, 수식의 결과나 또는 수식의 일부에 자신의 목적을 잘 설명하는 이름으로 된 임시변수를 사용하라.

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

동기

  • 수식은 매우 복잡해져 알아보기 어려워질수가 있으므로 임시변수를 사용하여 수식을 좀 더 다루기 쉽게 한다.
  • 조건문에서 각각의 조건의 뜻을 잘 설명하는 이름의 변수로 만들어 사용할 때 유용하다.
  • 긴 알고리즘에서 각 단계의 계산 결과를 잘 지어진 이름의 임시변수로 설명할 수 잇다.
  • 저자는 잘 사용하지 않는다고 한다.(머야 이게)
    • 항상 Extract Method 를 사용한다.
    • 이유: 임시변수는 한 메소드의 컨텍스트 내에서만 유용하지만 메소드는 객체의 모든 부분에서 뿐만 아니라 다른 객체에서도 유용하다.
    • 지역변수 때문에 Extract Method 를 사용하기 어려운 경우에만 사용한다.

절차

  • final 변수를 선언하고, 복잡한 수식의 일부를 이 변수에 대입한다.
  • 원래의 복잡한 수식에서, 임시변수에 대입한 수식을 임시변수로 바꾼다.
  • 컴파일과 테스트를 한다.
  • 수식의 다른 부분에 대해서도 위의 작업을 반복한다.

예제

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

quantity와 itemPrice의 곱이 basePrice라는 것을 알아낸 후 임시변수를 넣는다.

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와 itemPrice 의 곱은 코드의 뒷부분에서도 사용되므로 아래와 같이 바꾼다.

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

quantityDiscount 를 만든다.

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

shipping에 대해서도 같은 작업을 한다.

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


예제(Extract Method를 사용한 경우)

원본 코드
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);
   }

basePrice를 메소드로 뽑아낸다.

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

다른 부분도 계속 작업을 진행한다

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

Introduce Explaining Variable 은 언제 사용하는가? => Extract Method를 사용하기 어려울 때 이다.