개발정리

리팩토링 메소드정리 기법 본문

리팩토링

리팩토링 메소드정리 기법

성구님 2017. 4. 9. 13:41
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

6장. 메소드 정리


INTRO

  • 코드 덩어리를 별도의 코드로 분리
    • Extract Method
  • 위의 반대 개념
    • Inline Method
  • 임시변수 제거
    • Replace Temp with Query
  • 임시변수가 여러 목적으로 사용된다면
    • Split Temporary Variable
  • 임시변수가 너무 꼬여있다면
    • Replace Method with Method Object
  • 만약 파라미터에 값을 대입하고 있다면
    • Remove Assignment to Parameters
  • 더 정확한 알고리즘을 위해
    • Substitude Algorithm

Extract Method

그룹으로 함께 묶을 수 있는 코드 조각이 있으면

  • 코드의 목적이 잘 드러나도록
  • 메소드의 이름을 지어
  • 별도의 메소드로 뽑아낸다.

Befoe

void printOwing (double amount) {
  printBar();

  System.out.println("amount : " + amount);
}

After

void printOwing (double amount) {
  printBar();
  printDetails(amount);
}

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

동기

  • 짧고 이해하기 쉬운 이름으로 된 메소드
    • 메소드가 잘게 쪼개져 있다면 재사용 될 확률이 높다.
    • high-level 메소드에서 볼 때 일련의 주석을 읽는 느낌
    • 오버라이드가 쉽다.
  • 이름을 잘 지어야한다. 이름의 길이는 중요하지 않다.
  • 하나의 메소드는 하나의 값만 리턴하는 것을 권장한다.

Inline Method

메소드 몸체가 메소드의 이름만큼이나 명확할 때는

  • 호출하는 곳에 메소드의 몸체를 넣고, 메소드를 삭제해라.
  • Extract Method의 반대
  • 메소드가 잘 못 나뉘었을 때 새로운 리패토링을 위해 사용한다.
  • Replace Method with Method Object적용 전에 사용하면 좋다.

Inline Temp

간단한 수식의 결과값을 갖는 임시변수가 있고 그 임시 변수가 다른 리팩토링에 방해가 된다면

  • 이 임시변수를 참조하는 모든 부분을 모두 원래의 수식으로 바꿔라.
  • 대부분의 경우 Replace Temp with Query의 한 부분으로 사용한다.

Replace Temp with Query

어떤 수식의 결과값을 저장하기 위해서 임시변수를 사용하고 있다면

  • 수식을 뽑아서 메소드로 만들고, 임시변수를 참조하는 곳에 메소드 호출로 바꾼다.

Before

double basePrice = q * itemPrice;
if (basePrice > 1000)
  return basePrice * 0.95;
else
  return basePrince * 0.98;

After

public double basePrice () {
 return q * itemPrice;  
}
//.....
if (basePrice() > 1000)
  return basePrice() * 0.95;
else
  return basePrince() * 0.98;

동기

  • 임시변수는 임시로 사용되고, 특정 부분에서만 의미를 가지므로 문제가 된다.
  • 임시변수를 질의 메소드로 바꿈으로써 클래스 내의 어떤 메소드도 임시변수에 사용될 정보를 얻을 수 있다.
  • Extract Method 리팩토링 전 필수.

Introduce Explainung Variable

복잡한 수식이 있는 경우에는

  • 수식의 결과나 또는 수식의 일부에 자신의 목적을 잘 설명하는 이름으로 된 임시변수를 사용하라

Before

if ((platform.toUpperCase().indexof("MAC") > -1) &&
   (browser.toUpperCase().indexof("IE") > -1) &&
    wasInitalized() && resized > 0) {
      //...
}

After

final boolean isMacOs = platform.toUpperCase().indexof("MAC") > -1;
final boolean isIEBrowser = browser.toUpperCase().indexof("IE") > -1;
final boolean wasResized = resized > 0;

if (isMacOs && isIEBrowser && wasInitalized() && wasResized) {
      //...
}

Split Temporary Variable

루프 안에 있는 변수나 Collecting Temporary Variable이 아닌 임시변수에 값을 여러번 대입하는 경우

  • 각각의 대입에 대해서 따로 임시변수를 만들어라

동기

  • 어떤 변수를 여러가지 용도로 사용하는 경우에 각각의 용도에 맞게 변수를 사용하도록 해야한다.
  • 변수의 값이 여러번 바뀐다는 것은 여러가지 용도로 사용되고 있다는 뜻이다.
  • 그렇지않을 경우 코드를 보는 사람이 매우 혼란스럽다.

Remove Assignment to Parameters

파라미터에 값이 대입되는 코드가 있으면

  • 대신 임시변수를 사용하도록 하라

동기

  • 파라미터가 완전히 다른 객체를 참조하도록 하는 것은
    • 명확하지 않고
    • 값에 의한 전달과 참조에 의한 전달을 혼동할 여지가 있다.

Replace Method with Method

긴 메소드가 있는데, 지역변수 때문에 Extract Method를 적용할 수 없는 경우

  • 메소드를 그 자신을 위한 객체로 바꿔서 모든 지역변수가 그 객체의 필드가 되도록 한다.
  • 이렇게 하면 메소드를 같은 객체 안의 여러 메소드로 분해할 수 있다.

절차

  1. 메소드의 이름을 따서 새로운 클래스를 만든다.
  2. 새로운 클래스에 원래 메소드가 있던 객체를 보관하기 위한 final 필드를 하나 만들고, 메소드에서 사용되는 임시변수와 파라미터를 위한 필드를 만들어 준다.
  3. 새로운 클래스에 소스객체와 파라미터를 취하는 생성자를 만들어 준다.
  4. 새로운 클래스에 Compute라는 메소드를 만든다.
  5. 원래의 메소드를 Compute 메소드로 복사한다. 원래의 객체에 있는 메소드를 사용하는 경우에는 소스 객체 필드를 사용하도록 바꾼다.
  6. 새로운 클래스의 객체를 만들고 원래의 메소드를 새로 만든 객체의 Compute 메소드를 호출하도록 바꾼다.

Substitude Algorithm

알고리즘을 보다 명확한 것으로 바꾸고싶을 때는

  • 메소드의 몸체를 새로운 알고리즘으로 바꾼다.

Before

String foundPerson (String[] args) {
  for (int i = 0 ; i < args.length ; i++) {
    if (args[i].equals("Don")) {
      return "Don";
    }
  }
}

After

String foundPerson (String[] peaple) {
  List candidates = Array.asList(new String[] {...});

  for (int i = 0 ; i < peaple.length ; i++) {
    if (candidates.contains(peaple[i])) {
      return peaple[i];
    }
  }
}


'리팩토링' 카테고리의 다른 글

리팩토링 객체간의 기능 이동 기법  (0) 2017.04.09
리팩토링 [북리뷰] 리팩토링이란?  (0) 2017.04.09
Comments