객체 지향 다시 살펴보기 - 잘못된 지식을 바로잡아보자

eora21·2023년 10월 23일
8

해당 글은 '스프링 입문을 위한 자바 객체지향의 원리와 이해'를 참고하여 작성되었습니다.
객체지향의 개념은 알고 있으나, 잘못된 정의를 통해 학습한 내용을 바로잡아봅시다.

객체지향에 대해

누군가 '객체지향이 무엇인가요?'라는 질문을 해왔다고 가정합시다. 어떠한 답변을 할 수 있을까요?
많은 답이 나올 것 같습니다. '객체지향의 사실과 오해' 서적 내용을 정리하여 한 마디로 축약해 보자면 책임을 바탕으로 역할을 나누고, 메시징을 통해 소통하는 것이라고 볼 수 있겠습니다.

위와 같은 개념적인 글이 아니고, 붕어빵틀과 붕어빵의 관계에서부터 시작하여 is-a 관계 등 하나씩 확장시키며 설명할 수도 있겠죠. 4대 특성과 5원칙으로 정의된 내용을 이야기하는 것도 좋을 겁니다.

그런데 만약, 붕어빵틀과 붕어빵이 잘못된 비유였다면?
우리가 알고 있던 4대 특성 설명 중 잘못된 것이 있었다면?
is-a 관계 뒤에 생략된 설명이 있었다면?

이번 글에서는 우리가 숱하게 학습한 잘못된 내용들을 바로잡는 시간을 가져 보도록 하겠습니다.

클래스와 객체

붕어빵틀과 붕어빵

클래스와 객체를 설명할 때 한번씩은 들어봤던 내용이 바로 붕어빵틀과 붕어빵의 관계일 겁니다.
클래스는 붕어빵틀이고, 객체는 붕어빵으로 준비된 틀을 통해 객체를 찍어낸다같은 설명으로 코드를 이해하였을 테니까요.
그러나, 해당 설명이 과연 옳을까요?

코드로 예시를 들어봅시다. 우리가 클래스 객체를 만들 때의 예시를 들어봅시다.

클래스명 객체명 = new 클래스명();

JAVA 기준으로는 이렇게 클래스 객체를 만듭니다.
클래스는 붕어빵틀이고, 객체는 붕어빵이었으니 한 번 대입해 볼까요?

붕어빵틀 붕어빵 = new 붕어빵틀();

뭔가 이상하지 않나요?
붕어빵틀을 하나 만들었더니 붕어빵이 되었다..?
붕어빵틀이 붕어빵을 찍어내니까 클래스고, 붕어빵이 만들어지니까 객체라는 설명을 들었는데.. 이게 맞나 싶으실 겁니다.
'찍어낸다'에 집중하여 다른 예시를 들어보겠습니다. 이번에는 붕어빵틀을 만드는 금형기계라는 클래스를 생각해 보겠습니다.

금형기계 붕어빵틀 = new 금형기계();

금형기계를 하나 만들었더니 붕어빵틀이 되었다..?
이도 역시 말이 되지 않습니다. 붕어빵틀과 금형기계는 각각 붕어빵, 붕어빵틀을 만드는 무언가(팩토리)였을 뿐입니다. 절대 클래스와 객체의 관계는 아님을 알 수 있습니다.

그렇다면 클래스와 객체는 어떤 관계일까요?

개념과 실체

정확한 설명으로는 클래스는 개념, 객체는 실체라고 볼 수 있겠습니다.
사람을 비유하여 생각해 보겠습니다.

사람 유재석 = new 사람();
사람 홍진호 = new 사람();
사람 심규선 = new 사람();

각각 유재석, 홍진호, 심규선이라는 객체를 사람이라는 클래스로 생성하고 있습니다.
사람은 하나의 개념입니다. 두 발로 걷고, 높은 지능을 가지며, 성대의 진동을 통해 대화하는 등의 특징을 지닙니다..
반면 유재석, 홍진호, 심규선은 실체입니다. 사람이라는 개념으로 묶일 수 있는, 현실에 실존하는 존재들이죠.

