- 상속의 용도
- 상속의 첫 번째 용도는 타입 계층을 구현하는 것입니다.
- 상속의 두 번째 용도는 코드 재사용입니다.
01. 타입#
개념 관점의 타입#
- 개념 관점에서 타입이란 우리가 인지하는 세상의 사물의 종류를 의미합니다.
- 어떤 대상이 타입으로 분류될 때 그 대상을 타입의 인스턴스(instance) 라고 부릅니다.
- 타입은 심볼, 내연, 외연의 세 가지 요소로 구성됩니다.
- 심볼 : 타입에 이름을 붙인 것
- 내연 : 타입의 정의로서 타입에 속하는 객체들이 가지는 공통적인 속성이나 행동
- 외연 : 타입에 속하는 객체들의 집합
프로그래밍 언어 관점의 타입#
- 타입은 두 가지 목적을 위해 사용됩니다.
- 타입에 수행될 수 있는 유효한 오퍼레이션의 집합을 정의합니다.
- 타입에 수행되는 오퍼레이션에 대해 미리 약속된 문맥을 제공합니다.
객체지향 패러다임 관점의 타입#
- 타입은 두 가지 관점에서 정의할 수 있습니다.
- 개념 관점에서 타입이란 공통의 특징을 공유하는 대상들의 분류입니다.
- 프로그래밍 언어 관점에서 타입이란 동일한 오퍼레이션을 적용할 수 있는 인스턴스들의 집합입니다.
- 객체의 퍼블릭 인터페이스가 객체의 타입을 결정합니다. 동일한 퍼블릭 인터페이스를 제공하는 객체들을 동일한 타입으로 분류됩니다.
02. 타입 계층#
타입 사이의 포함관계#
- 타입 계층을 구성하는 두 타입 간의 관계에서 더 일반적인 타입을 슈퍼타입(supertype) 이라고 부르고 더 특수한 타입을 서브타입(subtype) 이라고 부릅니다.
- 일반화는 다른 타입을 완전히 포함하거나 내포하는 타입을 식별하는 행위 또는 그 행위의 결과를 가리키고, 특수화는 다른 타입 안에 전체적으로 포함되거나 완전히 내포되는 타입을 식별하는 행위 또는 그 행위의 결과를 가리킵니다.
- 슈퍼타입은 다음과 같은 특징을 가지는 타입을 가리킵니다.
- 집합이 다른 집합의 모든 멤버를 포함합니다.
- 타입 정의가 다른 타입보다 좀 더 일반적입니다.
- 서브타입은 다음과 같은 특징을 가지는 타입을 가리킵니다.
- 집합에 포함되는 인스턴스들이 더 큰 집합에 포함됩니다.
- 타입 정의가 다른 타입보다 좀 더 구체적이다.
객체지향 프로그래밍과 타입 계층#
- 슈퍼타입이란 서브타입이 정의한 퍼블릭 인터페이스를 일반화시켜 상대적으로 범용적이고 넓은 의미로 정의한 것입니다.
- 서브타입이란 슈퍼타입이 정의한 퍼블릭 인터페이스를 특수화시켜 상대적으로 구체적이고 좁은 의미로 정의한 것입니다.
03. 서브클래싱과 서브타이핑#
언제 상속을 사용해야 하는가?#
- 상속 관계가 Is-a 관계를 모델링하는가
- 클라이언트 입장에서 부모 클래스의 타입으로 자식 클래스를 사용해도 무방한가?
is-a 관계#
- 성급하게 상속을 적용하려고 서두르지 말고,애플리케이션이 어떤 방식으로 사용되고 협력하는지 살펴본 후에 상속의 적용여부를 봐도 괜찮습니다.
행동 호환성#
- 행동의 호환 여부를 판단하는 기준은 클라이언트 관점입니다.
클라이언트의 기대에 따라 계층 분리하기#
- 행동 호환성을 만족시키지 않는 상속 계층을 그대로 유지한 채 클라이언트의 기대를 충족하는 방법은 클라이언트의 기대에 맞게 상속 계층을 분리하는 방법 뿐입니다.
- 클라이언트의 기대에 따라 분리함으로써 변경에 의해 영향을 제어하는 설계 원칙을 인터페이스 분리 원칙(ISP)라고 합니다.
서브클래싱과 서브타이핑#
- 상속을 사용하는 두 가지 목적은 서브클래싱과 서브타이핑입니다.
- 서브클래싱
- 다른 클래스의 코드를 재사용할 목적으로 상속을 사용하는 경우
- 구현 상속 혹은 클래스 상속
- 서브타이핑
- 타입 계층을 구성하기 위해 상속을 사용하는 경우
- 인터페이스 상속
- 자식 클래스와 부모 클래스 사이의 행동 호환성은 부모 클래스에 대한 자식 클래스의 대체 가능성(substitutability)을 포함합니다.
04. 리스코프 치환 원칙#
- 리스코프 치환 원칙을 한마디로 정리하면 "서브타입은 그것의 기반 타입에 대해 대체 가능해야 한다"입니다.
클라이언트와 대체 가능성#
- 대체 가능성을 결정하는 것은 클라이언트입니다.
is-a 관계 다시 살펴보기#
- 상속이 서브타이핑을 위해 사용될 경우에만 is-a 관계입니다.
리스코프 치환 원칙은 유연한 설계의 기반이다#
- 아래 원칙을 합쳐서 설계를 확장 가능하게 만듭니다.
- 의존성 역전 원칙
- 리스코프 치환 원칙
- 개방-폐쇄 원칙
- 리스코프 치환 원칙은 개방-폐쇄 원칙을 만족하는 설계를 위한 전제 조건입니다.
타입 계층과 리스코프 치환 원칙#
- 구현 방법과 무관하게 클라이언트의 관점에서 슈퍼타입에 대해 기대하는 모든 것이 서브타입에게도 적용돼야 한다는 것입니다.
05. 계약에 의한 설계와 서브타이핑#
- 클라이언트와 서버 사이의 협력을 의무와 이익으로 구성된 계약의 관점에서 표현하는 것을 계약에 의한 설계(Design By Contract, DBC) 라고 부릅니다.
- 사전조건(precondition) : 클라이언트가 정상적으로 메서드를 실행하기 위해 만족시켜야 하는 조건
- 사후조건(postcondition) : 메서드가 실행된 후에 서버가 클라이언트에게 보장해야 하는 조건
- 클래스 불변식(class invariant) : 메서드 실행 전과 실행 후에 인스턴스가 만족시켜야 하는 식
- 위의 세 가지 요소로 구성됩니다.
- 서브타입이 리스코프 치환 원칙을 만족시키기 위해서는 클라이언트와 슈퍼타입 간에 체결된 '계약'을 준수해야 합니다.
서브타입과 계약#
- 계약의 관점에서 상속이 초래하는 가장 큰 문제는 자식 클래스가 부모 클래스의 메서드를 오버라이딩할 수 있다는 것입니다.
- 서브타입에 더 강력한 사전조건을 정의할 수 없습니다.
- 서브타입에 슈퍼타입과 같거나 더 약한 사전조건을 정의할 수 있습니다.
- 서브타입에 슈퍼타입과 같거나 더 강한 사후조건을 정의할 수 있습니다.
- 서브타입에 더 약한 사후조건을 정의할 수 없습니다.