본문 바로가기

자바 언어 & 객체지향 지식

Subtyping VS Subclassing

출처: https://velog.io/@hylee/Java-%EC%83%81%EC%86%8D%EA%B3%BC-%EA%B5%AC%EC%B2%B4%ED%99%94-1.-%ED%81%B4%EB%9E%98%EC%8A%A4-%EA%B0%84-%EA%B4%80%EA%B3%84-%EA%B0%9D%EC%B2%B4-%EA%B0%84-%EA%B4%80%EA%B3%84

 

출처: https://incheol-jung.gitbook.io/docs/study/object/2020-03-10-object-chap13

 

Subclassing=한 클래스의 상태와 행위를 재사용하는 것(=상속하는 것, 즉 상태와 구현한 행위들을 통째로 재사용하는 것을 말함). 

 

Subtyping (=구체화 관계)= (인터페이스의) 외부모습만 재사용 한것(=인터페이스를 구현하는 것). (한 클래스가 인터페이스를 구현하는 것)

 

중요한 것은 Subtyping이 반드시 인터페이스를 구현하는 것은 아니라는 것이다. 인터페이스를 구현하는 것은 자바에서의 Subtyping의 개념인것이지 언어를 초월한 개념적인 면에서 Subtyping은 외부모습만 재사용 하는 것이다!

 

그리고 재미있게도 상속이라는 개념은 Subclassing도 맞고 Subtyping도 맞다. 어떻게 상속이 Subtyping인가?

아래 코드에서 장식자(CondimentDecorator)는 상속을 하지만(Beverage를 상속), 상속의 목적이 subClassing에 있지 않음. getDescription을 추상메서드로 만들기 위함. 즉 외부모습만 재사용하기 위함. 따라서 상속을 통해 외부모습만 재사용하는 subtyping인 것이다.

 

앞서 클래스 간 관계를 상속과 구체화로 구분하였지만 이 구분은 자바에 적용되는 개념이고, 실제 객체지향에서는 클래스 간 관계를 subclassing과 subtyping으로 구분한다.

Subclassing

한 클래스의 상태와 행위의 구현을 재사용하는 것

Subtyping

외부 모습만 재사용하는 것을 말한다

특히, B가 A의 subtype이면(=B가 A의 모습만을 재사용한것. 즉 B는 A의 인터페이스일 가능성이 높음) A 타입을 기대하는 어느 곳이나 B 타입의 객체(=인터페이스 B를 구현한 클래스의 객체)를 안전하게 사용할 수 있어야 한다. 이것을 대체가능성(substitutability)이라 한다.
Subclassing을 하면 subtyping의 효과를 얻을 수 있지만(당연한말. 상속을 하면 외부모습만 재사용할 수 있는 효과가 있음) 언어마다 subclassing과 subtyping을 제공하는 방법에 따라 subclassing을 하면서 subtyping을 얻을 수 없는 경우도 많다. 특히 subclassing을 하였지만 논리적으로 subtyping이 성립하지 않는 경우가 많다. 자바의 상속은 명백하게 subclassing이며, 구체화(인터페이스를 구현하는 것. 즉 인터페이스의 외부 모습만 재사용하여 인터페이스를 구현하는 것이므로 구체화는 subtyping에 해당하는 것임)는 subtyping에 해당한다. 또 자바에서 상속을 하면 물리적 subtyping도 제공된다(자바에서는 subclassing, 즉 상속하면 물리적으로 subtyping의 효과도 있음). 즉, B 클래스가 A 클래스의 자식 클래스이면 B 클래스 객체를 A 클래스의 객체를 요구하는 위치에 언제든지 문법적 오류 없이 사용할 수 있다. 하지만 앞서 언급한 바와 같이 논리적으로는 그렇게 사용하는 것이 적절하지 않을 수 있다.

 

 

아래글을 보고 처음에는 무척 혼동스러웠다. 해설은 아래와 같다.

(출처: https://velog.io/@yhlee9753/Java-%EC%9D%98-Generics)

서브클래싱은 바로 이해가 가므로 넘어가고 서브타이핑이 문제였다. 위와같이 서브타이핑을 정의하면 논리이 있지만 그래도 꾸역꾸역 맞는 말이 될수 있다. 하지만 내가 가지고 있어야 하는 서브타이핑의 정의는 "외부 모습만 재사용하는 것"으로 변하지 않는다. 타입계층을 구성하기 위해 상속을 사용한다는 말은 기본적으로 위에서 예로 들었던 장식자를 보면 바로 이해할 수 있다. 상속을 하는 동시에 추상메서드를 만듬으로써 동시에 타입 계층을 구성하게 된 것이다. 그렇다면 외부 모습만 재사용하여 인터페이스를 구현하는 클래스는 어떻게 설명되는가? 인터페이스를 구현한다는 것이 때로는 상속으로 표현되기도 한다! 그냥 표현의 문제임.

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

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

오브젝트의 13장을 요약한 내용 입니다.
상속의 첫 번째 용도는 타입 계층을 구현하는 것이다(타입계층의 구현은 인터페이스를 구현하면서도 타입 계층을 구현할 수 있다. 재밌는 것은 인터페이스를 구현하는 것도 상속으로 표현되기도 한다는 것이다. 그리고 상속이라고 해서 부모의 멤버변수와 맴버함수까지 가지고 거기다 플러스로 자신만의 멤버변수와 멤버함수가 추가되는 일반적인 모형의 상속만이 있는 것이 아니라 위에 내가 언급했던 CondimentDecorator의 예처럼 부모의 메서드중 일부를 다시 추상화해버리는 독특한 상속도 있을수 있다. 그리고 이것 역시 타입 계층을 구현하는 방법이다). 타입 계층의 관점에서 부모 클래스는 자식 클래스의 일반화(generalization)이고 자식 클래스는 부모 클래스의 특수화(specialization)다.
상속의 두 번째 용도는 코드 재사용이다. 하지만 재사용을 위해 상속을 사용할 경우 부모 클래스와 자식 클래스가 강하게 결합되기 때문에 변경하기 어려운 코드를 얻게 될 확률이 높다.
상속을 사용하는 일차적인 목표는 코드 재사용이 아니라 타입 계층을 구현하는 것이어야 한다. 반면 타입 계층을 목표로 상속을 사용하면 다형적으로 동작하는 객체들의 관계에 기반해 확장 가능하고 유연한 설계를 얻을 수 있게 된다.
그렇다면 타입 계층이란 무엇인가? 상속을 이용해 타입 계층을 구현한다는 것이 무엇을 의미하는가?
타입

 

객체지향 패러다임 관점의 타입
타입을 다음과 같은 두가지 관점에서 정의할 수 있다.

 

 
객체지향 프로그래밍에서 오퍼레이션은 객체가 수신할 수 있는 메시지를 의미(오퍼레이션, 객체가 수신할 수 있는 메시지 모두 메서드를 말하는 것같음)한다. 따라서 객체의 타입이란 객체가 수신할 수 있는 메시지의 종류를 정의하는 것이다.

 

객체가 수신할 수 있는 메시지를 기준으로 타입을 분류하기 때문에 동일한 퍼블릭 인터페이스를 가지는 객체들은 동일한 타입으로 분류할 수 있다.
동일한 타입=동일한 퍼블릭 인터페이스를 가지는 객체 =동일한 오퍼레이션을 적용할 수 있는 인스턴스들의 집합