7. 서브클래스 제거하기서브클래싱?서브클래싱의 문제점절차예시8. 슈퍼클래스 추출하기저자가 말하는 상속절차예시9. 계층 합치기절차10. 서브클래스를 위임으로 바꾸기저자가 말하는 상속의 단점상속은 위험할까?절차예시정말 서브클래스를 위임으로 바꿔야 하는 구조일까? 🤔11. 슈퍼클래스를 위임으로 바꾸기위임의 단점절차예시
7. 서브클래스 제거하기
서브클래싱?
- 원래 데이터 구조와는 다른 변종을 만들거나 종류에 따라 동작이 달라지게 할 수 있는 유용한 메커니즘이다.
- 다름을 프로그래밍하는 멋진 수단
서브클래싱의 문제점
- 시스템 규모가 커짐에 따라 서브클래스가 다른 모듈로 이동하거나 사라져서 활용되지 않을 수 있다.
- 서브클래스를 필요로 하지 않는 방식으로 만들어진 기능에서만 사용되기도 한다.
절차
- 서브클래스의 생성자를 팩터리 함수로 변경한다.
- 서브클래스의 타입을 검사하는 코드가 있다면, 함수 추출하기와 함수 옮기기를 차례로 적용하여 슈퍼클래스로 옮긴다.
- 서브클래스의 타입을 나태내는 필드를 슈퍼클래스에 만든다.
- 서브클래스를 참조하는 메서드가 방금 만든 타입 필드를 이용하도록 수정한다.
- 서브클래스를 지운다.
- 테스트한다.
예시
리팩터링
8. 슈퍼클래스 추출하기
저자가 말하는 상속
‘현실 세계의 분류 체계를 기초로 하여 부모-자식 관계를 신중하게 설계해야 한다.’ 라는 말처럼 현실 세계의 분류 체계는 상속을 적용하는데 힌트가 될 수 있지만, 상속은 슈퍼클래스로 끌어올리고 싶은 공통 요소를 찾았을 때 수행하는 사례가 잦았다.
- 비슷한 일을 수행하는 두 클래스가 있을 때 비슷한 부분을 슈퍼클래스로 옮겨 상속 관계를 형성할 수 있다.
절차
- 빈 슈퍼클래스를 만든다. 원래의 클래스들이 새 클래스를 상속하도록 한다.
- 테스트한다.
- 생성자 본문 올리기, 메서드 올리기, 필드 올리기를 차례로 적용하여 공통 원소를 슈퍼클래스로 옮긴다.
- 서브클래스에 남은 메서드들을 검토한다. 공통되는 부분은 함수로 추출한 다음 메서드 올리기를 적용한다.
- 원래 클래스를 사용하는 코드를 검토하여 슈퍼 클래스의 인터페이스를 사용하게 할지 고민한다.
예시
리팩터링
9. 계층 합치기
- 슈퍼클래스와 서브클래스가 비슷해져 독립적으로 존재해야 할 이유가 사라지는 경우에 적용할 수 있다.
절차
- 두 클래스 중 제거할 것을 고른다.
- 필드 올리기와 메서드 올리기 혹은 필드 내리기와 메서드 내리기를 적용하여 모든 요소를 하나의 클래스로 옮긴다.
- 제거할 클래스를 참조하던 모든 코드가 남겨질 클래스를 참조하도록 고친다.
- 빈 클래스를 제거한다.
- 테스트한다.
10. 서브클래스를 위임으로 바꾸기
저자가 말하는 상속의 단점
- 달라져야 하는 이유가 여러 개여도 상속에서는 단 하나의 이유만 선택해 기준으로 삼는다.
- 젊은이 - 어르신
- 부자 - 서민
- 관계가 긴밀하여 부모를 수정했을 때 자식에서 발생할 수 있는 사이드 이펙트를 주의해야 한다.
상속은 위험할까?
클래스의 상속보다 객체 컴포지션을 사용하라!
많은 사람들이 이 원칙을 듣고 ‘상속은 위험하다’라고 받아들여서 상속을 하면 안된다고 주장한다고 한다. 이 원칙은 상속을 쓰지 말라는 말이 아닌, 과용하는데 따른 반작용으로 나온 것이다.
책의 저자는 언제든 서브클래스를 위임으로 바꿀 수 있음을 알기에, 처음에는 상속으로 접근하고 문제가 생기면 위임으로 갈아탄다고 설명한다.
절차
- 생성자를 호출하는 곳이 많다면 생성자를 팩터리 함수로 바꾼다.
- 위임으로 활용할 빈 클래스를 만든다. 이 클래스의 생성자는 서브클래스에 특화된 데이터를 전부 받아야 하며, 보통은 슈퍼클래스를 가리키는 역참조도 필요하다.
- 위임을 저장할 필드를 슈퍼클래스에 추가한다.
- 서브클래스 생성 코드를 수정하여 위임 인스턴스를 생성하고 위임 필드에 대입해 초기화한다.
- 서브클래스의 메서드 중 위임 클래스로 이동할 것을 고른다.
- 함수 옮기기를 적용해 위임 클래스로 옮긴다. 원래 메서드에서 위임하는 코드는 지우지 않는다.
- 서브클래스 외부에도 원래 메서드를 호출하는 코드가 있다면 서브클래스의 위임 코드를 슈퍼클래스로 옮긴다.
- 위임이 존재하는지를 검사하는 보호 코드로 감싸야 한다. 호출하는 외부 코드가 없다면 원래 메서드는 죽은 코드가 되므로 제거한다.
- 테스트한다.
- 서브클래스의 모든 메서드가 옮겨질 때까지 5~8 과정을 반복한다.
- 서브클래스들의 생성자를 호출하는 코드를 찾아서 슈퍼클래스의 생성자를 사용하도록 수정한다.
- 테스트한다.
- 서브클래스를 삭제한다.
예시
정말 서브클래스를 위임으로 바꿔야 하는 구조일까? 🤔
만약 일반 예약과 프리미엄 예약을 자유롭게 전환해야 한다면 어떨까?
- HTTP 요청을 통해 새로운 데이터를 받아서 처리한다.
- 새로 받아오는 방법을 사용하지 못하고, 데이터 구조를 수정해야 하는 상황 이라면?
- 수 많은 곳에서 참조되는 예약 인스턴스를 어떻게 교체하지?
위 예시가 와닿지 않는다면, 예약을 일반과 프리미엄이라는 기준 대신 다른 기준을 가져가야 한다면 어떨까?
리팩터링
11. 슈퍼클래스를 위임으로 바꾸기
위임의 단점
- 위임의 기능을 이용할 호스트의 함수를 모두 전달 함수로 만들어야 한다.
절차
- 슈퍼클래스 객체를 참조하는 필드를 서브클래스에 만든다. 위임 참조를 새로운 슈퍼클래스 인스턴스로 초기화한다.
- 슈퍼클래스의 동작 각각에 대응하는 전달 함수를 서브클래스에 만든다.
- 서로 관련된 함수끼리 그룹으로 묶어 진행하며, 그룹을 하나씩 만들 때마다 테스트한다.