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

순서

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


I. 배경

데이터 항목 여러개가 이 함수 저 함수 몰려다니는 것을 자주 본다.

이런 데이터 무리를 발견하면 하나로 묶어주고 싶고,
묶었을 때 데이터 사이의 관계가 좀 더 명확해지는 이점을 얻는다.

또한 매개변수가 하나로 통일되어 일관성도 높여준다.

이런 다양한 장점이 있지만 이 리팩토링의 가장 큰 장점은
코드를 더 "근본적"으로 바꾸어 준다는데에 있다.

"근본적" 이라는 것은 이런 리팩토링을 시작으로 method, Interface 등
일관된(성장된) class가 점차 만들어지는 것을 의미한다.

 


II. 절차

1. 적당한 구조가 없다면 새로 데이터 구조를 만든다.

    클래스가 유리하다 -> 나중에 동작까지 묶을 수 있음.
    주로 데이터 구조는 값 객체(Value Object)로 만든다.

2. 일단 구조 만들고 테스트

3. "함수 선언 바꾸기"로 새 데이터 구조를 매개변수로 추가

4. 다시 테스트

5. 함수 호출 시 신규 데이터 구조 인스턴스 넘기도록 수정
진행하며 하나당 하나의 테스트 (점진적 리팩토링)

6. 기존 코드를 수정하고 최종 테스트한다.

 


III. 예시


코드 원본

#include "gtest/gtest.h"

class Reading {
 public:
  int temp;
  int time;
};

class Station {
 public:
  char* name;
  struct Reading readings[5];
};

int ReadingsOutsideRange(Station* station, int min, int max) {
  int count = 0;
  for (int i = 0; i < 5; ++i) {
    if (station->readings[i].temp < min
        || station->readings[i].temp > max) {
      ++count;
    }
  }
  return count;
}

// 이 테스트를 메인 동작코드로 보자
TEST(IntroduceParameterObject, ReadingsOutsideRange) {
  Station station = {"ZB1", 47, 910, 53, 920, 58, 930, 53, 940, 51, 950};
  ASSERT_EQ(2, ReadingsOutsideRange(&station, 50, 55));
}

 


1. 데이터 구조 만들기 (CNumberRange)

#include "gtest/gtest.h"

class Reading {
 public:
  int temp;
  int time;
};

class Station {
 public:
  char* name;
  struct Reading readings[5];
};

/* 1. New Class For Range */
class CNumberRange {
public:
  int min;
  int max;
};

/* 1. Change Paramater */
int ReadingsOutsideRange(Station* station, CNumberRange* numRange) {
  int count = 0;
  for (int i = 0; i < 5; ++i) {
    if (station->readings[i].temp < numRange->min
        || station->readings[i].temp > numRange->max) {
      ++count;
    }
  }
  return count;
}

// 이 테스트를 메인 동작코드로 보자
TEST(IntroduceParameterObject, ReadingsOutsideRange) {
  Station station = {"ZB1", 47, 910, 53, 920, 58, 930, 53, 940, 51, 950};
  CNumberRange numRange = {50, 55}  /* 1. Instance 으로 전달 */
  ASSERT_EQ(2, ReadingsOutsideRange(&station, &numRange));
}

 


IV. 기타

위 처럼 매개변수 및 값 객체들을 클래스로 만들어주면
관련 동작들을 모두 클래스로 옮길 수 있다는 이점이 생기는 것이 매우 중요하다.

또한 이런 예시처럼 범위 개념에 대해서 값 쌍이 어떻게 사용되는지 보면
"동치성 검사 메서드(Equality Method)"부터 추가하여 방식을 간소화 시킬 수 있다.

 

+ Recent posts