객체지향의 세계에서도 이는 마찬가지입니다. 어떠한 특정 개념을 역할삼아 스스로 살아 숨쉬며 책임을 다하는 존재들을 일컬어 우리는 객체라고 합니다.

만약 사람이라는 개념과 유재석, 홍진호, 심규선이라는 실체를 정확히 구분하는 방법이 잘 떠오르지 않으신다면 해당하는 존재에게 물어보면 됩니다.

사람은 몇 살인가요?
유재석님은 몇 살인가요?
홍진호님은 몇 살인가요?
심규선님은 몇 살인가요?

애초에 문장 자체가 성립되지 않는 맨 위의 질문을 빼고는 제대로 대답할 수 있을 겁니다. 모르더라도 검색하면 나오니까요.
즉, 맨 위의 사람은 개념이고 나머지는 실체라는 것을 이러한 방식으로 구분할 수 있습니다.

객체지향의 4대 특성 중 상속(Inheritance)에 대해

객체지향의 4대 특성으로는 캡슐화, 상속, 추상화, 다형성이 있습니다.
이 중 상속에 대해 이야기해 보도록 하겠습니다.

제가 상속을 배울 때는 JAVA의 extend를 예시로 배웠습니다. 부모 클래스의 특징을 물려받는 것이 곧 상속이다..
그러나 JAVA를 다루는 분들은 아실 겁니다. JAVA는 다중 상속이 허용되지 않으며, 대신 인터페이스를 통해 코드를 구성하게끔 지향합니다.

객체지향의 중요한 특성인데, 이에 대해 제한을 걸었다는 게 뭔가 이상하지 않으신가요?
어쩌면 상속은 extend고 추상화와 다형성이 인터페이스다. 당연히 인터페이스가 더 많은 특성에 해당하니 상속보다 인터페이스가 더 좋은거라 그렇다라고 배우신 분들도 있을 지 모르겠습니다(저만의 경우이길 바랍니다).

사실, 상속이란 단어는 영단어를 그대로 옮기면서 발생한 오해라고 합니다. 본래의 뜻을 적용하자면, 상속은 재사용과 확장이 옳다고 하네요. 즉, extend뿐만 아니라 interface까지 포괄하는 것입니다.

이야기가 살짝 벗어난 것 같으니, 상속을 처음 배울 때 부모 클래스와 자식 클래스를 예시로 들었던 때로 돌아가 보겠습니다.

부모 클래스와 자식 클래스

부모 클래스, 자식 클래스 설명을 바탕으로 코드를 간단히 설계해보겠습니다.

class 부모 {
}

class 자식 extend 부모 {
}

부모 아들 = new 자식();

자식 객체를 부모라는 클래스로 업캐스팅하였습니다.
아까와 같은 해석을 해볼까요?

자식을 하나 만들었더니 아들이 되었다.. 근데 이게 부모 역할도 한다?
음.. 자식은 곧 부모가 될 수 있으니 맞는 설명일 수도 있겠습니다.

그렇다면 부모를 한자 그대로, 엄마와 아빠라는 글귀로 바꿔봅시다.
자식을 하나 만들었더니 아들이 되었다.. 근데 이게 엄마와 아빠 역할도 한다?
아빠의 역할은 그렇다 치더라도, 엄마의 역할까지 할 수 있을까요?
그렇다고 이게 객체명의 잘못은 아닐 겁니다. 아들은 자식이라는 개념의 실체에 이름을 붙인 것 뿐이니까요.

객체명을 '갓난아기'로 더 좁게 가져가면서 예시를 들어 봅시다.
자식을 하나 만들었더니 갓난아기가 되었다.. 근데 이게 엄마와 아빠 역할도 한다?
더 뒤틀린 것을 볼 수 있습니다. 이쯤 되면 다들 이해하셨겠지만, 상속은 우리가 생각하는 '내 위의 존재에게 무언가를 물려받는 것'이라고 생각하면 문제가 됩니다.

