10장: 상속과 코드 재사용
상속과 중복 코드
DRY 원칙
Don’t Repeat Yourself라는 뜻으로, 동일한 것을 중복하지 말라는 것이다.
모든 지식은 시스템 내에서 단일하고, 애매하지 않고, 정말로 믿을 만한 표현 양식을 가져야 한다.
중복이라고 판단하는 기준은 요구사항이 변경되었을 때 두 코드를 함께 수정해야 하는가이다.
중복 코드는 새로운 중복 코드를 부른다. 그리고 이를 추가하는 과정에서 코드의 일관성이 무너지고 버그가 발생할 수 있으며 코드의 변경 속도가 느려진다.
이미 존재하는 클래스와 유사한 클래스가 필요하다면 코드를 복사하지 말고 상속을 이용해 코드를 재사용할 수 있다.
상속을 이용해 코드를 재사용하기 위해서는 부모 클래스의 개발자가 세웠던 가정이나 추론 과정을 정확하게 이해해야 한다.
이로 인해 상속은 부모 클래스와 자식 클래스 간의 결합도를 높이며 코드를 수정하기 어렵게 만든다.
자식 클래스의 메서드 안에서 super 참조를 이용해 부모 클래스의 메서드를 직접 호출할 경우 두 클래스는 강하게 결합된다. super 호출을 제거할 수 있는 방법을 찾아 결합도를 제거해야 한다.
예를 들면 Phone 클래스의 요금을 계산하는 calculateFee 메서드와 이를 상속받은 NightlyDiscountPhone 클래스의 calculateFee 메서드가 있다고 한다. 이 때 NightlyDiscountPhone 클래스의 calculateFee 메서드는 super.calculateFee 를 호출한다. 이 때 세금을 부과하는 요구사항이 추가되면, Phone 클래스의 calculateFee 메서드에 세금을 부과하는 로직을 적용하고, NightlyDiscountPhone 클래스의 calculateFee 메서드에서 야간 할인을 적용하는 경우에도 세금을 부과하는 로직을 적용해야 한다.
취약한 기반 클래스 문제
부모 클래스의 변경에 의해 자식 클래스가 영향을 받는 현상
부모 클래스의 작은 변경에도 자식 클래스는 컴파일 오류와 실행 에러가 발생할 수 있다.
상속은 자식 클래스가 부모 클래스의 구현 세부사항에 의존하도록 만들기 때문에 캡슐화를 약화시킨다.
상속받은 부모 클래스의 메서드가 자식 클래스의 내부 구조에 대한 규칙을 깨트릴 수 있다.
Java Util의 Vector 클래스를 상속받는 Stack 클래스는 맨 마지막 위치에서만 요소를 추가/제거할 수 있는 메서드 뿐만 아니라 get, add 등과 같이 원하는 원소를 조회/추가할 수 있는 Vector 클래스의 메서드를 사용할 수 있으므로 Stack의 규칙을 파괴하는 안좋은 예시이다.
자식 클래스가 부모 클래스의 메서드를 오버라이딩할 경우 부모 클래스가 자신의 메서드를 사용하는 방법에 자식 클래스가 결합될 수 있다.
클래스가 상속되기를 원한다면 상속을 위해 클래스를 설계하고 문서화해야 하며, 그렇지 않은 경우에는 상속을 금지시켜야 한다. 하지만 내부구현을 드러내야 하는 것은 결국 상속이 캡슐화를 위반하기 때문에 발생하는 것이다.
클래스를 상속하면 결합도로 인해 자식 클래스와 부모 클래스의 구현을 영원히 변경하지 않거나, 자식 클래스와 부모 클래스를 동시에 변경하거나 둘 중 하나를 선택할 수밖에 없다.
추상화
어떤 클래스가 있다면 무작정 상속하는 대신 추상화한 객체를 상속받도록 해야 한다.
어떤 메서드의 중복을 제거하기 위해 재정의하고 있다면, 이에서 공통된 부분을 뽑아 추상 클래스의 메서드로 두고 변하는 부분은 추상 메서드로 재정의하도록 한다.
아래는 Phone이라는 추상 클래스를 기본 요금 정책을 사용하는 RegularPhone과 야간 할인 정책을 사용하는 NightlyDiscountPhone이 상속받는 구조를 보여준다.
자식 클래스는 자신의 인스턴스를 생성할 때 부모 클래스에 정의된 인스턴스 변수를 초기화해야 하기 때문에 자연스럽게 부모 클래스에 추가된 인스턴스 변수는 자식 클래스의 초기화 로직에 영향을 미치게 된다.
차이에 의한 프로그래밍
기존 코드와 다른 부분만을 추가함으로써 애플리케이션의 기능을 확장하는 방법
상속을 이용하면 이미 존재하는 클래스의 코드를 쉽게 재사용할 수 있기 때문에 애플리케이션의 점진적인 정의(incremental definition)가 가능해진다.
중복 코드를 제거해 하나의 모듈로 모아 코드를 재사용한다면 코드의 품질을 유지하면서 코드 작성에 들이는 노력과 테스트를 줄일 수 있다.
Last updated