이 글은 리팩터링 2판(마틴 파울러) 책을 참고하였습니다.

순서

I. 배경
II. 절차
III. 예시
IV. 기타


I.배경

매개변수 목록은 함수의 변동 요인을 모아두는 곳이다.
즉, 함수의 동작에 변화를 줄 수 있는 가장 일차적인 수단이다.

이 리팩토링에서 인지해야 할 부분은
매개변수를 제거하면 값을 결정하는 '책임의 주체'가 달라진다는 것이다.
호출하는 함수에서 매개변수를 넘기지 않으면
피 호출함수에서 이를 결정해야 하기 때문이다.

마틴 파울러는 습관적으로 호출하는 쪽을 간소화 시킨다고 한다.

이 방법을 사용하지 말아야 할 때는 매개변수 제거시 피 호출함수에
의존성이 생겼을 때이다.
= 해당 함수가 알지 못했으면 하는 프로그램 요소에 접근해야 하는 상황

주의사항 : 대상 함수가 참조 투명해야 한다는 것.

참조 투명 (Referential Transparency)
- 함수에 똑같은 값을 건네 호출하면 항상 똑같이 작동
참조 불투명 (Referential Opaque)
- 함수에 똑같은 값을 건네도 다른 요인에 의해 다르게 작동

int Rt (int x) { return x;} (투명)
vs
int Rtg(int x) { return x + g; } (불투명)
-> 이때 g는 외부에서 선언된 글로벌 변수

 


II. 절차

1. 필요하다면 대상 매개변수의 값을 계산하는 코드를 별도 함수로 추출해놓는다.

2.함수 본문에서 대상 매개변수로의 참조를 모두 찾아 그 매개변수의 값을
만들어주는 표현식을 참조하도록 바꾼다. 하나 수정할 때 마다 테스트한다
-> 점진적 리팩토링 : 하나당 1테스트

3. 함수 선언 바꾸기로 대상 매개변수를 없앤다.

 

 


III. 예시


코드 원본

#include "gtest/gtest.h"

int quantity;
int item_price = 1;

int DiscountedPrice(int base_price, int discount_level) {
  switch (discount_level) {
    case 1:
      return base_price * 0.95;
    case 2:
      return base_price * 0.9;
  }
  return base_price;
}

int FinalPrice() {
  int base_price = quantity * item_price;
  int discount_level = 0;
  if (quantity > 100) {
     discount_level = 2;
  } else {
    discount_level = 1;
  }
  return DiscountedPrice(base_price, discount_level);
}

TEST(ReplaceParameterWithQuery, DiscountedPrice_DiscountLevel1) {
  ASSERT_EQ(95, DiscountedPrice(100, 1));
}

TEST(ReplaceParameterWithQuery, DiscountedPrice_DiscountLevel2) {
  ASSERT_EQ(90, DiscountedPrice(100, 2));
}

TEST(ReplaceParameterWithQuery, FinalPrice_Quantity100) {
  quantity = 100;
  ASSERT_EQ(95, FinalPrice());
}

TEST(ReplaceParameterWithQuery, FinalPrice_Quantity101) {
  quantity = 101;
  ASSERT_EQ(90, FinalPrice());
}

 


1. discount_level 변수를 질의함수로 바꾸기

// TEST 코드 생략
#include "gtest/gtest.h"

int quantity;
int item_price = 1;

int getDiscountLevel() {  /* 1. 함수 분리 */
  int discount_level = 0;
  if (quantity > 100) {
     discount_level = 2;
  } else {
    discount_level = 1;
  }
  return discount_level;
  // return (quantity>100? 2 : 1) 이렇게 변경해도 깔끔
}

int DiscountedPrice(int base_price) {
  switch (getDiscountLevel()) { /* 1. 함수 분리 */
    case 1:
      return base_price * 0.95;
    case 2:
      return base_price * 0.9;
  }
  return base_price;
}

int FinalPrice() {
  int base_price = quantity * item_price;
  
  /* 1. 함수 분리 -> 매개변수 삭제 */
  return DiscountedPrice(base_price);
}

 


IV. 기타

코딩을 하다보면 함수 호출시 은근 매개변수의 고민을 많이 하게 되는데
최대한 Main 코드가 간소화 될 수 있도록 구현 하는 것이
코드의 전체 구조를 이해하기에 더 좋아보인다.

근데 회사에서 함수Call이 너무 많아 진다고 좋지 않다고 해서
고민이다. 난 책대로 했는데...

+ Recent posts