이상한 나라의 객체
- 이상한 나라의 앨리스
- 객체의 세 가지 특성 — 상태, 행동, 식별자
- 상태
- 행동
- 식별자
- 기계로서의 객체
- 은유와 객체
"이상한 나라의 앨리스"를 비유로 가져와서 객체가 뭔지를 깊게 파보자. 1장이 "객체지향은 협력이다"라는 큰 그림을 그렸다면, 이번엔 그 협력에 참여하는 개별 객체가 도대체 뭔 놈인지를 탐구하는 거야.
저자가 앨리스를 꺼낸 이유가 있어. 앨리스는 이상한 나라에서 음료를 마시면 키가 줄어들고, 케이크를 먹으면 키가 커지잖아. 여기서 객체의 핵심 특성이 전부 드러나거든.
- 앨리스의 키는 상태야
- 음료를 마시는 것과 케이크를 먹는 것은 행동이지
- 행동의 결과로 상태가 변해
- 키가 아무리 바뀌어도 앨리스는 여전히 앨리스야 — 이게 식별자야
음료를 마셔서 키가 40cm가 된 앨리스와, 케이크를 먹어서 3m가 된 앨리스는 상태가 완전히 다르지만 같은 앨리스지. 상태가 바뀐다고 다른 존재가 되는 게 아니라는 거야. 이 직관이 객체의 식별자 개념을 이해하는 열쇠거든.
저자는 객체를 다음 세 가지로 정의해:
- 상태(state) — 객체가 가지고 있는 정보
- 행동(behavior) — 객체가 할 수 있는 것
- 식별자(identity) — 객체를 다른 객체와 구별하는 것
이 세 가지가 전부 있어야 객체야. 상태만 있으면 데이터고, 행동만 있으면 프로시저고, 식별자가 없으면 값(value)이지. 이 세 요소가 함께 있을 때 비로소 자율적으로 협력에 참여할 수 있는 "객체"가 되는 거야.
왜 객체에게 상태가 필요한가? 저자의 대답은 명쾌해 — 과거에 일어난 모든 일을 기억하지 않아도 되게 해주기 때문이지.
앨리스의 키가 현재 130cm라는 사실을 알면, 앨리스가 지금까지 뭘 마시고 뭘 먹었는지의 전체 이력을 알 필요가 없어. 상태는 과거 행동의 이력을 압축한 거야. 행동의 결과가 상태에 반영되어 있으므로, 현재 상태만 보면 객체가 어떤 행동을 할 수 있는지 판단할 수 있지.
상태는 두 가지로 구성돼:
- 프로퍼티(property) — 변하지 않는 정적 속성. 앨리스의 이름 같은 것
- 프로퍼티 값(property value) — 시간에 따라 변할 수 있는 동적 값. 앨리스의 키 같은 것
그리고 상태를 구성하는 요소 중에는 다른 객체에 대한 참조도 있어. 앨리스가 음료를 들고 있다면, 앨리스의 상태에는 음료 객체에 대한 참조(링크)가 포함되지. 이 링크가 객체 간의 관계를 만들어. 객체는 링크를 통해 다른 객체에게 메시지를 보낼 수 있거든.
핵심 포인트: 상태는 외부에서 직접 접근해서는 안 돼. 앨리스의 키를 바꾸고 싶으면 앨리스에게 직접 키 값을 수정하는 게 아니라, 앨리스에게 음료를 마시게 하거나 케이크를 먹게 해야 하지. 상태 변경은 반드시 행동을 통해서만 이뤄져야 해 — 이게 캡슐화야.
행동은 두 가지 효과를 가져:
- 자기 자신의 상태를 변경해 — 앨리스가 음료를 마시면 앨리스의 키가 변하지
- 다른 객체에게 메시지를 보내 — 앨리스가 음료를 마시면 음료의 양도 줄어들잖아. 앨리스의 행동이 음료 객체의 상태에도 영향을 미치는 거야
여기서 상태와 행동의 관계가 양방향이라는 점이 중요해:
- 행동의 결과는 상태에 의존해 — 앨리스의 현재 키에 따라 문을 통과할 수 있는지 없는지가 달라지지
- 행동의 순서가 결과에 영향을 줘 — 음료를 먼저 마시고 케이크를 먹는 것과, 케이크를 먼저 먹고 음료를 마시는 것은 다른 결과를 낳을 수 있어
저자가 여기서 던지는 중요한 메시지: 상태를 먼저 결정하고 행동을 나중에 붙이지 마라. 많은 개발자가 데이터(상태)를 먼저 설계하고, 그 데이터를 처리하는 메서드(행동)를 나중에 추가하는 방식으로 객체를 만들거든. 하지만 올바른 순서는 반대야. 객체가 어떤 행동을 해야 하는지를 먼저 결정하고, 그 행동에 필요한 상태를 나중에 결정해야 해. 행동이 상태를 결정하는 것이지, 상태가 행동을 결정하는 게 아니거든.
값(value)과 객체(object)의 차이가 여기서 나와.
- 값은 상태가 같으면 같은 거야. 숫자 1과 숫자 1은 같지. 이걸 **동등성(equality)**이라 해
- 객체는 상태가 같아도 다른 것일 수 있어. 같은 키, 같은 이름의 두 사람이 있어도 다른 사람이잖아. 이걸 **동일성(identity)**이라 하지
객체는 상태와 무관하게 고유한 식별자를 가져. 앨리스의 키가 변해도 앨리스라는 정체성은 유지되거든. 이게 식별자야.
프로그래밍에서 이걸 혼동하면 버그가 생겨. 두 객체의 상태가 같다고 ==로 비교하면 안 되는 경우가 있고(참조 비교가 필요), 반대로 값 객체는 상태가 같으면 같다고 봐야 하는 경우도 있지(equals 오버라이드). 값과 객체의 구분을 명확히 하는 것이 설계의 기본이야.
저자는 객체를 이해하는 또 다른 비유로 기계(machine) 메타포를 사용해.
버튼이 달린 블랙박스를 상상해봐. 외부에서는 버튼만 누를 수 있고(행동을 요청), 내부에서 무슨 일이 일어나는지는 보이지 않지(캡슐화). 디스플레이에는 결과만 나와(응답).
이 기계 메타포에서 중요한 두 가지:
- 사용자 버튼 — 객체의 행동을 요청하는 인터페이스. 퍼블릭 메서드에 해당하지
- 상태 조회 버튼 — 객체의 상태를 간접적으로 확인하는 인터페이스. getter에 해당하지만, 내부 상태를 그대로 노출하는 게 아니라 객체가 가공해서 보여주는 거야
핵심은 기계의 내부 메커니즘은 외부에서 보이지 않는다는 거지. 외부에서는 오직 버튼(인터페이스)만 통해서 상호작용해. 이게 객체의 캡슐화를 직관적으로 이해하는 방법이야.
마지막으로 저자는 객체지향과 현실 세계의 관계를 정리해.
흔히 객체지향은 현실 세계의 모방이라고 하는데, 저자는 이게 정확하지 않다고 봐. 현실의 물건은 수동적이잖아. 커피잔은 스스로 움직이지 않거든. 하지만 객체지향에서의 커피잔 객체는 능동적이야 — 스스로 자신의 상태를 관리하고, 메시지에 응답하지.
그래서 저자는 "모방"이 아니라 **은유(metaphor)**라고 표현해. 현실 세계의 개념을 빌려오되, 소프트웨어 세계의 규칙에 맞게 재해석하는 거야. 이상한 나라의 앨리스처럼, 소프트웨어 세계에서는 현실에서 불가능한 일이 가능하지. 트럼프 카드가 말을 하고, 케이크를 먹으면 키가 자라고.
이 관점이 중요한 이유: 현실 세계에 지나치게 얽매이면 잘못된 설계를 하게 돼. 현실에서 "주문서"는 스스로 계산하지 않지만, 소프트웨어의 주문서 객체는 스스로 총액을 계산할 수 있고, 그렇게 하는 게 오히려 좋은 설계거든. 현실의 수동적 사물을 소프트웨어에서는 능동적 객체로 바꾸는 것 — 이걸 저자는 **의인화(anthropomorphism)**라고 불러.
정리
2장 읽고 기억할 거 세 가지:
- 객체 = 상태 + 행동 + 식별자. 이 세 요소가 전부 있어야 객체야. 하나라도 빠지면 그냥 데이터이거나 프로시저일 뿐이지
- 행동이 상태를 결정해. 데이터를 먼저 설계하고 메서드를 나중에 붙이는 습관을 버려. 객체가 무엇을 해야 하는지를 먼저 결정하고, 거기에 필요한 상태를 나중에 붙여
- 객체지향은 현실의 모방이 아니라 은유야. 현실에 갇히지 말고, 소프트웨어 세계에서 객체를 능동적 존재로 자유롭게 설계해