Skip to main content

13. 서브클래싱과 서브타이핑

  • 상속의 용도
    • 상속의 첫 번째 용도는 타입 계층을 구현하는 것입니다.
    • 상속의 두 번째 용도는 코드 재사용입니다.

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) : 메서드 실행 전과 실행 후에 인스턴스가 만족시켜야 하는 식
    • 위의 세 가지 요소로 구성됩니다.
  • 서브타입이 리스코프 치환 원칙을 만족시키기 위해서는 클라이언트와 슈퍼타입 간에 체결된 '계약'을 준수해야 합니다.

서브타입과 계약#

  • 계약의 관점에서 상속이 초래하는 가장 큰 문제는 자식 클래스가 부모 클래스의 메서드를 오버라이딩할 수 있다는 것입니다.
  • 서브타입에 더 강력한 사전조건을 정의할 수 없습니다.
  • 서브타입에 슈퍼타입과 같거나 더 약한 사전조건을 정의할 수 있습니다.
  • 서브타입에 슈퍼타입과 같거나 더 강한 사후조건을 정의할 수 있습니다.
  • 서브타입에 더 약한 사후조건을 정의할 수 없습니다.
Last updated on