SerialDate라는 클래스가 실제로 나타내는 개념은 serial number(일련 번호)가 아닌 ordinal number(서수). 즉 클래스 이름과 개념이 일치하지 않음
SerialDate라는 이름은 구현 클래스라는 것을 암시함. 그러나 실제로 SerialDate는 추상 클래스이고, 가장 최선은 구현/추상 여부가 이름에 드러나지 않는 것.
저자는 DayDate라는 이름을 추천함
MonthConstants는 인터페이스가 아니라 enum이 되야함
- 불필요한 코멘트 제거
- 추상 클래스와 구현 클래스
SerialDate는 아래와 같이 MINIMUM_YEAR_SUPPORTED와 MAXIMUM_YEAR_SUPPORTED 멤버 프로퍼티를 갖고 있으며 이는 구현에 해당함. 그러나 추상 클래스는 구현에 대한 어떠한 암시도 하지 않아야 함.
저자는 이 문제를 해결하기 위해 프로퍼티들을 구현 클래스인 SpreadSheetDate로 보내고 싶어함.
그러나 이 변수들을 구현부로 보내버리면 SerialDate를 사용하는 클래스들이 SerialDate의 구현에 대한 정보까지 필요로 하게 된다는 점이다. 일반적으로는 SerialDate의 구현 클래스의 인스턴스를 변수로 넘기는 방식이 사용된다. 그러나 SerialDate.MINIMUM_YEAR_SUPPORTED 실제 사용하고 있는 함수(getDate)라는 함수를 보면 인스턴스를 전달 받는 게 아니라, 반대로 인스턴스를 리턴하고 있다. 결국 이 함수 내부 어딘가에서 SerialDate의 구현 클래스의 인스턴스가 생성된다는 뜻이다.
인스턴스가 생성되는 위치를 추적해보면 SerialDate는 아래와 같이 createInstance라는 메소드를 통해 SpreadsheetDate라는 구현클래스의 인스턴스를 생성할 수 있다.
**베이스 클래스가 구현 클래스에 대해 알게 하는 것은 일반적으로 좋지 않다.**
어떻게 이 문제를 해결할 수 있을까?
AbstractFactory 패턴을 사용하면 된다
- 중복 코드 제거
- 불필요한 함수 쪼개기 제거
- 잘못된 static 키워드 제거
addDays의 인자로 SerialDate base를 받고있음. 구현 클래스의 인스턴스를 인자로 받고 있으므로 이 함수는 static이 될 수 없음
Chapter 16 Refactoring SerialDate
Make it work
유닛 테스트 보완
유닛테스트 보완 결과 노출된 버그 예시
문제코드 수정 전
문제코드 수정 후
Make it right