본문 바로가기
Concepts/객체지향

객체지향의 사실과 오해 - 객체란 무엇인가

by ocwokocw 2021. 8. 9.

- 이 글은 조영호의 객체지향의 사실과 오해를 기반으로 작성되었습니다. (가능하면 꼭 읽어보는것을 추천드립니다.)

- 엘리스와 객체지향의 공통점

저자는 객체지향을 설명하기 위해 이상한 나라의 앨리스 이야기를 예시로 들고 있다. 사실 나는 이상한 나라의 앨리스를 읽어보진 않았지만 그래도 이해하는데 전혀 무리가 없도록 자세히 설명해주고 있다.

 

엘리스는 아름다운 정원으로 들어가기 위해 많은 노력을 한다. 그 과정에서 음식을 먹거나 부채질을 하면 키가 변하는 이상현상을 겪게 된다. 그리고 이를 이용해 키를 변화시키면서 목표했던 아름다운 정원에 들어가게 된다.

 

엘리스의 키나 현재위치는 상태라고 볼 수 있다. 엘리스의 상태가 변하는것은 케이크를 먹거나 부채질을 하는 등의 행동을 했기 때문이다. 또한 현재 상태에 따라 행동의 결과가 달라지기도 한다. 하지만 이렇게 상태가 아무리 변해도 엘리스는 엘리스이며 이를 식별가능하다고 말할 수 있다.

 

위의 문장에서 객체의 중요한 개념 3 가지가 도출되는데 그것이 바로 상태, 행동, 식별자이다.


- 상태

상태란 해당 객체가 과거에 했던 모든 행동이력을 캐싱한것이라고 볼 수 있다. 만약 내가 일본여행을 가려고 공항에 갔다고 가정하자. 승무원은 내가 비행기에 탑승할 수 있는지 여부를 발권 상태를 보고 결정한다.

 

만약 상태라는 개념이 없다면 이전 행동들을 모두 살펴보고 검증해야 한다. 항공권을 발권했는지 그 항공권을 발권하기에 충분한 금액을 소지하고 있었는지, 발권 당시 예약할 수 있는 여유좌석이 있었는지 내가 금액을 마련할 때 어떤 행동을 수행했는지를 계속 추적하다보면 내가 태어날 때 부터 모든 행동들이 발권이 가능할만한 행동이었느냐를 따져야 한다. 하지만 상태라는 개념이 존재하면 굳이 과거의 행동이력들을 모두 따져보지 않아도 그 사람(객체)의 행동결과를 예측할 수 있다.

 

객체의 상태를 구성하는 특징을 통틀어 객체의 프로퍼티라고 한다. 앨리스의 키와 위치 또는 음료도 프로퍼티라고 볼 수 있다. 프로퍼티와 더불어 속성이라는 단어도 들어봤을 것이다. 편의상 속성을 프로퍼티와 동일하게 부르기도 하지만 엄밀히 말하면 속성은 프로퍼티의 하위 개념이다.

위의 다이어그램에서 locate 나 height 는 앨리스의 키와 위치를 문자열과 숫자와 같은 단순값으로 나타내는 속성이다. 하지만 음료의 경우 Beverage 라는 클래스의 객체를 참조하는데 이를 연관이라고 표현한다. UML Distilled 에서는 프로퍼티를 속성과 연관 표기법으로 표현할 수 있다고 말한다.

 

아래 다이어그램은 위의 속성과 연관을 혼합해 표기한 방법을 전부다 연관 표기법으로 표현한것이다.

Alice 하나의 클래스만 표현했는데도 벌써 복잡해질 조짐이 보인다. 그래서 보통 속성들을 클래스 내부로 다른 클래스의 참조에 대해서는 연관 표기법을 이용하므로 1번째 다이어그램과 같이 많이 표기한다. 어떤 경우에 속성 혹은 연관 표기법을 이용해야 하는 절대적 기준은 없다. 상대적인 중요도에 따라 표기하면 된다.

 

책에서는 객체 사이의 연결을 링크라고 하고 링크가 존재해야 객체간의 요청을 송수신할 수 있다고 말한다. 위 다이어그램은 클래스 다이어그램이기 때문에 연관인것이고 만약 객체사이의 연결이라면 링크가 된다.


- 상태와 행동

상태와 행동을 서로 영향을 미친다. 객체의 행동은 상태를 변경하지만, 객체의 상태도 행동에 영향을 미친다. 만약 어떤 음료를 마실 때 10cm 의 키가 줄어들고 문이 40cm 라고 가정해보자. 앨리스의 키가 50cm 라면 음료를 마셨을 때 문을 통과할 수 있지만 앨리스의 키가 60cm 라면 여전히 문을 통과하지 못한다. 음료를 마심으로써 앨리스의 키가 변경되었지만 앨리스의 키가 문을 통과하는 행위에 영향을 미친다.

 