상속은 어디까지나 개념의 구체화와 기능의 확장입니다. 부모와 자식은 붕어빵틀과 붕어빵처럼, 부분적인 이해만을 위한 예시였던 것입니다.

개념의 구체화와 기능의 확장

제대로 된 정의를 지닌 채 코드를 작성해 봅시다.

class 생물 {
	void 성장() {}
}
class 동물 exend 생물 {
	void 숨쉬기() {}
}

class 사람 extend 동물 {
	void 말하기() {}
    void 걷기() {}
}

아까와 같이 객체를 만들며 확인해 봅시다.

동물 김주호 = new 사람();

사람을 하나 만들었더니 김주호가 되었다.. 근데 이게 동물의 역할도 한다.
네, 사람은 동물의 역할을 합니다. 김주호는 사람의 이름일 뿐입니다.

사람을 하나 만들었더니 김주호가 되었다.. 근데 이게 생물의 역할도 한다.
동물을 하나 만들었더니 김주호가 되었다.. 근데 이게 생물의 역할도 한다.

모두 말이 됩니다. 즉 상속은 무언가의 개념을 구체화(생물이라는 넓은 범위에서 사람의 좁은 범위까지 구체화)하며 기능을 확장하고 재사용(생물은 성장만 하지만, 사람은 성장하고 숨쉬고 말하고 걸을 수 있다)합니다.
애초에 자바의 상속이 extend(확장)이었듯, 이는 아주 당연한 내용임을 알 수 있습니다.

여기서 하나 더 짚어보겠습니다. 바로 is-a 관계입니다.

is-a

상속은 is-a 관계를 만족해야 한다라는 말을 자주 들어보셨을 겁니다.
위의 예시를 다시 한 번 들어보며 확인해 볼까요?
상속은 클래스사이의 관계이니, 동물과 사람으로 확인해 보겠습니다.

동물 is a 사람, 동물은 한 명의 사람이다
얼핏 보면 맞는 것 같습니다.
하지만 자세히 보면 뭔가 이상합니다. 동물, 사람 모두 클래스이므로 개념에 속합니다. 여기서 한 명의 사람은 과연 클래스일까요? 객체에 가까울 것입니다.

명확히 하기 위해 상위 클래스, 하위 클래스라는 단어를 넣어 봅시다.
하위 클래스 is a 상위 클래스, 하위 클래스는 하나의 상위 클래스이다.
하위 클래스는 개념입니다.
상위 클래스도 개념입니다.
하나의 상위 클래스는 객체입니다.

이를 다시 대입하면 이런 문장이 나옵니다.
개념은 객체이다.
위에서 이야기한 것과 매우 다른 문장이 나옵니다. 클래스가 개념이고, 객체는 실체였습니다.
네, 해당하는 문구는 사실 뒤에 있던 내용이 잘린 거였다고 하네요.
원문은 바로 is a kind of입니다.

is a kind of

이를 이용해 다시 문장을 완성해 봅시다.
하위 클래스 is a kind of 상위 클래스, 하위 클래스는 상위 클래스의 한 분류다.
사람 is a kind of 동물, 사람은 동물의 한 분류다.

아주 매끄러운 정의가 나왔습니다.

정리

마지막으로 정리하며 끝내겠습니다.

  • 클래스와 객체의 관계는 붕어빵과 붕어빵틀이 아닌 개념과 실체이다.
  • 객체지향의 4대 특성 중 상속(Inheritance)은 부모와 자식이 아닌 개념의 구체화와 기능의 확장 및 재사용이다.
  • 상속(JAVA의 extend)는 is-a 관계가 아닌 is a kind of 관계다.

이상 잘못된 예시 및 정의를 바로잡는 과정을 마치겠습니다.

profile
나누며 타오르는 프로그래머, 타프입니다.

1개의 댓글

comment-user-thumbnail
2023년 11월 1일

최근에 책을 읽다가 interface implements 도 상속, class extend 도 상속이라고
표현해서 상당히 혼란스러웠는데, 이 글을 읽고 왜 그랬는지 이제야 알게 되었네요.
좋은 글 정말 감사합니다.

답글 달기