Self Encapsulate Field

  • 정의
  • 필드에 직접 접근하고 있는데 필드에 대한 결합이 이상해지면, 그 필드에 대한 get/set 메소드를 만들고 항상 이 메소드를 사용하여 필드에 접근하라.

  • 동기
    • 간접 접근 방식(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
Posted by outliers
,