




| 변경 전 | 변경 후 |
|---|---|
| {code} public class Employee { void tenPercentRaise(){ salary *=1.1; } |
void fivePercentRaise(){
salary *=1.05;
}
}
|
public class Employee{
void raise(double factor){
salary *=(1+factor);
}
}
|
h2. Replace Parameter with Explicit Methods
* 파라미터의 값에 따라서 다른 코드를 실행하는 메소드가 있다면, 각각의 파라미터 값에 대한 별도의 메소드를 만들어라.
||변경 전||변경 후||
|
void setValue (String name, int value) {
if (name.equals("height")) {
_height = value;
return;
}
if (name.equals("width")) {
_width = value;
return;
}
Assert.shouldNeverReachHere();
}
|
void setHeight(int arg) {
_height = arg;
}
void setWidth (int arg) {
_width = arg;
}
|
h4. 동기
* 위와 같이 별도의 메소드를 만들어서 조건문을 거치지 않게 하면 조건에 따른 행동을 피할 뿐만 아니라 컴파일 할 때 확인 할 수 있다
또한 인터페이스가 좀 더 명확해 진다.
h2. Preserve Whole Object
* 어떤 객체에서 여러 개의 값을 얻은 다음 메소드를 호출하면서 파라미터로 넘기고 있다면, 대신 그 객체를 파라미터로 넘겨라.
||변경 전||변경 후||
|
int low = daysTempRange().getLow();
int high = daysTempRange().getHigh();
withinPlan = plan.withinRange(low, high);
|
withinPlan = plan.withinRange(daysTempRange());
|
h4. 동기
* Preserve Whole Object은 파라미터 리스트가 변경에 유연하게 대처 할 수 있도록 해준다.
* 종종 코드를 좀 더 읽기 좋게 만든다.
h2. Replace Parameter with Method
* 객체가 메소드를 호출한 다음, 결과를 다른 메소드에 대한 파라미터로 넘기고 있다.
수신자(Receiver:파라미터를 넘겨받는 메소드) 또한 이 메소드를 호출할 수 있다면,
그 파라미터를 제거하고 수신자가 그 메소드를 호출하도록 하라
||변경 전||변경 후||
|
int basePrice = _quantity * _itemPrice;
discountLevel = getDiscountLevel();
double finalPrice = discountedPrice (basePrice, discountLevel);
|
int basePrice = _quantity * _itemPrice;
double finalPrice = discountedPrice (basePrice);
|
h4. 동기
* 어떤 메소드가 파라미터로 넘겨 받는 값을 다른 방법을 사용해서 얻을 수 있다면, 그렇게 해야 한다.
* 긴 파라미터 리스트는 이해하기 어려우므로, 파라미터 리스트를 가능한 짧게 줄여야 한다.
h4. 예제
||변경 전||변경 후||
|
int basePrice = _quantity * _itemPrice;
discountLevel = getDiscountLevel();
double finalPrice = discountedPrice (basePrice, discountLevel);
private double discountedPrice(int basePrice, int discountLevel){
if(discountLevel == 2) return basePrice * 0.1;
else return basePrice * 0.05;
}
|
int basePrice = _quantity * _itemPrice;
double finalPrice = discountedPrice (basePrice);
private double discountedPrice(int basePrice){
if(getDiscountLevel() == 2) return basePrice * 0.1;
else return basePrice * 0.05;
}
|
h2. Introduce Parameter Object
* 자연스럽게 몰려다니는 파라미터 그룹을 가지고 있다면, 그것들을 객체로 바꾸어라.
!9.introParamObj.gif!
h4. 동기
* 종종 같이 넘겨지는 경향이 있는 특별한 그룹의 파라미터를 보게 된다면 그 그룹은 데이터 덩어리이고 이 데이터 전부를 운반하는 객체로 바꿀 수 있다.
* 이 파라미터를 객체로 바꾸는 것은 파라미터 리스트의 길이를 줄이기 때문에 유용하다.
* 대체하려는 파라미터 그룹을 나타낼 새로운 클래스는 불변성(immutable)으로 한다.
* [immutable 패턴|http://blog.naver.com/kittenjun?Redirect=Log&logNo=10003991072]
* [immutable과 static factory method | /wiki/pages/1507380]
h2. Remove Setting Method
* 어떤 필드가 객체 생성시에 값이 정해지고 그 이후에는 변경되지 않아야 한다면, 그 필드 값을 설정하는 모든 메소드를 제거하라.
!10.removeSettingMethod.gif!
h4. 동기
* 객체가 생성되고 나서 어떤 필드 값이 바뀌는 것을 원하지 않는다면, 그 필드에 대한 set 메소드를 제공하지 마라.
* 이런 방법을 사용하면 명확해 지고, 필드 값이 변할지도 모르는 가능성이 없어지게 된다.
h4. 예제
||변경 전||변경 후||
|
public class Account{
private String _id;
Account (String id){
setId(id);
}
void setId (String arg){
id = arg;
}
}
|
public class Account {
private final String _id;
Account (String id){
id = id;
}
}
|
h2. Hide Method
* 메소드가 다른 클래스에서 사용되지 않는다면, 그 메소드를 private으로 만들어라.
!11.hideMethod.gif!
h4. 절차
* 메소드의 접근 권한을 좀 더 줄일 수 있는지 정기적으로 검사한다.
* 가능하면 각각의 메소드의 접근 권한을 private로 한다.
h2. Replace Constructor with Factory Method
* 객체를 생성할 때 단순히 생성하는 것 이외에 다른 작업도 하고 있다면, 생성자를 팩토리 메소드로 대체하라.
||변경 전||변경 후||
|
Employee (int type){
_type = type;
}
|
static Employee create(int type){
return new Employee(type);
}
|
h4. 동기
* Replace Constructor with Factory Method를 사용해야 하는 가장 명확한 때는 타입 코드를 서브클래스로 대체할 때이다.
h4. 예제
||① 최초||② 중간||
|
class Employee{
private int _type;
static final int ENGINEER = 0;
static final int SALESMAN = 1;
static final int MANAGER = 2;
Employee (int type){
_type = type;
}
static Employee create(int type){
return new Employee(type);
}
}
//client code..
Employee emp = Employee.create(Employee.ENGINEER);
|
//Replace Type Code with Subclass를 적용
static Employee create(int type){
switch(type){
case ENGINEER :
return new Engineer();
case SALESMAN :
return new Salesman();
case MANAGER :
return new Manager();
default :
throw new IllegalArgumentException("Incorrect type code value");
}
}
|
||③ 최종||
|
static Employee create(int type){
switch(type){
case ENGINEER :
return create("Engineer");
case SALESMAN :
return create("Salesman");
case MANAGER :
return create("Manager");
default :
throw new IllegalArgumentException("Incorrect type code value");
}
}
//Class.forName을 사용한다.
static Employee create(String name){
try{
return (Employee)Class.forName(name).newInstance();
}catch(Exception e)
throw new IllegalArgumentException("Incorrect type code value");
}
}
//client code..
Employee emp = Employee.create("Engineer");
|
h2. Encapsulate Downcast
* 메소드가 그 호출부에서 다운캐스트(downcast) 될 필요가 있는 객체를 리턴하고 있다면, 다운캐스트 하는 것을 메소드 안으로 옮겨라.
||변경 전||변경 후||
|
Object lastReading(){
return readings.lastElement();
}
|
Reading lastReading(){
return (Reading) readings.lastElement();
}
|
h4. 동기
* 가능하면 다운캐스팅을 적게 사용해야 한다.
* 클라이언트에서 다운캐스팅을 하도록 하는 것보다 가능하면 가장 구체적인 타입을 항상 제공해야 한다.
불필요한 작업을 클라이언트에 강요하는 것이다.
* Generic을 잘 활용하면 좋겠죠.
h2. Replace Error Code with Exception
* 메소드가 에러를 나타내는 특별한 코드를 가지고 있다면, 대신 예외를 던져라.
||변경 전||변경 후||
|
int withdraw(int amount) {
if (amount > _balance)
return -1;
else {
_balance -= amount;
return 0;
}
}
|
void withdraw(int amount) throws BalanceException {
if (amount > _balance) throw new BalanceException();
_balance -= amount;
}
|
h4. 동기
* 예외는 일반적인 처리 과정과 예외 처리 과정을 명확하게 분리하기 때문에 더 좋다.
* 이는 프로그램을 이해하기 쉽게 만든다.
h2. Replace Exception with Test
* 호출부에서 먼저 검사할 수 있는 조건에 대해 예외를 던지고 있다면, 호출부가 먼저 검사하도록 바꿔라
||변경 전||변경 후||
|
double getValueForPeriod (int periodNumber) {
try {
return _values[periodNumber];
} catch (ArrayIndexOutOfBoundsException e) {
return 0;
}
}
|
double getValueForPeriod (int periodNumber) {
if (periodNumber >= _values.length) return 0;
return _values[periodNumber];
}
|
h4. 동기
* 예외는 예외적인 동작(예상치 못한 에러)에 대해서 사용되야 한다. (예외를 과도하게 사용해서는 안 된다.)
* 예외가 조건 테스트를 대신하는 역할을 하면 안된다.
* 호출부에서 동적을 호출하기 전에 조건을 테스트할 수 있다면 테스트를 제공해야 하고, 호출부에서는 그것을 사용해야 한다.
h2. 문서에 대하여
* 이 문서의 내용은 [Refactoring- 나쁜 디자인의 코드를 좋은 디자인으로 바꾸는 방법|http://kangcom.com/common/bookinfo/bookinfo.asp?sku=200204020003] 교재를 스터디 하면서 정리한 내용 입니다.
* 최초작성자 : [김정식]
* 최초작성일 : 2007년 12월 03일
* 이 문서는 [오라클클럽|http://www.gurubee.net] [자바 웹개발자 스터디|2007년 하반기 - 제2차 자바 웹개발 스터디] 모임에서 작성하였습니다.
* 이 문서를 다른 블로그나 홈페이지에 퍼가실 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^\