오브젝트 - 13. 서브클래싱과 서브타이핑

강준혁·2022년 9월 20일
0

오브젝트

목록 보기
13/14
post-thumbnail

상속의 첫번째 용도는 타입 계층을 구현하는 것이다. 부모 클래스는 일반적인 개념을, 자식 클래스는 특수한 개념을 구현한다.

두 번째 용도는 코드 재사용이다. 상속은 간단한 선언만으로 부모 클래스의 코드를 재사용할 수 있게 한다.

상속을 사용하는 일차적인 목표는 코드 재사용이 아닌 타입계층 구현이 되어야 한다.
상속은 부모/자식 클래스간의 결합도를 높이기에 설계의 변경과 진화를 방해한다.
반면 타입 계층을 목표로 상속을 사용하면 다형적으로 동작하는 객체들의 관계에 기반해 확장 가능하고 유연한 설계를 얻을 수 있게 된다.

동일한 메시지에 대해 서로 다르게 행동할 수 있는 다형적인 객체를 구현하기 위해서는 객체의 행동을 기반으로 타입 계층을 구성해야 한다.

타입

프로그래밍 언어 관점의 타입

프로그래밍 언어에서 타입은 두 가지 목적을 위해 사용된다.

  • 타입에 수행될 수 있는 유효한 오퍼레이션의 집합을 정의한다

자바에서 '+' 연산자는 원시형 숫자/문자열 타입의 객체에는 사용가능하지만 다른 클래스의 인스턴스에 대해서는 사용할 수 없다. 모든 객체지향 언어들은 객체의 타입에 따라 적용 가능한 연산자의 종류를 제한함으로써 프로그래머의 실수를 막는다.

  • 타입에 수행되는 오퍼레이션에 대해 미리 약속된 문맥을 제공한다

자바에서 a + b 라는 연산이 있을 때 각 타입이 int타입인지, String 타입인지에 따라 다르게 동작한다.

객체지향 패러다임 관점의 타입

객체지향 프로그래밍에서 오퍼레이션은 객체가 수신할 수 있는 메시지를 의미한다. 그리고 이 메시지의 집합은 객체의 퍼블릭 인터페이스이다.

따라서 객체지향 프로그래밍 관점에서는 타입을 다음과 같이 정의할 수 있다.

객체의 퍼블릭 인터페이스가 객체의 타입을 정의한다. 동일한 퍼블릭 인터페이스를 제공하는 객체들은 동일한 타입으로 분류된다.

객체에서 중요한 것은 속성이 아니라 행동이다.
어떤 객체들이 동일한 상태를 가지고 있더라도 퍼블릭 인터페이스가 다르다면 이들은 서로 다른 타입으로 분류된다.
반대로 어떤 객체들이 내부 상태는 다르지만 동일한 퍼블릭 인터페이스를 공유한다면 이들은 동일한 타입으로 분류된다.

타입 계층

슈퍼타입과 서브 타입

슈퍼 타입은 다음과 같은 특징을 가지는 타입을 말한다.

  • 집합이 다른 집합의 모든 멤버를 포함한다.
  • 타입 정의가 다른 타입보다 좀 더 일반적이다.

서브 타입은 다음과 같은 특징을 가지는 타입을 말한다.

  • 집합에 포함되는 인스턴스들이 더 큰 집합에 포함된다.
  • 타입 정의가 다른 타입보다 좀 더 구체적이다.

객체지향 프로그래밍과 타입 계층

더 일반적인 퍼블릭 인터페이스를 가지는 객체들은 더 특수한 퍼블릭 인터페이스를 가지는 객체들의 슈퍼타입이다.
서브 타입의 인스턴스 집합은 슈퍼타입의 인스턴스 집합의 부분집합이기 때문에 더 특수한 퍼블릭 인터페이스를 가지는 객체들은 동시에 더 일반적인 퍼블릭 인터페이스를 가지는 객체들의 집합에 포함된다.

서브클래싱과 서브타이핑

언제 상속을 사용해야 하는가?

아래의 조건을 모두 만족할 때 상속을 사용해야 한다.

  • 상속 관계가 is - a 관계를 모델링 하는가
  • 클라이언트 입장에서 부모 클래스의 타입으로 자식클래스를 사용해도 무방한가

is - a 관계

is - a 관계를 정의할 때에는 어휘적인 정의가 아닌 기대되는 행동에 따라 타입계층을 구성해야 한다.
어휘적으로 펭귄은 새지만 새에 날 수 있다는 행동이 포함된다면 펭귄은 새의 서브타입이 될 수 없다.

너무 성급하게 상속을 사용하려 하지마라. 애플리케이션 안에서 두 가지 후보 개념이 어떤 방식으로 사용되고 협력하는지 살펴본 후에 상속의 적용여부를 결정해도 늦지 않다.

행동 호환성

행동의 호환여부를 판단하는 기준은 클라이어트의 관점이다.
클라이언트가 두 타입이 동일하게 행동할 것이라고 기대한다면 두 타입을 타입 계층으로 묶을 수 있다.

서브 클래싱과 서브 타이핑

  • 서브 클래싱 : 다른 클래스의 코드를 재사용할 목적으로 상속을 사용하는 경우를 말한다. 자식 클래스와 부모 클래스의 행동이 호환되지 않기 때문에 자식 클래스의 인스턴스가 부모 클래스의 인스턴스를 대체할 수 없다.

  • 서브 타이핑 : 타입 계층을 구성하기 위해 상속을 사용하는 경우를 말한다. 서브타이핑에서는 자식 클래스와 부모 클래스의 행동이 호환되기 때문에 자식 클래스의 인스턴스가 부모 클래스의 인스턴스를 대체할 수 있다.
    서브 타이핑을 인터페이스 상속이라고 부르기도 한다.

슈퍼타입과 서브타입 사이의 관계에서 가장 중요한 것은 퍼블릭 인터페이스다.
슈퍼타입 인스턴스를 요구하는 모든 곳에서 서브타입의 인스턴스를 대신 사용하기 위해 만족해야 하는 최소한의 조건은 서브타입의 퍼블릭 인터페이스가 슈퍼타입에서 정의한 퍼블릭 인터페이스와 동일하거나 더 많은 오퍼레이션을 포함해야 한다는 것이다.

서브타이핑 관계가 유지되기 위해서는 서브타입이 슈퍼타입이 하는 모든 행동을 동일하게 할 수 있어야 한다. 즉 어떤 타입이 다른 타입의 서브타입이 되기 위해서는 행동 호환성을 만족시켜야 한다.

리스코프 치환 원칙

리스코프 치환 원칙은 "서브타입은 그것의 기반 타입에 대해 대체 가능해야 한다" 는 것으로 "클라이언트가 차이점을 인식하지 못한 채 기반 클래스의 인터페이스를 통해 서브클래스를 사용할 수 있어야 한다" 는 것이다.

리스코프 치환 원칙은 자식 클래스가 부모 클래스를 대체하기 위해서는 부모 클래스에 대한 클라이언트의 가정을 준수해야 한다는 것을 강조한다.
정사각형을 직사각형의 자식클래스로 만드는 것은 직사각형에 대해 클라이언트가 세운 가정을 송두리째 뒤흔드는 것이다.

profile
백엔드 개발자

0개의 댓글