그룹으로 함께 묶을 수 있는 코드 조각이 있으면 코드의 목적이 잘 드러나도록 메소드의 이름을 지어 별도의 메소드로 뽑아낸다.
동기
절차
지역 변수가 포함되어 있는 경우
지역 변수에 다른 값을 여러번 대입하는 경우
변수 e는 뽑아낸 코드 안에서만 사용되기 때문에 새 메소드로 옮길 수 있다. 변수 outstanding은 양쪽에서 모두 사용되므로 뽑아낸 메소드에서 그 값을 리턴하게 한다. 테스트 후에 변수 이름을 변경한다.
컴파일과 테스트를 한 후에 outstanding 변수를 초기화 하는 방법을 바꾼다
void printOwing(double amount) { printBanner(); //print details System.out.println ("name:" + _name); System.out.println ("amount" + amount); }
void printOwing(double amount) { printBanner(); printDetails(amount); } void printDetails (double amount) { System.out.println ("name:" + _name); System.out.println ("amount" + amount); }
동기
- 지나치게 긴 메소드
- 목적을 이해하기 위해서 주석이 필요한코드
- 짧고 이해하기 쉬운 메소드는
- 메소드가 잘게 쪼개져 있을때 다른 메소드에서 사용될 확률이 높아진다
- 상위 레벨(high-level)의 메소드를 볼때 일련의 주석을 읽는것 같은 느낌이 든다
- 오버라이드 하는것도 쉽다
- 이름을 지을때 주의하라
- 한 메소드의 길이는 중요하지 않다
- 메소드의 이름과 메소드 몸체의 의미적 차이
- 뽑아내는 것이 코드를 더욱 명확하게 하면, 새로 만든 메소드의 이름이 원래 코드의 길어보다 길어져도 뽑아낸다
절차
- 메소드를 새로 만들고, 의도를 잘 나타낼수 있도록 이름을 정한다
- 어떻게 하는지를 나타내는 방식으로 이름을 정하지 말고, 무엇을 하는지를 나타내게 이름을 정한다.
- 더 이해하지 쉬운 이름을 지을수 없다면 뽑아내지 않는것이 낫다.
- 원래 메소드에서 뽑아내고자 하는 부분의 코드를 복사하여 새 메소드로 옮긴다.
- 원래 메소드에서 사용되고 있는 지역 변수가 뽑아낸 코드에 있는지 확인한다.
- 이런 지역변수는 새로운 메소드의 지역변수나 파라미터가 된다.
- 뽑아낸 코드내에서만 사용되는 임시 변수가 있는지 본다
- 있다면 새로 만든 메소드의 임시변수로 선언한다
- 뽑아낸 코드내에서 지역 변수의 값이 수정되는지 본다
- 하나의 지역변수만 수정된다면, 뽑아낸 코드를 질의로 보고, 수정된 결과를 관련된 변수에 대입할수 있는지 본다.
- 이렇게 하는것이 이상하거나, 값이 수정되는 지역변수가 두개 이상 있다면 쉽게 메소드로 추출할 수 없는 경우이다.
- Split Temporary Variable을 사용한뒤에 재시도
- 임시 변수는 Replace Temp with Query로 제거
- 뽑아낸 코드에서 읽기만 하는 변수는 새 메소드의 파라미터로 넘긴다.
- 지역 변수와 관련된 사항을 다룬 후에는 컴파일 한다.
- 원래 메소드에서 뽑아낸 코드 부분은 새로 만든 메소드를 호출하도록 바꾼다.
- 새로 만든 메소드로 옮긴 임시 변수가 있는 경우, 그 임시 변수가 원래 메소드의 밖에서 선언 되었는지를 확인한다
- 새로 만든 메소드에서는 선언을 해줄 필요가 없다
- 컴파일과 테스트를 한다.
지역 변수가 없는 경우
void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; // print banner System.out.println ("**************************"); System.out.println ("***** Customer Owes ******"); System.out.println ("**************************"); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } //print details System.out.println ("name:" + _name); System.out.println ("amount" + outstanding); }
배너를 인쇄하는 부분을 뽑아내는 것은 쉽다. ==> Cut and Paste 후 원래 코드는 새 메소드를 호출한다.
void printOwing() {
Enumeration e = _orders.elements();
double outstanding = 0.0;
printBanner();
// calculate outstanding
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
//print details
System.out.println ("name:" + _name);
System.out.println ("amount" + outstanding);
}
void printBanner() {
// print banner
System.out.println ("**************************");
System.out.println ("***** Customer Owes ******");
System.out.println ("**************************");
}
지역 변수가 포함되어 있는 경우
- 가장 쉬운 것은 변수가 읽히기만 하고 값이 변하지 않는 경우 ==> 그냥 파라미터만 넘긴다.
void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } //print details System.out.println ("name:" + _name); System.out.println ("amount" + outstanding); }
void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); } void printDetails (double outstanding) { System.out.println ("name:" + _name); System.out.println ("amount" + outstanding); }
- 실제로 지역변수에 다른 값을 대입하는 경우에만 부가적인 작업이 필요
지역 변수에 다른 값을 여러번 대입하는 경우
- 지역 변수에 다른 값을 대입하는 코드가 있는 경우에는 문제가 복잡
- 우선 임시변수에 대해서만 생각
- 파라미터에 다른 값을 대입하는 코드가 있다면 --> Remove Assignments to Parameters 를 적용한다.
- 임시 코드에 값을 대입하는 경우
- 임시 변수가 뽑아낸 코드안에서만 사용될때
- 뽑아낸 코드로 임시 변수를 옮긴다.
- 임시 변수가 뽑아낸 코드 외부에서도 사용되는 경우
- 뽑아낸 코드 이후의 부분에서 사용되지 않는다면, 앞의 경우처럼 바꿀수 있다
- 이후에서도 사용된다면, 뽑아낸 코드에서 임시 변수의 바뀐 값을 리턴하도록 수정
- 임시 변수가 뽑아낸 코드안에서만 사용될때
void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); }
void printOwing() { printBanner(); double outstanding = getOutstanding(); printDetails(outstanding); } double getOutstanding() { Enumeration e = _orders.elements(); double outstanding = 0.0; while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } return outstanding; }
변수 e는 뽑아낸 코드 안에서만 사용되기 때문에 새 메소드로 옮길 수 있다. 변수 outstanding은 양쪽에서 모두 사용되므로 뽑아낸 메소드에서 그 값을 리턴하게 한다. 테스트 후에 변수 이름을 변경한다.
double getOutstanding() { Enumeration e = _orders.elements(); double result = 0.0; while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); result = each.getAmount(); } return result; }
void printOwing(double previousAmount) { Enumeration e = _orders.elements(); double outstanding = previousAmount * 1.2; printBanner(); // calculate outstanding while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); }
void printOwing(double previousAmount) { double outstanding = previousAmount * 1.2; printBanner(); outstanding = getOutstanding(outstanding); //<- printDetails(outstanding); } double getOutstanding(double initialValue) { double result = initialValue; Enumeration e = _orders.elements(); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); result += each.getAmount(); } return result; }
void printOwing(double previousAmount) { printBanner(); double outstanding = getOutstanding(previousAmount * 1.2); //<-- printDetails(outstanding); }
- 만약 두개 이상의 값이 리턴되어야한다면
- 가장 좋은 선택은 뽑아낼 코드를 다르게 선택하라. (하나의 값을 리턴하기를 좋아하는 저자, 잘 정리해서 각각의 다른 값에 대한 메소드를 따로 만든다.)
- 사용중인 언어가 출력 파라미터를 지원한다면 이것을 이용한다.
- 임시 변수가 너무 많아 코드를 뽑기 힘든 경우
- Replace Temp with Query ==> 임시 변수를 줄인다
- Replace Method with Method Object
'프로그램언어 > Refactoring' 카테고리의 다른 글
[ Refactoring ] Split Temporary Variable (2) | 2010.12.01 |
---|---|
[ Refactoring ] Introduce Explaing Variable (0) | 2010.11.29 |
[ Refactoring ] Replace Temp with Query Method (0) | 2010.11.29 |
[ Refactoring ] Inline Temp (0) | 2010.11.24 |
[ Refactoring] Inline Method (0) | 2010.11.24 |