C++ 리팩토링
- Extract Method
- 하나의 그룹으로 묶어 분리할 수 있는 코드를 뽑아낸다.
- 코드가 작게 분리 될 수록 하위 클래스가 작은 메소드를 override하기 쉽다.
- 큰 메소드 하나는 하위 클래스가 전체 메소드를 재정의해야 함으로 작업량이 많아진다
void Owing::printOwing (double amount)
{
printBanner ();
cout << "name : " << _name << endl;
cout << "amount : " << amount << endl;
}
void Owing::printOwing (double amount)
{
printBanner ();
printDetail(amount);
}
void Owing::printDetail(double amount)
{
cout << "name : " << _name << endl;
cout << "amount : " << amount << endl;
}
Extract Function
- 코드 블록을 전역 함수로 분리
- 멤버 변수를 액세스 하는 코드 블록은 적용할 수 없다
- Inline Method
- Extract Method의 반대로 메소드가 하는 일이 명확하고 작을 때 메소드 호출을 삭제하고 코드를 붙여 넣는다.
- 리팩토링을 역행하므로 특별한 경우가 아니면 사용할 필요가 없다.
- 위음을 통해 메소드가 서로 연결된 경우 이것을 단순화 시키기 위해 사용할 수 있다.
- Inline Temp - Inline Constant
- 간단한 수식의 결과를 가지는 임시변수를 Inline Temp로 정의
- 명칭만으로 명확한 함수 호출이 단순히 임시변수에 대입 되어 사용되는 경우 임시 변수를 제거하고 함수 호출을 바로 하는 방법
- 임시 변수의 제거가 코드의 가독성을 해치는 경우에는 적용 X
double Circle::GetVolume() {
double PI = getPI();
return m_radius * m_radius * PI;
return m_radius * m_radius * getPI();
}
- Inline Result
- Replace Temp with Query
- 수식의 결과 값을 저장하기 위해 임시 변수를 사용하는 것을 수식의 메소드로 만들고, 임시 변수를 참조하는 곳을 모두 메소드 호출로 변경
- Replace Temp with Query 사용 목적
- 임시 변수는 메소드 길이를 길게 만드는 경향이 있음
- 나중에 그 임시변수를 사용하게 될 가능성이 생겨, 목적과 달리 사용될 수 있는 경향이 있음
- 임시 변수를 제거하는 것은 클래스 코드를 좀 더 깔끔하게 해줌
- Introduce Explaining Variable - Introduce Local
- 복잡한 수식이 있는 경우 이것을 의미 있는 이름을 가지는 임시 변수에 대입한 후에 사용함으로써 가독성을 높인다.
- 사용 목적
- 복잡한 수식에 의미 있는 이름을 붙일 때
- if 나 while의 조건으로 복잡한 수식이 사용될 때 조건을 좀 더 명확하게 설명할 수 있다
- 임시 변수는 반드시 의미 있는 이름을 가져야 한다
- const로 선언하여 다른 목적으로 사용되지 못하게 해야 한다
- Extract Method와 유사하므로 적절하게 분리하여 사용한다.
- Split Temporary Variable
- 임시 변수가 여러 가지 목적으로 사용될 때 목적에 맞게 임시 변수 생성
- 사용 목적
- 여러 목적으로 사용되는 임시변수는 가독성을 떨어뜨린다
- 여러 목적으로 사용되는 임시변수는 잘못 사용될 가능성이 높아진다.
- Remove Assignments to Parameters
- 메소드나 함수의 인자에 값을 대입하는 코드가 있다면 이것을 임시변수로 변경
- 목적
- 인자는 인자 원래의 기능에 충실하도록, 변수의 목적을 명확히
- 인자 대신 의미 있는 이름의 임시 변수를 사용해 가독성 증가
- call by reference로 전달된 인자인 경우 프로그램의 오류를 예방할 수 있다.
- 코드가 의도적으로 참조에 의해 값을 전달하고 메소드나 함수 내부에서 참조값을 변경하는 목적이면 Remove Assignments to Parameters를 사용하면 안된다. 객체가 참조에 의해 전달되고, 이것의 속성을 변경하는 것이 목적인 경우에도 마찬가지이다.
//before
int Manufacture::discount(int inputVal, int date) {
if(inputVal > 50 ) inputVal += 2;
if(date > 1000 ) inputVal -= 4;
return inputVal;
}
//after
int Manufacture::discount(int inputVal, int date) {
int result;
if(inputVal > 50 ) result = inputVal + 2;
if(date > 1000 ) result = inputVal - 4;
return result;
}
- Replace Method with Method Object
- Extract Method를 할 코드가 있는데, 지역변수나 인자 때문에 못하는 경우, 메소드 전체를 새로운 객체를 만들어 옮기고, 모든 지역 변수를 새로운 객체의 멤버 필드가 되도록 한다
- 지역 변수를 개체 필드를 생성한 다음에는 자유롭게 Extract Method 가능
- Extract Method 전 단계 과정으로 사용한다.
- Substitute Algorithm
- 메소드 알고리즘을 보다 명확한 것으로 바꾸고 싶을 때는 메소드 전체를 새로운 알고리즘으로 바꾼다.
- 메소드 정리의 최후의 방법
- 메소드 정리를 히스토리로 관리하고, 이것이 어떤 횟수 이상이 되면 Substitute Algorithm을 하는 것도 좋은 방법