티스토리 뷰

반응형

리팩토링 방법

  • 이전 방법은 아래 링크에서 확인할 수 있습니다.
 

자바로 배우는 리팩토링 입문 - 유키 히로시 리뷰 (1)

코드에서 나는 악취를 나타내는 말 겹치잖아! 너무 길어! 너무 많아! 이름이 안 맞잖아! 너무 공개적이잖아! 객체 지향답지 않아! 리팩토링 방법 1. 매직 넘버를 기호 상수로 치환 if (100 < input.lengt

aeliketodo.tistory.com

 

자바로 배우는 리팩토링 입문 - 유키 히로시 리뷰 (2)

리팩토링 방법 1 - 4번째 방법은 아래 링크에서 확인할 수 있습니다. 자바로 배우는 리팩토링 입문 - 유키 히로시 리뷰 (1) 코드에서 나는 악취를 나타내는 말 겹치잖아! 너무 길어! 너무 많아! 이

aeliketodo.tistory.com

 

 

10. 에러 코드를 예외로 치환

public static Command parseCommand(String name) {
    if (!_commandNameMap.containsKey(name)) {
    	return null;
    }
    return _commandNameMap.get(name);
}

public static Command parseCommand(String name) {
    if (!_commandNameMap.containsKey(name)) {
    	throw new InvalidCommandException(name);
    }
    return _commandNameMap.get(name);
}

 

 

 

11. 생성자를 팩토리 메서드로 치환

  • 클라이언트
Shape shape = new Shape(TYPECODE_LINE);
  • 서버
public Shape(int typecode) {
    _typecode = typecode;
    ...
}

  • 클라이언트
Shape shape = Shape.create(TYPECODE_LINE);
  • 서버
private Shape(int typecode) {
    _typecode = typecode;
	....
}

public static Shape.create(int typecode) {
    return new Shape(typecode);
}

 

 

 

12. 관측 데이터 복제

  • 혼재하는 모델과 뷰를 분리하는 리팩토링 기법이다.
  • 옵저버 패턴이나 이벤트 리스너를 사용해 모델 내용이 변하면 그 사실을 뷰에 알려 동기화한다.

 

[ 모델과 뷰를 분리하는 방법 ]

1) 모델을 나타내는 클래스 작성

  • Value 클래스 작성
public class Value {
    private int _value = 0;
    
    public Value(int value) {
    	_value = value;
    }
    
    public void setValue(int value) {
    	_value = value;
    }
    
    public int getValue() {
    	return _value;
    }
}

 

  • 뷰에서 모델을 참조
private int _value = 0;

private Value _value = new Value(0);

 

  • 뷰: 모델을 메서드로 조작
_value = value;

_value.setValue(value);

 

 

2) 통지 관련 클래스와 인터페이스 작성

  • 통지 내용을 나타내는 이벤트 선언
public class ValueChangeEvent {
    private final Value _source;
    
    public ValueChangeEvent(Value source) {
    	_source = source;
    }
    
    public Value getSource() {
    	return source;
    }
}

 

  • 통지 관련 인터페이스 선언
public interface ValueListener {
	public void valueChanged(ValueChangeEvent e);
}

 

  • 통지를 받는 메서드를 뷰에 선언
public class IntegerDisplay extends Frame implements ActionListener, ValueListener {
    ...
    
    public void valueChanged(ValueChangeEvent e) {
    	....
    }
    
}

 

 

3. 뷰 등록과 뷰 통지

  • 모델: 모델에 뷰를 등록 가능하게 만듦
public class Value {
    ...
    
    private final List<ValueListener> _listener = new ArrayList<ValueListener>();
    
    public void addValueListener(ValueListener listener) {
    	_listener.add(listener);
    }
}

 

  • 뷰: 뷰를 모델에 등록
public IntegerDisplay() {
    ...
    
    _value.addValueListener(this);
    
}

 

  • 모델: '모델을 변경하면 뷰에 통지'하는 코드 작성
public class Value {
    ...
    
    public void setValue(int value) {
    	_value = value;
        notifyToListeners();
    }
    
    private void notifyToListeners() {
    	for (ValueListener listener: _listeners) {
        	listener.valueChanged(new ValueChangeEvent(this));
        }
    }
}

 

  • 뷰: 통지를 받는 메서드 안으로 표시 갱신 처리를 이동
public class IntegerDisplay ... {
    ...
    
    public void valueChanged(ValueChangeEvent e) {
    	if (e.getSource(0 == _value) {
            _octaLabel.setText(Integer.toString(_value.getValue(), 8));
            _decimalLabel.setText(Integer.toString(_value.getValue(), 10));
            _hexadecimalLabel.setText(Integer.toString(_value.getValue(), 16));
        }
    }
}

 

 

13. 상속을 위임으로 치환

  • 부적절한 상속을 위임으로 치환하는 리팩토링 기법이다.
  • 상속은 최후의 무기 - 남용하지 말아야 한다.
  • 리스코프 치환 원칙
    • 'Parent 타입 변수에 Child 클래스의 인스턴스를 할당해도 문제 없이 사용 가능'하게 만들어야 하는 원칙
    • 상속을 사용하는 게 좋을지 안 좋을지 판단해야할 때 유용한 기준이다.
  • 2가지의 관계
    • IS-A 관계 : 'oo는 ㅁㅁ의 일종이다.' → 상속 관계
    • HAS-A 관계 : 'oo는 ㅁㅁ를 가지고 있다.' → 위임 관계

 

 

class Another {
    void method() {
    	...
    }
    ...
}

class Something extends Another {
    ...
}

class Something {
    Another _delegate = new Another();
    ...
    
    void method() {
    	_delegate.method();
    }
}

 

 

생성자 중복으로 인한 악취도 리팩토링해보자

public Dice() {
    _random = new Random(314159L);
}

public Dice(long seed) {
    _random = new Random(seed);
}

public Dice() {
    this(314159L);
}

public Dice(long seed) {
    _random = new Random(seed);
}

 

 

14. 대리자 은폐

  • 서버 클래스가 다른 클래스(대리 클래스)에 기능을 위임하는 경우를 대비한 리팩토링 기법이다.
  • 클라이언트 클래스가 대리 클래스를 직접 호출하지 않도록 대리 클래스를 은폐한다.

 

  • 클라이언트 클래스가 대리 클래스를 이용함
server.getDelegate().handle();

  • 클라이언트가 대리 클래스를 이용하지 않음
server.handle();

 

다양한 은폐 방법

1) 접근 제어를 사용한 은폐

  • private 선언자
  • protected 선언자

 

2) 패키지를 사용한 은폐

  • public 없이 클래스를 선언하면 그 클래스는 패키지 외부에서 보이지 않는다.

 

1) 중첩 클래스를 사용한 은폐

  • 클래스 내부에 클래스를 선언해 클래스끼리 관계가 있음을 코드로 명시한다.

 

중개자 제거

  • 대리자 은폐 리팩토링은 서버 클래스 안에 위임 메서드가 늘어난다는 단점이 있다.
  • 대리자 은폐와 반대로 중개자를 삭제하는 것도 리팩토링이 될 수 있다.

 

클래스 인라인화

  • 대리 클래스가 별다른 처리를 안 한다면 서버 클래스 안에 집어넣어 관계를 간단하게 만든다.

 

 

 

15. 상속 구조 정리

  • 사실상 브리지 패턴을 이용하는 것과 동일하다.
  • 엉킨 상속 관계를 풀어내서 분할하고, 분할한 두 상속을 위임으로 접근한다.

 

반응형