1. 객체지향과 인지 능력
📍 객체지향이 직관적인 이유는 객체지향이 인간의 기본적인 인지 능력에 기반을 두고 있기 때문
- 인간은 세상을 자율적이고 독립적인 객체들로 분해할 수 있는 기본적인 인지 능력을 갖고 있다
- 그리고 객체지향 개념도 이 인간의 인지 능력에 기반한다
- 객체: 인간이 분명하게 인지하고 구별할 수 있는 물리적인 또는 개념적인 경계를 지닌 어떤 것
- 객체지향 패러다임도 현실 세계와 마찬가지로, 인간(개발자)이 인지할 수 있는 다양한 소프트웨어 객체들이 모여 이루어져 있다는 믿음에서 출발
- 하지만, 객체지향의 목적이 현실 세계를 모방하는 것은 아니다 (현실 세계의 객체와 소프트웨어 세계의 객체는 전혀 다름)
예)
- (현실 세계)사람이 직접 주문 금액을 계산
- (객체지향) 주문 객체가 자신의 금액을 계산 -> 이상한 나라의 앨리스에 나오는 세계처럼 차이가 분명함
2. 객체, 그리고 이상한 나라
📍 앨리스 객체
- 앨리스는 상태(키)를 가지며, 상태는 변경 가능하다
- 앨리스의 주스를 마시는 행동(메서드)이 앨리스의 키(상태)를 변화 시킴
- 앨리스의 상태를 결정하는 것은 행동이지만, 행동의 결과를 결정하는 것은 상태이다
예)
- 케이크를 먹으면 키가 150cm 커질 때, 앨리스가 130cm 일 때 케이크를 먹는다면, 앨리스의 키가 280cm가 된다
- 즉, 행동 전의 상태가 행동 후의 상태를 결정(행동의 결과는 상태에 의존)
- 행동의 순서도 결과에 영향을 미친다
- 앨리스의 상태가 어떻든, 앨리스는 유일하다(식별 가능하며, 앨리스인 것은 변하지 않음)
3. 객체, 그리고 소프트웨어 나라
객체: 상태, 행동, 식별자를 지닌 실체
📍상태(state)
상태가 필요한 이유
- 객체의 이전까지의 이력을 세세히 알 필요 없음
- 현재를 기반으로 객체의 행동 방식을 이해할 수 있음
상태와 프로퍼티
예)
앨리스 객체
- 키 = 130 (cm)
- 위치 = "통로"
음료 객체
- 양 = 500 (ml)
프로퍼티
- 키: 객체의 상태를 구성하는 모든 특징 -> 일반적으로 고정되므로 정적
- 값: 시간의 흐름에 따라 변경되기 때문에 동적
즉 상태는,
- 특정 시점에 객체가 갖고 있는 정보의 집합
- 객체의 구조적 특징을 표현
- 객체에 존재하는 프로퍼티(정적)와 프로퍼티 값(동적)으로 구성됨
- 프로퍼티는 단순한 값과 다른 객체를 참조하는 링크로 구분 가능
링크
- 객체와 객체 사이의 의미있는 연결
- 링크가 있어야만 두 객체가 서로 메시지 주고받을 수 있음(협력 가능)
- 서로 다른 객체가 참조할 수 있음을 의미(식별자를 알고 있음)
📍 행동(behavior)
행동은 부수 효과를 초래
- 부수 효과(side effect): 객체의 행동에 의해 객체의 상태가 변경됨
상태와 행동 사이의 관계
- 객체의 행동은 상태에 영향을 받는다(현재의 상태에 의존)
- 객체의 행동은 상태를 변경시킨다
예) 키, 위치의 2가지 상태를 이용해 행동을 서술
- 앨리스의 키가 40cm 이하라면 문을 통과할 수 있다
- 문을 통과한 후에 앨리스의 위치는 아름다운 정원으로 바뀌어야 한다
협력과 행동
- 객체는 다른 객체와 적극적으로 상호작용하여 주어짐 책임을 완수하려고 함
- 객체 간의 협력은 요청에 의해 발생하고, 요청을 수신한 객체는 적절한 행동을 취해야 함
- 객체가 협력에 참여하는 과정에서 다른 객체의 상태 변경을 유발할 수도 있다
예) 앨리스가 음료를 마시면, 앨리스 객체의 키가 증가하고, 음료 객체의 양이 감소
객체의 행동으로 발생하는 결과 2가지
- 객체 자신의 상태 변경
- 행동 내에서 협력하는 다른 객체에 대한 메시지 전송
상태 캡슐화
- 앨리스가 음료를 마시는 행동은 앨리스 자신의 키를 작게 만든다 (자신의 상태 변경)
- 이 과정에서 앨리스는 자신이 먹은 양만큼 음료의 양을 줄여달라고 메시지를 전송한다
- 그러나 음료의 양이 줄어들 것인지는 메시지를 수신한 음료가 결정할 사항이다
- 메시지 송신자는 상태가 변경될 것이라 기대할 뿐, 직접적으로 간섭하지 않음
- 객체는 상태를 캡슐 안에 감춰두고 외부로 노출하지 않음
- 객체가 외부에 노출하는 것은 only 행동 (상태는 노출되지 않음)
- 외부에서 객체에 접근할 수 있는 방법도 only 행동 (상태에 직접 접근 불가)
- 캡슐화가 객체의 자율성을 높여준다
📍 식별자
- 식별자(=프로퍼티): 객체를 서로 구별할 수 있는 객체 내부의 구성요소
- 모든 객체는 식별자를 가진다
- 객체가 아닌 단순한 값은 식별자를 가지지 않는다
동일성
- 식별자를 기반으로 두 객체가 같은지 판단할 수 있는 성질
- 두 객체의 상태(값)가 달라도, 식별자가 같다면 두 객체를 같다고 볼 수 있음(덕타이핑?)
- 상태는 시간의 흐름에 따라 변하기 때문에, 객체의 동일성을 따지기 힘들다
📍 값
- 숫자, 문자열, 날짜 등과 같이 변하지 않는 양을 모델링 (상수와 비슷)
- 두 인스턴스의 상태가 같다면, 두 인스턴스를 같은 것으로 판단
값 객체
- 식별자를 갖지 않는 단순한 값
- 반면, 참조 객체와 엔터티는 식별자를 지닌 전통적 의미의 객체
참조 객체(Reference Object)
- 상태나 프로퍼티보다 객체의 고유한 정체성에 더 큰 의미가 부여된 객체
예) 쇼핑몰에서 고객 정보를 관리하는 경우, 두 고객이 동명이인이고 나이가 같아도 다른 고객으로 취급 (id가 달라서)
class Customer:
def __init__(self, id, name, age):
self.id = id # Customer 인스턴스마다 고유한 id를 가짐
self.name = name
self.age = age
# 각 Customer 객체는 고유하다고 볼 수 있으므로 참조 객체가 됨
customer1 = Customer(id=1, name="Alice", age=30)
customer2 = Customer(id=2, name="Alice", age=30)
엔터티(Entity)
- 객체가 가진 프로퍼티를 더 중요하게 취급하는 객체
- 주로 프로퍼티 값에 따라 식별되며, 같은 프로퍼티를 가지면 같은 엔터티로 간주할 수 있음
예) 좌표 상의 위치를 나타내는 Point 객체
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# 2차원 좌표에서 같은 x, y 값을 가지면, 같은 엔터티로 볼 수 있음
point1 = Point(x=10, y=20)
point2 = Point(x=10, y=20)
4. 행동이 상태를 결정한다
객체를 설계할 때, 상태를 먼저 결정하고, 행동을 나중에 결정하는 방법은 설계에 나쁜 영향을 끼친다. 그 이유는
1️⃣ 상태를 먼저 결정할 경우, 캡슐화가 저해된다
- 상태가 공용 인터페이스에 노출될 확률이 높아진다
2️⃣ 객체를 협력자가 아닌 고립된 섬으로 만든다
- 객체는 다른 객체와 협력할 수 있어야 하는데, 상태를 먼저 고려하면 협력에 적합하지 않은 객체가 만들어질 수 있다
3️⃣ 객체의 재사용성이 저하된다
- 다양한 협력에 참여하기 어려워져서 재사용이 힘들어질 수 있다
객체의 적합성을 결정하는 것은 상태가 아니라 행동
- 상태가 아닌 행동에 초점을 맞춰야 객체가 협력이 쉬워진다
객체에게 어떤 책임이 필요한가를 결정하는 과정이 전체 설계를 주도해야 한다
- 책임주도설계(RDD)
- 협력이라는 문맥 안에서 객체의 행동을 생각하도록 도움으로써 응집도 높고 재사용 가능한 객체를 만들 수 있다
5. 은유과 객체
📍두 번째 도시 전설
도시전설 1) 클래스가 객체 지향의 핵심
2) 객체지향이란 현실 세계의 모방
객체지향은 현실 세계의 단순한 모방(또는 추상화)이 아니다
- 소프트웨어 세계와 현실 세계는 매우 다름
예) 실제 세계에서 사람이 없으면 전화기가 서로 통화를 위해 연결되지 않는 것
- 모방(추상화) 대신 은유(metaphor)라는 표현이 더 적절하다
- 따라서, 객체지향은 현실 세계의 모방 대신 은유를 통해 소프트웨어 세계를 새로 창조한다고 이해해야 함