[Refactoring] 리팩터링 2판 Chapter.12 (상속 다루기)
카테고리: Refactoring
리팩터링의 마지막 장입니다. 이번 장에서는 객체지향 프로그래밍에서 가장 유명한 특성인 상속을 다룹니다. 다른 강력한 메커니즘처럼 이 역시 아주 유용한 동시에 오용하기 쉽습니다. 더욱이 상속은 발등에 불이 떨어져서야 비로소 잘못 사용했음을 알아차리는 경우가 많습니다.
이번 장에서는 리팩터링의 기법이라기보다는 상속을 언제 어떻게 활용해야 하는지에 대한 내용이 많았습니다. 그리고 필드/메서드를 상위 클래스로 올리기 등 상속의 본질을 생각해본다면 너무 당연한 내용이 많았습니다.
생성자 본문 올리기
상속관계에서 생성자는 다루기 까다롭습니다. 일반 메서드와는 많이 달라서, 생성자에서 하는일에 제약을 둬야합니다.
상속관계에서는 부모클래스부터 생성자가 호출되기 때문에, 제약없이 사용했다간 의도했던 결과가 나오지 않는 경우가 많습니다.
절차
- 슈퍼클래스에 생성자가 없다면 하나 정의한다. 서브클래스의 생성자들에서 이 생성자가 호출되는지 확인한다.
- 문장 슬라이드하기로 공통 문장 모두를 super() 호출 직후로 옮긴다.
- 공통 코드를 슈퍼클래스에 추가하고 서브클래스들에서는 제거한다. 생성자 매개변수 중 공통 코드에서 참조하는 값들을 모두 super()로 건넨다.
- 테스트한다.
- 생성자 시작 부분으로 옮길 수 없는 공통 코드에는 함수 추출하기와 메서드 올리기를 차례로 적용한다.
계층 합치기
클래스 계층구조를 리팩터링하다 보면 기능들을 위로 올리거나 아래로 내리는 일은 다반사로 벌어집니다. 예컨대 계층구조도 진화하면서 어떤 클래스와 그 부모가 너무 비슷해져서 더는 독립적으로 존재해야 할 이유가 사라지는 경우가 생기기도 합니다. 바로 그 둘을 하나로 합쳐야 할 시점입니다.
절차
- 두 클래스 중 제거할 것을 고른다.
- 필드 올리기와 메서드 올리기 혹은 필드 내리기와 메서드 내리기를 적용하여 모든 요소를 하나의 클래스로 옮긴다.
- 제거할 클래스를 참조하던 모든 코드가 남겨질 클래스를 참조하도록 고친다.
- 빈 클래스를 제거한다.
- 테스트한다.
서브클래스를 위임으로 바꾸기
상속에는 큰 단점이 있습니다. 다중상속을 지원하는 언어가 아니라면 단 한번만 쓸 수 있는 카드라는 것입니다.
무언가가 달라져야 하는 이유가 여러 개여도 상속에서는 그중 단 하나의 이유만 선택해 기준으로 삼을 수 밖에 없습니다. 또 다른 문제로, 상속은 클래스들의 관계를 아주 긴밀하게 결합합니다. 부모를 수정하면 이미 존재하는 자식들의 기능에 영향을 미치기도 쉽습니다.
위임은 이상의 두 문제를 모두 해결해줍니다. 다양한 클래스에 서로 다른 이유로 위임할 수 있습니다. 위임은 객체 사이의 일반적인 관계이므로 상호작용에 필요한 인터페이스를 명확히 정의할 수 있습니다. 즉, 상속보다 결합도가 훨씬 약합니다.
유명한 원칙이 하나 있습니다. 클래스 상속보다는 객체 컴포지션을 사용하라 입니다. 여기서 컴포지션은 사실상 위임과 같은 말입니다.
결국, 디자인 패턴에서 말하는 DI를 많이 사용해라라는 뜻으로 이해했습니다. 왜 굳이 DI를 해서 정의하지? 라고 했던것들에 이런 이유가 있었습니다.
절차
- 생성자를 호출하는 곳이 많다면 생성자를 팩터리 함수로 바꾼다.
- 위임으로 활용한 빈 클래스를 만든다. 이 클래스의 생성자는 서브클래스에 특화된 데이터를 전부 받아야 하며, 보통은 슈퍼클래스를 가리키는 역참조도 필요하다.
- 위임을 저장할 필드를 슈퍼클래스에 추가한다.
- 서브클래스 생성 코드를 수정하여 위임 인스턴스를 생성하고 위임 필드에 대입해 초기화 한다.
- 서브클래스의 메서드 중 위임 클래스로 이동할 것을 고른다.
- 함수 옮기기를 적용해 위임 클래스로 옮긴다. 원래 메서드에서 위임하는 코드는 지우지 않는다.
- 서브클래스 외부에도 원래 메서드를 호출하는 코드가 있다면 서브클래스의 위임 코드를 슈퍼클래스로 옮긴다. 이 때위임이 존재하는지를 검사하는 보호 코드로 감싸야한다. 호출하는 외부 코드가 없다면 원래 메서드는 죽은 코드가 되므로 제거한다.
- 테스트한다.
- 서브클래스의 모든 메서드가 옮겨질 때까지 5~8 과정을 반복한다.
- 서브클래스들의 생성자를 호출하는 코드를 찾아서 슈퍼클래스의 생성자를 사용하도록 수정한다.
- 테스트한다.
- 서브클래스를 삭제한다.
리팩터링 소감
여기까지하여 리팩터링 책이 완료되었습니다. 이 책은 읽으면서 제가 코드를 짤 때 바로바로 적용할 수 있어서 좋았던거 같습니다. 해당 책을 읽고 함수단위와 더 나아가 캡슐화에 대해 많이 생각하는 계기가 되었습니다. 또한 사소한 성능이슈를 생각하며 가독성이 낮은 코드를 작성하는것에 대한 강박이 사라지게 되었습니다. 아직 연습이 많이 필요하겠지만, 코드의 질을 올리게 되어 좋았습니다.
댓글 남기기