Self Encapsulate Field
정의 필드에 직접 접근하고 있는데 필드에 대한 결합이 이상해지면, 그 필드에 대한 get/set 메소드를 만들고 항상 이 메소드를 사용하여 필드에 접근하라.
동기
주의사항
Replace Data Value with Object
Change Reference to Value
Replace Array with Object
Duplicate Observed Data
Change Unidirectional Association to Bidirectional
Change Bidirectional Association to Unidirectional
Replace Magic Number with Symbolic Constant
Encapsulate Field
Replace Magic Number with Symbolic Constant
Replace Record with Data Class
Replace Type Code with Class
Replace Type Code with Subclasses
Replace Type Code with State/Strategy
Replace Subclass with Fields
- 간접 접근 방식(indirect variable access)의 장점은 서브클래스에서 정보를 얻는 메소드를 오버라이드 하여, 데이터를 관리하는데 있어 lazy initialization 과 같은 보다 많은 융통성을 제공할 수 있다는 것이다.
- 이 리팩토링을 사용해야 하는 가장 중요한 때는 수퍼클래스에 있는 필드에 접근하지만 이 변수 접근을 서브클래스에서 계산되는 값으로 오버라이드 하고 실을 때이다.
- 직접 접근 방법(direct variable access)의 장점은 코드가 읽기 쉬워진다는 것이다.
- 자체 캡슐화를 사용할 때, 생성자에서 set 메소드가 사용되는 것에 주의해야 한다. 종종 객체가 생성된 후에 속성을 변경하기 위해 set 메소드를 사용하는 것으로 가정하므로, set 메소드에는 초기화 할 때와는 다른 동작을 포함하고 있을 수 있다. 이런 경우에는 생성자에서 직접 접근하거나 또는 별도의 초기화 메소드를 만든다.
Replace Data Value with Object
- 정의
추가적인 데이터나 동작을 필요로 하는 데이터 아이템이 있을 때는, 데이터 아이템을 객체로 바꾸어라. - 동기
- 한두 개의 아이템에 대해서는 아이템을 포함하고 있는 객체에 메소드를 추가할 수 있겠지만, 곧 코드는 중복(duplication)과 기능에 대한 욕심(feature envy)의 냄새를 풍기게 된다. 이런 냄새가 나기 시작하면 데이터 값을 객체로 바꾸어야 한다.
- 주의사항
Change Value to Reference
- 정의
동일한 인스턴스를 여러 개 가지고 있는 클래스가 있고 여러 개의 동일한 인스턴스를 하나의 객체로 바꾸고 싶으면, 그 객체를 참조 객체로 바꾸어라. - 동기
- 불변성(immutable) 데이터를 가지는 간단한 값으로 시작하다가 변경 가능한 데이터를 두고, 변경이 그 객체를 참조하고 있는 모든 곳으로 전파되어야 한다면 객체를 참조 객체로 바꾸어라.
- 주의사항
- 어떤 객체가 참조 객체에 대한 접근을 제공하는 책임을 질 것인지 결정한다.
- 객체를 미리 생성해두고 메모리에서 구해서 쓴다면, 객체를 요구하기 전에 생성하는 것을 확실히 해야 한다.
Change Reference to Value
- 정의
작고, 불변성(immutable)이고, 관리하기가 어려운 참조 객체(reference object)가 있는 경우, 그것을 값 객체(value object)로 바꾸어라. - 동기
- 참조 객체로 작업하는 것이 복잡해지면 참조에서 값으로 바꿀 이유가 될 수 있다.
- 주의사항
- 바꿀 객체가 immutable 인지 또는 immutable이 될 수 있는지 확인한다. 만약 객체가 immutable이 될 수 없다면, 이 리팩토링을 포기해야 한다.
Replace Array with Object
- 정의
배열의 특정 요소가 다른 뜻을 가지고 있다면, 배열을 각각의 요소에 대한 필드를 가지는 객체로 바꿔라. - 동기
- 다른 종류의 객체를 포함한 배열을 보게 된다. 배열의 첫 번째 요소는 사람의 이름이라는 식의 약속은 기억하기 어렵다. 이런 배열을 보게 되면 리팩토링을 해라.
- 주의사항
Duplicate Observed Data
- 정의
GUI 컨트롤에서만 사용 가능한 도메인(domain) 데이터가 있고, 도메인 메소드에서 접근이 필요한 경우, 그 데이터를 도메인 객체로 복사하고, 옵저버(observer)를 두어 두 데이터를 동기화 하라. - 동기
- 비지니스 로직이 사용자 인터페이스와 섞여 있는 2-티어로 개발된 코드를 보게 되면 인터페이스와 동작을 분리해야 한다.
- 주의사항
Change Unidirectional Association to Bidirectional
- 정의
각각 서로의 기능을 필요로 하는 클래스가 있는데, 링크가 한쪽 방향으로만 되어 있는 경우, 반대 방향으로 포인터를 추가하고, 수정자(modifier)가 양쪽 세트(set)를 모두 업데이트 하게 변경하라. - 동기
- 두 개의 클래스 중 단 방향 링크 일때, 기능 추가 등으로 반대 방향의 링크가 필요한 경우 역 포인터(back pointer)로 불리는 양방향 참조를 사용해라.
- 주의사항
- 어느 클래스가 이 연관을 책임지게 할 것인지 결정해야 한다.
- 두 객체가 모두 참조 객체(reference object)이고, 연관이 일대다(one to many)인 경우, 하나의 참조를 가지는 객체를 컨트롤러로 한다.
- 한 객체가 다른 객체의 일부로 사용된다면, 그 객체를 포함하고 있는 객체가 연관을 컨트롤 한다.
- 두 객체가 모두 참조 객체이고, 연관이 다대다(many to many)인 경우, 어느 쪽이 연관을 컨트롤 하든 상관 없다.
Change Bidirectional Association to Unidirectional
- 정의
서로 링크를 가지는 두 개의 클래스에서 한 쪽이 다른 한쪽을 더 이상 필요로 하지 않을 때는 불필요한 링크를 제거하라. - 동기
- 양방향 연관은 반드시 필요한 곳에만 사용해야 한다. 제 몫을 하지 못하는 양방향 연관을 발견하면 즉시 불필요한 한쪽 링크를 끊어라.
- 주의사항
- 양방향 링크에서는 죽어야 하는데 참조가 제대로 클리어 되지 않아 계속 살아돌아다니는 객체를 유도하기가 쉽다.
- 양방향 링크를 유지하게 되면, 객체가 적절히 생성/제거되는지를 확인해야 하는 등의 복잡성(complexity)이 증가한다.
- 양방향 연관을 자연스럽게 다루지 못하게 되면 종종 에러의 원인이 된다.
Replace Magic Number with Symbolic Constant
- 정의
특별한 의미를 가지는 숫자 리터럴이 있으면, 상수를 만들고, 의미를 잘 나타내도록 이름을 지은 다음, 숫자를 상수로 바꾸어라. - 동기
- 매직 넘버는 특정 값을 가지는 숫자로 보통 그 의미는 명확하지 않다. 논리적으로 같은 숫자를 여러 곳에서 사용해야 하는 경우, 여러 곳에서 사용하지 않더라도 그 의미를 이해하기가 어렵다. 이 경우에 리팩토링 한다.
- 주의사항
Encapsulate Field
- 정의
public 필드가 있는 경우, 그 필드를 private으로 만들고, 접근자를 제공하라. - 동기
- 객체 지향에서는 데이터를 절대로 public으로 하지 말라고 한다. 만약 데이터를 public으로 하면, 데이터를 가지고 있는 객체가 알지 못하는 사이에 다른 객체가 데이터 값에 접근하고 변경할 수 있게 된다.
- 주의사항
Replace Magic Number with Symbolic Constant
- 정의
컬렉션(Collection)을 리턴하는 메소드가 있으면, 그 메소드가 읽기 전용 뷰(read-only view)를 리턴 하도록 만들고, add/remove 메소드를 제공하라. - 동기
- 컬렉션은 다른 종류의 데이터를 다룰 때와는 약간 다른 프로토콜을 사용해야 한다.
- get 메소드가 컬렉션 객체 자체를 리턴하면 안 되는데, 왜냐하면 이것은 클라이언트 코드가 컬렉션을 가지고 있는 클래스가 알지 못하는 사이에 컬렉션의 내용을 조작할 수 있기 때문이다.
- 컬렉션에 대한 set 메소드가 있으면 안 된다. 대신 컬렉션에 요소(element)를 추가, 삭제하는 오퍼레이션이 잇어야 한다. 이것은 컬렉션을 가지고 있는 객체가 컬렉션에 요소를 추가, 삭제하는 작업을 제어할 수 있게 한다.
- 주의사항
Replace Record with Data Class
- 정의
전통적인 프로그래밍 환경에서의 레코드 구조에 대한 인터페이스가 필요한 경우, 그 레코드를 위한 데이터 객체를 만들어라. - 동기
- 레거시(legacy) 프로그램을 복사하는 경우, 전통적인 프로그래밍 API에서 사용되는 구조적 레코드 또는 데이터베이스 레코드와 통신하는 경우, 이런 외부 요소를 다루는 인터페이스 클래스를 만들면 편리하다.
- 주의사항
Replace Type Code with Class
- 정의
클래스의 동작에 영향을 미치지 않는 숫자로 된 타입 코드(numeric type code)가 있으면, 숫자를 클래스로 바꾸어라. - 동기
- 숫자를 클래스로 바꾼다면, 컴파일러는 클래스에 대해서 타입 체크를 할 수 있다.
- 주의사항
Replace Type Code with Subclasses
- 정의
클래스의 동작에 영향을 미치는 변경 불가능한(immutable) 타입 코드가 있다면, 타입 코드를 서브클래스로 바꾸어라. - 동기
- 타입 코드가 동작에 영향을 미치는 경우 대부분 switch 문이거나 if then - else 구조일 것이다. 이런 조건문은 Replace Conditional with Polymorphism을 사용하여 리팩토링 할 필요가 있다. 그러기 위해서는 타입 코드가 다형성 동작을 가지는 상속 구조로 바뀌어야 한다.
- 또 다른 경우는, 특정 타입 코드를 가지는 객체에만 관계된 기능이 있을 때이다.
- 주의사항
- 객체가 생성된 다음에 그 객체의 타입 코드 값이 바뀌는 경우에는 이 리팩토링을 할 수 없다.
- 타입 코드를 가지는 클래스가 이미 다른 이유로 서브클래스를 가지고 있는 경우에는 이 리팩토링을 할 수 없다.
- Replace Type Code with Subclasses 는 주로 Replace Type Code with State/Strategy을 가능하게 하기 위한 발판이 된다.
- 만약 타입 코드가 생성자로 전달된다면, 생성자를 팩토리 메소드로 바꾸어야 한다.
Replace Type Code with State/Strategy
- 정의
클래스의 동작에 영향을 미치는 타입 코드가 있지만 서브클래싱을 할 수 없을 때는, 타입 코드를 스테이트(State) 객체로 바꾸어라. - 동기
- 객체의 존속기간 동안 타입 코드가 바뀌거나 또는 다른 이유로 서브클래싱을 할 수 없는 경우에 사용한다.
- 주의사항
Replace Subclass with Fields
- 정의
상수 데이터를 리턴하는 메소드만 다른 서브클래스가 있으면, 그 메소드를 수퍼클래스의 필드로 바꾸고 서브클래스를 제거하라. - 동기
- 상수 메소드만을 포함하고 있는 서브클래스는 존재할 가치가 있을 만큼 충분한 일을 하는 것이 아니다. 이런 서브클래스는 수퍼클래스에 필드를 추가하고 완전히 샂게할 수 있다. 이렇게 하며녀 서브클래스를 사용하면서 생기는 여러 복잡성을 제거할 수 있다.
- 주의사항
'Programs > Refactoring' 카테고리의 다른 글
Refactoring - 객체간의 기능 이동 (5) | 2011.11.21 |
---|---|
Refactoring - 메소드 정리(Composing Methods) (4) | 2011.11.16 |
리팩토링(Refactoring) (4) | 2011.11.07 |