Notice
Recent Posts
Recent Comments
끄적끄적
리팩토링 7장 - 객체간의 기능 이동 본문
책임을 어디에 둘 것인가
- Move Field
- Move Method
- Extract Class
- Inline Class
Move Method(v)
- 메소드가 자신이 정의된 클래스보다 다른 클래스의 기능을 더 많이 사용하고 있다면
- 이 메소드를 가장 많이 사용하고 있는 클래스에 비슷한 몸체를 가진 새로운 메소드를 만들어라.
- 그리고 이 전 메소드는 간단한 위임으로 바꾸거나 완전히 제거하라.
- 동기
- 자신이 속해 있는 클래스보다 다른 클래스를 더 많이 참조하는 메소드가 있는지 확인
- 절차
- 소스 클래스에 정의된 소스 메소드에 의해 사용되는 모든 부분을 조사
- 어떤 부분이 지금 옮기려는 메소드에서만 사용된다면, 그 부분 또한 같이 옮기는 것이 낫다.
- 소스 클래스의 서브클래스나 슈퍼클래스에서 옮기려고 하는 메소드에 대한 다른 선언이 있는지 확인
- 타겟 클래스에 메소드를 정의
- 소스 메소드에서 타겟 메소드로 코드를 복사. 그리고 그 메소드가 타겟 클래스에서 동작하도록 적절히 수정
- 타겟 클래스 컴파일
- 소스 클래스에서 적절한 타겟 객체를 참조하는 방법 결정
- 소스 메소드를 위임 메소드로 바꾼다.
- 컴파일, 테스트 한다.
- 소스 메소드를 제거할지 위임 메소드로 남겨둘지 결정
- 만약 소스 메소드를 참조하는 부분이 많다면, 소스 메소드를 위임 메소드로 남겨두는 것이 더 쉬운 방법
- 소스 메소드를 제거한다면 소스 메소드를 참조하고 있는 부분을 타겟 메소드를 참조하도록 수정
- 컴파일, 테스트
Move Field(v)
- 필드가 자신이 정의된 클래스보다 다른 클래스에 의해서 더 많이 사용되고 있다면
- 타겟 클래스에 새로운 필드를 만들고 기존 필드를 사용하고 있는 모든 부분을 변경하라.
- 동기
- 어떤 Field가 자신이 속한 Class보다 다른 Class의 Method에서 더 많이 사용되고 있을 때
- get/set으로 다른 곳에서 많이 쓰고 있을 거 같으면 Method를 옮기는 게 좋다.
- 그러나 Method의 위치가 적절하다면 필드를 옮긴다.
- Extract Class를 할 땐 Field를 먼저 옮기고 Method를 옮긴다.
- 절차
- Field가 public으로 선언되어 있으면 Encapsulate Field를 사용
- Compile, Test
- Target Class에 Field와 그 Field에 대한 get/set method를 만든다.
- Compile Target Class
- Source Class에서 Target 객체를 참조하는 방법 결정
- Source Class에 있는 Field 제거
- Source Field를 참조하고 있는 모든 부분을 Target Class에 있는 적당한 Method를 참조하도록 바꾼다.
- Compile, Test
Extract Class(v)
- 두 개의 Class가 해야 할 일을 하나의 Class가 하고 있는 경우
- 새로운 Class를 만들어서 관련 있는 Field와 Method를 예전 Class에서 새로운 Class로 옮겨라
- 동기
- Class가 많은 Method, Data를 가지고 있고, 너무 커서 쉽게 이해하기 어려운 경우
- 어떤 Data의 부분 집합과 Method의 부분 집합이 같이 몰려다니는 경우
- 만약 일부 Data나 Method를 제거한다면 다른 Field나 Method가 의미 없는 것이 될지를 물어보는 것은 편리한 테스트 방법
- 그렇다면 서로 연관있는 것일테니까
- 절차
- Class의 책임을 어떻게 나눌지 결정
- 분리된 책임을 떠맡을 새로운 Class 생성
- 책임을 분리한 후 이전 Class의 책임이 이름과 더 이상 맞지 않는다면, 이전 클래스의 이름도 변경
- 이전 클래스에서 새로 만든 클래스에 대한 링크를 만든다.
- 양방향 링크가 필요할지 모른다.
- 하지만 필요해지기 전에는 새로 만든 클래스에서 이전 클래스로 가는 링크를 만들지 말라.
- 옮기고자 하는 각각의 Field에 대해 Move Field 사용
- 각각의 Field를 옮길 때마다 Compile, Test
- Move Method를 사용해서 이전 Class에서 새로 만든 Class로 Method를 옮긴다.
- 저수준 Method(호출하기보다 호출되는 Method) -> 고수준 Method 순서로
- 각각의 Method 옮길 때마다 Compile, Test
- 각 Class를 검토하고, Interface를 줄인다.
- 양방향 링크를 가지고 있다면, 단방향 링크로 만들 수 있는지 확인
- 새로운 Class를 공개할지 결정
Inline Class
- Class가 하는 일이 많지 않은 경우에는
- 그 Class에 있는 모든 변수와 메소드를 다른 클래스로 옮기고 그 클래스를 제거하라.
- 동기
- Extract Class와 반대
- Refactoring으로 그 Class의 책임을 대부분 다른 곳으로 옮기고 남은 것이 거의 없는 경우
- 절차
- 흡수하는 Class에 Source Class의 public Field와 Method를 선언
- Source Class를 참조하고 있는 모든 부분을 흡수하는 Class를 참조하도록 변경
- Compile, Test
- Move Method와 Move Field를 사용하여 Source Class에 있는 모든 Field와 Method를 흡수하는 Class로 옮김
Hide Delegate
- Client가 객체의 위임 Class를 직접 호출하고 있는 경우
- 서버에 Method를 만들어서 대리객체(delegate)를 숨겨라
Remove Middle Man
- Class가 간단한 위임을 너무 많이 하고 있는 경우에는
- Client가 대리객체(delegate)를 직접 호출하도록 하라.
Introduce Foreign Method
- 사용하고 있는 서버 Class에 부가적인 Method가 필요하지만 Class를 수정할 수 없는 경우에는
- 첫 번째 인자로 서버 Class의 인스턴스를 받는 Method를 클라이언트에 만들어라
- 동기
- 모든 서비스를 제공하는 정말로 멋진 Class를 사용하고 있다.
- 그러나 꼭 필요하지만 그 Class가 제공하지 않는 서비스가 하나 있다.
- 그런데 소스 코드를 변경할 수 없다면 클라이언트에서 외래 메소드(Foreign Method)로 만들어주는 방법밖에 없다.
- Foreign Method는 임시방편일 뿐
- 절차
- 필요한 작업을 하는 Method를 클라이언트 Class에 만든다.
- 이 Method는 클라이언트 Class의 어떤 부분에도 접근해선 안 됨
- 값이 필요하다면 값을 Parameter로 넘겨야 함
- 첫 번째 Parameter로 서버 Class의 인스턴스를 받도록 함
- Method에 "외래 메소드, 원래 서버 클래스에 있어야 한다."와 같은 주석을 달아 놓는다.
Introduce Local Extension(v)
- 사용하고 있는 서버 Class에 여러 개의 Method를 추가할 필요가 있지만 서버 Class를 수정할 수 없는 경우
- 필요한 추가 Method를 포함하는 새로운 Class를 만들어라.
- 이 확장 Class를 원래 Class의 서브클래스 또는 래퍼 클래스로 만들어라.
- 동기
- Introduce Foreign Method만으로는 감당이 안 될 만큼 Method가 많은 경우
'리팩토링' 카테고리의 다른 글
리팩토링 8장 - 데이터 구성 (0) | 2016.04.02 |
---|---|
리팩토링 6장 - 메소드 정리 (0) | 2016.03.06 |
리팩토링 4장 - 테스트 만들기 (0) | 2016.02.27 |
리팩토링 3장 - 코드 속의 나쁜 냄새 (0) | 2016.02.21 |
리팩토링 2장 - 리팩토링의 원리 (0) | 2016.02.14 |
Comments