또한 변경되는것은 객체의 내부 상태에만 해당되는것은 아니다. 앨리스가 음료수를 마시면 음료수의 양도 줄어든다. 즉 자신의 상태를 변경하는것과 더불어 협력안에서 다른 객체에 대해 메시지를 전송할 수 있고, 이 메시지에 의해서 다른 객체의 상태도 영향을 받을 수 있는것이다.


- 캡슐화

앨리스는 음료수를 마셨다 라는 메시지를 음료 객체에게 전달한다. 현실 세계에서는 "사람이 음료수를 마시면 당연히 양이 줄어들지" 라고 하지만 객체 지향 세계에서는 "앨리스가 마시면 음료의 양이 줄어들지만 다른 누군가가 마시면 음료수의 양이 줄어들지 않는다" 라고 정의할수도 있다. 현실세계에서는 사람이 음료의 양을 줄이지만 객체 지향 세계에서는 상태에 해당하는 음료의 양을 줄이는것은 자기자신이다. 

 

음료객체가 양을 줄인다는 행위를 외부에 노출하지 않으면(접근 제어자를 public 으로 설정하지 않으면) 다른 객체가 음료의 양을 줄일 방법은 없다. 음료는 양이라는 상태를 외부에 노출하지 않고 행위만 노출하여 자율성을 보장받는다.

 

만약 음료의 양을 외부 객체가 마음껏 조절할 수 있도록 오픈해버리면 앨리스가 아니어도 아무나 음료의 양을 줄일 수 있다. 그렇게 되면 앨리스가 마시기전 100 의 용량에서 30 을 마셔도 과연 70 이 남아있는가에 대해 보장받기가 힘들어진다. 이렇게 필요한 정보만 노출하는 행위를 캡슐화 라고 한다.


- 식별자

만약 어떤 객체를 식별할 수 있는 기준이 되는 프로퍼티가 있다면 이 프로퍼티를 식별자라고 한다. 반면 단순한 값은 식별자를 가지지 않는다.

 

값은 불변이다. 우리가 프로그래밍을 할 때 1 이라는 숫자가 있고 이에 추가로 2 라는 숫자가 필요하다면 1 의 상태를 변경해서 2 를 만들지 않는다. 2 를 생성한다. 그래서 값은 변하지 않아야 하며 이를 만족하기 위해 setter 를 제공하지 않는다. 값이 같은지를 판단할때에는 동등성(equality)를 따진다. 설령 기본형 타입이 아닌 위도와 경도의 상태를 가진 클래스라고 해도 해당 클래스를 Entity 가 아닌 Value Object 의 의도로 사용했다면 위도와 경도가 같을 때 동등하다고 치부해야 한다. 이를 보장해주기 위해 equals 메소드를 재정의 하여 Object 의 기본 연산인 주소값 비교가 아니라 상태의 값이 같은지를 비교하게 해야 한다.

 

반면 객체는 가변상태이다. 3 살의 나도 10 살의 나도 나는 나다. 설령 현재 내옆에 이름과 키와 몸무게와 모든 상태가 같은 사람이 한명 더 있다고 해도 그 존재와 나는 구별된다. 즉 식별자를 제외한 상태가 모두 같거나 모두 다르더라도 식별자만 같다면 해당 객체는 같다고 할 수 있다. 이를 동일성(identical) 이라고 한다.


- 행동을 우선시하라.

우리는 흔히 객체 지향 설계를 할 때, 객체가 어떤 데이터(상태)를 가져야 할까를 먼저 고려한 후 관습적으로 getter/setter 를 자동완성으로 추가한다. 그 후 필요하면 어떤 편의 메소드를 추가하면 좋을까라는 고민을 하기 시작한다.

 

객체 지향에서는 상태보다 협력안에서 객체들의 행동을 우선적으로 고려해야 한다. 상태를 먼저 결정할 경우 프로그램이 커져갈수록 필요한 상태와 필요 없는 상태를 구분할 수 없게되며, 밖으로 노출하지 말아야 하는 상태도 노출되는 경우가 많아진다.

 

또한 상태를 우선시하여 고려하면 객체를 고립된 섬으로 만들어 재사용성을 저해시킨다. 상태를 우선시했기 때문에 객체 자신의 동작에만 신경쓴 나머지 협력에서 어떤 행동으로 다른 객체와의 교류를 해야하는지에 대한 점이 미흡해지기 때문이다.

댓글