[객체지향 프로그래밍] [Kotlin] 객체(Object)란 무엇이고 코틀린에서의 객체는 어떻게 다른가?
1. 객체지향 프로그래밍은 알겠는데, 객체는 모른다?
컴퓨터공학을 전공하신 분들이라면, 또는 자바나 C++과 같은 프로그래밍 언어를 공부하신 분들이라면 객체지향 프로그래밍이 무엇인지 모르시지는 않을 것입니다. 절차지향 프로그래밍과 반대되는, 프로그램의 설계를 객체라는 개념을 토대로 바라보는 관점이 바로 객체지향 프로그래밍입니다. 하지만 많은 개발자들이 객체지향 프로그래밍을 하고 있으면서도, 객체가 무엇인가?라는 질문에 대해 명확한 대답을 할 수 있는 사람은 드뭅니다. 저 또한 그러한 사람 중 한 명이었고, 우아한테크코스에서 공부하며 제가 아직도 객체가 무엇인지, 심지어 객체지향 프로그래밍이 무엇인지조차 모르고 있었다는 사실을 깨닫게 되었습니다. 그래서 객체란 무엇인지 한 번 제대로 짚고 넘어갈 필요가 있다고 생각했습니다.
많은 개발자들이 객체지향 프로그래밍을 하고 있으면서 왜 객체가 무엇인지 명확하게 설명하는 것은 어려울까요? 저는 '객체'라는 개념 자체가 매우 추상적이고, 애매모호하기 때문이라고 생각합니다. 개발자의 관점, 사용 언어, 코드의 맥락에 따라 객체의 정의와 이해가 달라질 수 있습니다. 코드 상에서는 객체를 생성하는 단위로서 클래스라는 개념이 존재하기 때문에 클래스가 존재하면 객체지향 프로그래밍이라는 것을 쉽게 알아챌 수 있지만, 객체가 무엇인지에 대한 정의를 내리는 것은 그렇게 간단하지 않습니다. 게다가 개발자마다 객체를 바라보는 관점이 다 다릅니다. 따라서 경험이 많은 개발자에게 객체가 무엇인지 질문한다고 하더라도, 돌아오는 답변을 100% 이해하거나 납득하기는 어려울 가능성이 높습니다.
결국 객체가 무엇인지 이해하려면 자신만의 정의를 내리고, 나만의 개념을 정립하는 방법밖에 없습니다. 그리고 그것을 남에게 설명했을 때, 듣는 사람의 입장에서 그것이 터무니없지 않고 어느정도의 일리가 있으면 됩니다. 본 포스팅에서 설명하는 객체의 정의 또한 저만의 생각일 뿐이며, 이 글을 읽는 분들의 생각은 저와 다를 수 있습니다. 서론이 길었군요! 한 번 들어가 보도록 하겠습니다.
2. 그래서 객체가 무엇인가요?
먼저 객체가 무엇인지 설명하기 위해서, 객체지향 프로그래밍이 무엇인지부터 생각할 필요가 있습니다.
객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위, 즉 "객체"들의 모임으로 파악하고자 하는 것이다.
-위키백과-
위키백과의 설명을 빌려오면, 객체는 소프트웨어 세계에서 존재하는 어떤 독립된 단위라고 합니다. 객체지향 프로그래밍이 등장한 이유는, 현실세계의 사물을 간략화 및 추상화 하여 소프트웨어 세계를 표현하는 것이 효과적이라는 것을 개발자들이 깨달았기 때문입니다. 이렇게 간략화된 현실세계의 사물들은 소프트웨어 세계에서 독립된 단위로 존재하게 되는데, 이것들을 우리는 객체라고 부릅니다. 따라서 저는 객체의 정의를 다음과 같이 내리고 싶습니다.
객체란 소프트웨어 세계에서 독립된 단위로서 의미를 가지는 실체를 말한다.
예를 들어보겠습니다. 현실 세계에서 '볼펜'이라는 물체가 있다고 가정해 보겠습니다.
이 볼펜은 훌륭한 객체입니다. 소프트웨어 세계에서 살아가는 존재들은 이 볼펜을 사용할 수 있습니다. 따라서 독립된 단위로서 충분한 의미를 가지고 있죠.
그리고 이 볼펜은 상태를 가지고 있습니다. 색깔(파란색), 잉크의 양(100%), 길이(약 15cm) 등이 상태에 해당합니다. 따라서 이 객체는 다음과 같은 클래스로 구현이 가능합니다. (당연하지만 실제로 동작하지 않는 수도코드입니다)
class 볼펜 {
val 색깔 = 파란색
val 잉크의 양 = 100%
val 길이 = 15cm
}
하나의 예시를 더 들어볼까요? 이번엔 아래에서 알송이가 춤을 추고 있습니다.
이 알송이도 물론 객체입니다. 제가 창조한 소프트웨어 세계에서는 춤을 추는 알송이가 필요하거든요. 그러니 독립된 단위로서 의미를 가지죠.
알송이는 볼펜처럼 나이(10살), 이름("알송이")라는 상태도 가지고 있지만 '춤추다'라는 행위 또한 가지고 있습니다. 이것을 클래스로 구현해 볼까요?
class 알송이 {
val 나이 = 10살
val 이름 = "알송이"
fun 춤추다() {
춤추기
}
}
위의 예시들에서 보시다시피, 객체의 상태는 프로퍼티로, 행위는 메서드로 표현됩니다. 여기서 객체가 가지는 중요한 특성이 등장합니다.
3. 상태, 행위, 식별자
객체는 다음과 같은 특성을 가집니다.
객체는 상태와 행위를 가지며, 식별이 가능해야 한다.
여기서 '상태와 행동을 가진다' 라는 말은, 상태와 행동 둘 중 하나만 가지고 있어도 객체에 범주에 포함됨을 의미합니다.
상태와 행동을 가진다? 이 세상에 존재하는 대부분의 사물은 상태와 행동을 가지지 않나? 그렇습니다. 위의 설명대로라면 현실세계에 존재하는 대부분의 물체는 객체가 되기 위한 필요조건을 충족하고 있죠. 즉 이 세상에 존재하는 거의 모든 것은 객체가 될 수 있다는 것입니다. 게다가 적어도 현실에서만큼은 모든 사물 또는 생명체는 식별이 가능합니다. 공장에서 만든 똑같은 볼펜이 두 개가 있다고 하더라도, 이 두 물체는 구별이 가능합니다. 겉보기에는 똑같게 보이더라도 두 볼펜의 상품번호는 다를 것입니다.
하지만 현실세계가 아닌 소프트웨어 세계에서는 조금 다릅니다. 소프트웨어 세계에서는 식별 불가능한 개체가 존재합니다. 가령 숫자 1은 어떨까요?
fun main() {
val a = 1
val b = 1
val c = 1
}
a
, b
, c
에 저장한 숫자 1은 식별이 가능할까요? 불가능합니다. 프로그램 세계에서 세 1은 모두 똑같은 1일뿐입니다. 따라서 숫자 1은 객체라고 보기 어렵습니다. 이는 단순한 값입니다. 숫자뿐만 아니라 Char, Float, Boolean 등의 원시값 또한 마찬가지입니다.
4. 코틀린에서의 객체
여기서부터는 조금 다른 이야기를 해보겠습니다. 그 이야기를 하기 위해서 원시 자료형(Basic types)에 대한 이야기를 코틀린 공식문서에서 찾아보겠습니다. 코틀린 공식문서에서는 원시 자료형을 다음과 같이 설명하고 있습니다.
Basic types
In Kotlin, everything is an object in the sense that you can call member functions and properties on any variable. While certain types have an optimized internal representation as primitive values at runtime (such as numbers, characters, booleans and others), they appear and behave like regular classes to you.
코틀린에서는 모든 것이 객체입니다. 이 말은 모든 변수에 대해 멤버 함수와 속성을 호출할 수 있다는 의미입니다. 특정 유형은 런타임에서 원시 값으로 최적화된 내부 표현을 가지고 있지만(예: 숫자, 문자, 부울 등), 여러분에게는 일반적인 클래스처럼 보입니다.
여기서 "코틀린에서는 모든 것이 객체입니다." 라는 말에 주목해 봅시다. 앞에서 숫자 '1'은 객체가 아니라고 설명했습니다. 그런데 공식문서의 설명대로라면 숫자 '1'도 객체라는 걸까요? 네, 맞습니다! 코틀린에서는 원시값이 존재하지 않으며, 자바에서의 원시값들도 모두 객체로 취급됩니다. 그 말인즉슨 숫자 1, 문자 'a' 등이 모두 코틀린에서는 객체라는 것입니다. 즉 우리는 객체지향 패러다임에서의 객체와 코틀린에서의 객체를 구별해 생각할 필요가 있습니다.
코틀린 공식문서의 설명대로, 코틀린에서는 정수 또한 객체이기 때문에 Int의 인스턴스인 a
의 메서드가 존재함을 확인할 수 있습니다.
심지어 코틀린에서는 메서드 역시 객체입니다. 코틀린에서 함수는 일급 시민(First-class Citizen)이기 때문에 클래스의 멤버로만 존재하지 않으며 클래스 외부에도 존재할 수 있고, 변수에도 들어갈 수 있습니다.