클래스를 재사용하기 위해 새로운 클래스를 추가하는 가장 대표적인 기법인 상속에 관해 살펴보자.
중복 코드는 변경을 방해한다. 프로그램의 본질은 비즈니스와 관련된 지식을 코드로 변환하는 것인데 이 지식은 항상 변한다. 그런데 코드가 중복되면 중복된 코드를 하나하나 찾아서 변경해야 한다.
중복 코드란 무엇인가? 요구사항이 변경됐을 때 두 코드를 함께 수정해야 한다면 이 코드는 중복이다. 함께 수정할 필요가 없다면 중복이 아니다. 모양이 유사한 것은 중복의 징후일 뿐이다.
한 달에 한 번씩 가입자별로 전화요금을 계산하는 간단한 애플리케이션을 개발한다. 요금 계산은 10초당 5원이다.
먼저 개별 통화기간은 저장하는 Call 클래스, Call의 목록을 관리하는 Phone 클래스를 생성하자.
하지만 요구사항은 항상 변한다. 시간이 흘러 심야할인 요금제가 생겼다면 어떻게 될까? 가장 쉽고 빠른 방법은 Phone의 코드를 복사해 NightlyDiscountPhone이라는 새로운 클래스를 만드는 것이다.
그런데 이후 세금을 계산한다는 새로운 요구사항이 생겼다. 세율은 핸드폰마다 다르다고 가정한다. 지금 통화 요금을 계산하는 로직은 Phone, NightlyDiscountPhone 양쪽 모두에 구현되어 있다. 둘 모두 인스턴스 변수인 taxRate를 추가하고 요금에 세율을 반영하도록 calculateFee 메서드를 수정한다.
이런 경우 모든 중복 코드를 식별하고 함께 수정해야한다. 하나라도 빼뜨리면 문제가 생긴다. 한 발 양보해서 모든 중복을 식별하고 함께 수정했다고 가정하자. 더 큰 문제는 중복 코드를 서로 다르게 수정하기 쉽다는 것이다. 실수를 아무도 눈치챌 수 없다.
중복을 제거하는 한 가지 방법은 클래스를 하나로 합치는 것이다. 요금제를 구분하는 타입을 추가하고 조건문을 사용해 분기할 수 있다. 하지만 조건문을 사용해 구분하는 것은 낮은 응집도와 높은 결합도라는 문제에 시달리게 된다.
객체지향 언어는 타입 코드를 사용하지 않고 중복을 관리할 수 있는 효과적인 방법이다. 가장 유명한 방법은 상속이다.
상속의 기본 아이디어는 이미 존재하는 클래스와 유사한 클래스가 필요하다면 코드를 복사하지 말고 상속으로 코드를 재사용하는 것이다.
고로 NightlyDiscountPhone 클래스가 Phone을 상속받도록 하자.