13장: 상속의 본질 - 타입 계층과 다형성
상속의 진정한 목적이 코드 재사용이 아니라 '타입 계층'을 구축하는 것
1. 상속의 두 얼굴: 서브클래싱 vs 서브타이핑
책에서는 상속을 사용하는 용도를 엄격하게 두 가지로 구분한다.
- 서브클래싱 (Subclassing - 구현 상속)
- 단순히 부모 클래스의 코드를 재사용하기 위해 상속을 사용하는 경우를 말한다.
- 이는 부모와 자식 간의 결합도를 높여 변경에 취약한 설계를 만든다.
- 10장에서 비판했던 방식이 바로 이 서브클래싱이다.
- 서브타이핑 (Subtyping - 인터페이스 상속)
- 부모 클래스가 정의한 타입 계층을 물려받아 다형적으로 동작하기 위해 상속을 사용하는 것을 의미한다.
- 객체지향 설계에서 상속을 사용하는 유일하고 올바른 목적이다.
2. 대체 가능성을 결정하는 기준: 리스코프 치환 원칙 (LSP)
올바른 상속(서브타이핑)인지 판단하는 기준은 SOLID 원칙 중 하나인 리스코프 치환 원칙(LSP)이다.
- 행동 호환성: 자식 클래스는 부모 클래스의 역할을 완벽하게 대체할 수 있어야 한다.
- 클라이언트 관점의 중요성: 상속 관계의 적절성은 현실 세계의 어휘적 분류(
is-a)가 아니라, 해당 객체를 사용하는 클라이언트의 기대에 따라 결정된다.
예: 펭귄은 새인가?
현실에서는 펭귄이 새(Bird)이지만, 소프트웨어 클라이언트가 새에게 '날기(fly)’를 기대한다면 펭귄은 새를 상속받아서는 안 된다. 펭귄은 날 수 없으므로 클라이언트의 기대를 저버리기 때문이다.
- 결론: 상속 관계가 올바른지 판단할 때는 반드시 문장 앞에 "클라이언트 입장에서"라는 전제를 붙여야 한다. 직사각형과 정사각형 예시 역시 클라이언트의 기대를 배신하므로 상속을 사용해서는 안 되는 대표적 사례다.
3. 계약에 의한 설계 (Design by Contract)
리스코프 치환 원칙을 더 엄밀하게 설명하기 위해 '계약'이라는 개념을 도입한다. 클라이언트와 부모 클래스 사이의 약속을 자식이 어떻게 지켜야 하는지를 규정한다.
- 사전조건 강화 불가: 자식 클래스는 부모 클래스보다 더 까다로운 조건(사전조건)을 클라이언트에게 요구해서는 안 된다. 클라이언트가 부모 수준의 조건만 맞췄음에도 자식이 에러를 던지면 시스템은 붕괴된다.
- 사후조건 완화 불가: 자식 클래스는 부모 클래스가 보장해주던 결과(사후조건)를 더 약하게 보장해서는 안 된다. 클라이언트는 부모가 보장하던 최소한의 결과를 얻으리라 믿고 코드를 작성하기 때문이다.
정리하며
결국 상속은 코드를 편하게 쓰기 위한 수단이 아니라, 클라이언트의 관점에서 동일하게 행동하는 객체들의 집합(타입 계층)을 만들기 위해 사용해야 한다
'서적 > Object' 카테고리의 다른 글
| 14장 일관성 있는 협력 / 15장 디자인 패턴과 프레임워크 (5) | 2026.04.07 |
|---|---|
| 11장 합성과 유연한 설계 (7) | 2026.03.18 |
| 10장 상속과 코드 재사용 (3) | 2026.03.08 |
| 9장 유연한 설계 (6) | 2026.03.04 |
| 6장 메시지와 인터페이스 / 8장 의존성 관리하기 (8) | 2026.02.24 |