객체지향의 사실과 오해 1,2 Chapter

위승현·2024년 11월 26일

CS

목록 보기
4/6
post-thumbnail

객체지향 소프트웨어는 실세계의 투영이다.
객체란 현실세계에 존재하는 사물에 대한 추상화이다.

하지만 현실세계와 사물 사이에 존재한느 연관성을 찾기란 힘들다.

소프트웨어 개발자는 실세계를 단순히 소프트웨어 안으로 옮겨담는 것이 아니다.
곡개과 사용자를 만족시킬 수 있는 신세계를 창조하는 것.

실세계의 모방이라는 개념이 비현실적임에도 실세계 객체와 소프트웨어 객체 간의 대응을
이뤄내려는 이유는 무엇일까??

실세계의 사물을 기반으로 소프트웨어 객체를 식별하고 구현까지 이어간다는 모방의 개념은
객체지향 설계의 핵심 사상인 연결 완정성을 설명하는데 적합한 틀이기 때문이다.

즉 프로그램을 설계 구현하는데에는 옳지 않은 것이지만
이 객체지향이라는 용어를 이해하고 학습하는데는 효과적이다.

우리가 생활하면서 겪는 모든 일들의 과정은
역할, 책임, 협력이라는 개념이 조화되어 어울려 만들어진다.

요청과 응답으로 이루어진 협력

일상에서의 대부분 문제에서 사람들은 해결하지 못하는 문제와 마주치면
문제 해결에 대한 지식을 알거나 서비스를 제공해줄 수 있는 사람에게 도움을 요청 한다.

대부분의 문제는 다수의 사람 혹은 역할이 같이 해결하기 때문에
요청은 연쇄적으로 발생하는 것이 대부분이다.

요청을 받은 사람은 자신의 책임을 다하며 필요한 지식이나 서비스를 제공한다.
즉 요청에 응답 하는 것이다. 응답 역시 요청과 반대 방향으로 연쇄적으로 전달된다.


역할과 책임 그리고 협력

요청과 응답의 협력 과정 속에 사람들은 각자의 역할을 부여받는다.
역할은 협력에 참여하는 사람이 협력 안에서 차지하는 책임, 의무를 의미한다.

역할은 책임이라는 개념을 내포한다.
선생님이라면 가르칠 책임이 있는 것이고, 경찰이라면 범죄자를 검거해야하는 책임이 있듯이

사람들이 협력 과정 속에서 특정 역할을 맡고 그에 대한 책임을 수행한다는 사실을
몇가지 중요한 개념을 제시한다.

  1. 여러 사람이 동일한 역할을 수행할 수 있다.
    -> 즉 누가 그 역할을 하든 문제는 없다.

  2. 역할을 대체 가능성을 의미한다.
    -> 1번과 비슷한 의미

  3. 책임을 수행하는 방법/방식은 자율적으로 선택 가능하다.
    -> 자신의 일처리하는 방식은 사람마다 다르듯이.

  4. 한 사람이 동시에 여러 역할을 수행할 수 있다.
    -> 즉 여러 책임을 한 사람이 수행할 수도 있는 것 (주문을 받고, 요리를 하고..)


객체의 세계는 인간의 세계와 유사하다.
객체 공동체 안에 사는 객체 시민은 자신에게 주어진 역할의 책임을 다하는 동시에
더 큰 목표를 위해 다른 객체와도 협력하기도 한다.

사람은 공통적인 목표를 달성하기 위해 협력한다고 치면
객체는 애플리케이션 기능을 구현하기 위해 협력한다고 할 수 있다.

객체에 얼마나 적절한 책임을 부여하느냐에 따라 설계의 완성도가 달라진다.

대체 가능한 역할과 책임은 객체지향 패러다임의 중요한 개념인 다형성과도 연관돼있다.

객체도 실세계와 다를게 없다고 설명했듯이
애플리케이션에서 협력 과정의 주체는 객체이다.
다른 객체와 협력을 하여 애플리케이션의 완성도를 결정한다면
협력이 얼마나 조화로울지는 객체가 결정한다.

즉 객체의 품질에 따라 협력의 품질, 애플리케이션의 품질이 결정된다는 것이다.

  • 객체가 갖춰야할 덕목
  1. 객체는 협력적 이어야한다.
    -> 다른 객체의 요청에 귀 기울이거나 오히려 도움을 요청할 수 있어야한다.

    하지만 이것이 객체가 수동적인 존재라는 의미는 아니다.
    요청에 응답할 뿐 복종하여 따르는 것이 아니라는 것이다.

    어떤 방식으로 응답할지/요청을 받아드릴지는 객체 스스로 판단하고 결정한다.


  2. 객체는 충분히 자율적 이어야한다.
    객체지향의 묘미는 이것이다.
    한 객체가 다른 객체와 조화롭게 협력할 수 있을 만큼 충분히 개방적인 동시에
    협력에 참여하는 방법을 스스로 결정할 수 있게끔 충분히 자율적인 객체 공동체를 설계해야한다.


상태와 행동을 함께 지닌 자율적인 객체

협력을 하기위해 어떤 행동을 해야한다면 그것에 필요한 상태가 있어야한다.
객체의 자율성은 객체의 내부와 외부를 명확하게 구분하면서부터 나온다.

사적인 부분은 스스로 관리하여 외부에서는 객체가 무엇을 수행하는지는 알 수 있지만
그것을 어떻게 수행하는지는 알 수 없다.

즉 객체의 자율성이란 자신의 상태를 관리하고 그것을 기반으로 스스로 판단하고
행동할 수 있음을 의미한다.


협력에서의 메시지, 메서드

인간은 타인에게 도움을 요청할 때 다양한 방법을 활용한다. (말 or 글자..)

하지만 객체지향의 세계에서는 오로지 하나의 의사소통 수단만이 존재한다.
이것을 메시지라고한다.

메시지 전송 객체를 송신자 sender, 수신자 객체를 receiver 라고 한다.

전송된 메시지는 이해할 수 있는지 여부를 판단하고
미리 정해진 자신만의 방법에 따라 메시지를 처리한다.

객체가 수신된 메시지를 처리하는 방법을 메서드 라고 부른다.
메시지를 수신한 객체가 실행 시간에 메서드를 선택할 수 있으며

이것은 프로시저 호출에 대한 실행 코드를 컴파일 시간에 결정하는
절차적 언어와 확연히 구분되는 특징이다.

바리스타를 예시로 커피 제조 요청이 메시지이고 만드는 구체적인 방식이 메서드인 셈.
제조를 요청한 사람은 방법에는 관여하지 않는다. 바리스타는 자율적으로 커피를 제조한다.

이것은 캡슐화 개념과 연관되어 있다.


객체지향과 클래스

클래스는 많이 부풀려져있다.
대부분 우리만 보아도 객체지향이란 말을 들으면 클래스라는 단어를 떠올릴 것이다.

클래스가 객체지향 프로그래밍 언어 관점에서 매우 중요한 구성요소이긴 하지만
객체지향의 핵심을 이루는 중심 개념이라고 하기는 무리가 있다.

지나치게 클래스를 강조한다면 객체의 캡슐화를 저해하고 클래스를 강하게 결합시킬 수 있다.
애플리케이션을 협력하는 객체들의 공동체가 아니라 클래스로 구성된 설계도로 본다면
유연하고 확장 가능한 애플리케이션의 구축은 힘들어질 것이다.

클래스의 관점에서 메시지를 주고받는 객체의 관점으로 사고의 중심을 전환하라.

클래스는 객체들의 협력 관계를 코드로 옮기는 도구에 불과하다.


객체 -> 상태, 행동

객체란 식별 가능한 개체 또는 사물이다.
구체적인 사물일수도 추상적인 개념일 수도 있다.
객체는 구별 가능한 식별자, 특징적 행동, 변경 가능한 상태를 가진다.

소프트웨어 속의 객체는 저장된 상태와 실행 가능한 코드를 통해 구현된다.

객체가 주변 환경에 상호작용에 어떻게 변환하는가는
그 시점까지 객체에 어떤 일이발생했는가에 따라 좌우된다.
어떤 행동의 결과는 과거에 어떤 행동들이 일어났었느냐에 의존한다.
ex) 자판기 음료를 먹으려면 충분한 돈을 내야됨, 엘레베이터의 층 버튼을 눌러야 이동이 가능

과거의 발생한 행동의 이력만을 통해 현재 발생한 행동의 결과를 판단하는 것은
복잡하고 번거롭고 이해하기 어렵기에 행동의 과정과 결과를 단순히 기술하기 위해서
상태라는 개념이 나오게된다.

상태를 이용하면 행동 이력이 필요없이 행동의 결과를 예측하고 설명할 수 있다.

하지만 세상에 존재하고 인식할 수 있는 모든 것들이 객체인 것은 아니다.

책에서는 엘리스로 설명을 드는데 엘리스는 객체이지만 엘리스의 키와 위치는 객체가 아니다.
키를 바꾸기위해 먹는 음료와 케이크의 양은 객체가 아니다.

이러한 단순한 값들은 객체가 아니다. 다른 객체들의 특성을 표현하는 데 사용되는 것이다.
엘리스의 키는 숫자 값으로 위치는 문자열로 표현할 수도 있는 것이다.

그럼 이런 단순한 값말고 객체로 다른 객체의 상태를 표현해야할 때가 있다

엘리스가 현재 음료를 들고있는지 없는지 확인하고 싶다면 엘리스의 상태 일부를
음료라는 객체를 이용해 표현하면 된다.
엘리스라는 객체가 음료라는 객체와 연결되어있는지의 여부로 표현할 수 있게 된다.

결론적으로 모든 객체의 상태는 단순한 값들, 객체의 조합으로 표현할 수 있다.
이때 객체의 상태를 구성하는 모든 것들을 통틀어 객체의 프로퍼티 라고 한다.

일반적으로 프로퍼티는 변경되지 않고 고정되기 때문에 정적이지만
프로퍼티 값은 시간의 흐름에 따라 변경되기 때문에 동적이다.

이 그림은 엘리스의 상태를 표현한 것이다.
이 전의 상태와는 달라진 것이 보인다.
두 객체 사이의 선이 사라져서 엘리스가 음료가 관계가 없어졌음을 의미한다.

이러한 객체 사이의 의미있는 연결을 링크라고 한다.
객체 사이에 링크가 존재해야 요청을 보내고 받을 수 있는 메시지를 주고받을 수 있다.

즉 링크는 객체가 다른 객체를 참조할 수 있다는 것을 의미하며
이것은 일반적으로 한 객체가 다른 객체의 식별자를 알고 있는 것으로 표현된다.

프로퍼티는 단순한 값인 속성과 다른 객체를 가리키는 링크 두 가지 종류의 조합으로 표현할 수 있다.

하지만 객체는 자율적인 존재이다. 한 객체가 다른 객체의 상태에 직접적으로 접근하거나
상태를 변경할 수 없다. 객체는 스스로 자신의 상태를 책임져야한다.
그렇다면 간접적으로라도 객체의 상태를 변화하거나 조회하는 방법이 필요하다.

여기서 행동이라는 것이 등장한다.
객체의 상태를 변경하는 것은 객체의 자발적인 행동 뿐이다.
앨리스는 키가 작아지기 위해 음료를 마신다. 앨리스의 위치가 변하는 이유는 앨리스가 이동했기 때문이다.

이처럼 객체의 행동은 상태를 변경시키며, 행동의 결과는 상태에 의존적이다.

객체는 이렇게 서로 협력에 참여하는 과정에서 행동을 통해 자기 자신의 상태뿐만 아니라
다른 객체의 상태 변경을 유발할 수 있다.
ex) 앨리스가 음료를 마시면 자신의 키가 작아지는 동시에 음료의 양이 먹은만큼 줄어야함.

이것을 통해 객체의 행동은 두가지 관점의 부수효과가 나타난다는 것을 알 수 있다.

  1. 객체 자신의 상태 변경
  2. 행동 내에서 협력하는 다른 객체에 대한 메시지 전송

위에서 앨리스와 음료수를 통해 예시를 들었는데 현실 세계와 객체지향 세계는 차이가 있다.
현실에서는 음료는 수동적인 존재이다. 앨리스가 음료를 마심으로 인해 양이 줄어든다.
객체지향 세계에서는 음료의 양을 줄이는 것은 음료 자신이다.

앨리스는 단지 음료의 양이 줄어들 것이라고 믿고 요청 메시지를 전달할 뿐이다.

메시지 송신자는 메시지 수신자의 상태변경에 대해서는 전혀 알지 못한다.
그저 자신이 메시지를 전달하는 것일 뿐이다.
이것이 캡슐화이다. 객체는 상태를 외부로 노출하지 않는다.
노출하는 것은 행동뿐이며, 외부에서 객체에 접근하는 유일한 방법도 행동이다.


식별자

객체는 인간이 식별 가능한 경계를 가진 모든 사물을 의미한다.
객체가 식별 가능하다는 것은 객체를 서로 구별할 수 있는 특정 프로퍼티가
객체 안에 존재한다는 것을 의미하고 이것을 식별자 라고한다.

반대로 생각하면 객체가 아닌 단순한 값은 식별자를 가지지 않는다는 것을 의미한다.
값은 숫자, 문자열, 날짜, 시간 같이 변하지 않는 양을 모델링한다.
이는 불변 상태를 가짐을 의미하고 값은 상태가 같으면 동일한 것으로 판단된다.
이처럼 상태를 통해 판단할 수 있는 성질을 동등성 equality 라고 한다.

객체는 시간에 따라 변경되는 상태를 포함하며 행동을 통해 상태를 변경한다.
따라서 값과 달리 객체는 가변 상태를 가진다.
우리도 어린 시절과 지금의 상태는 다르지만 어른 시절의 나와 지금의 나는 동일한 인물이다.
우리도 식별자를 가지고 있는 객체인 셈이다.

이처럼 두 객체의 상태가 다르더라도 식별자가 같으면 두 객체는 같은 객체이다.
식별자로 객체가 같은지 판단할 수 있는 성질을 동일성 identical 이라고 한다.


행동이 상태를 결정한다.

객체지향에 입문한 사람들이 가장 쉽게 빠지는 함정은
상태를 중심으로 객체를 바라보는 것이다.

객체에 필요한 상태가 무엇인지 결정하고 그 상태에 필요한 행동을 결정한다.
이런 행위는 설계에 나쁜 영향을 미친다.

  1. 캡슐화의 저해

  2. 객체를 협력자가 아닌 고립된 섬으로 만든다.

  3. 객체의 재사용성이 저하된다.

협력하는 좋은 객체 시민을 양성하기 위해서는 상태가 아니라 초점에 행동을 맞춰야한다.
다른 객체와 협력하기 위해 존재하는 객체의 행동은 협력에 참여하는 유일한 방법이다.

즉 객체지향 설계는 애플리케이션에 필요한 협력을 먼저 생각하고
협력에 참여하는데 필요한 행동을 생각한 후 행동을 수행할 객체를 선택하는 방식으로 진행된다.
행동을 결정한 후에야 행동에 필요한 정보가 무엇인지 고려하게 되고
이 과정에서 필요한 상태가 결정되는 것이다.

객체의 행동은 결국 협력에 참여하면서 객체가 완수해야하는 책임을 의미한다.
따라서 어떤 책임이 필요한가를 결정하는 과정이 전체 설계를 주도해야한다.
여기서 책임-주도 설계 Responsibility-Driven Design, RDD 라는 용어가 나온다.


은유와 객체

대부분의 사람들은 객체지향이란 현실 세계의 모방이라고 한다.
이는 현실세계에 존재하는 다양한 객체를 모방한 후 필요한 부분만 취해 소프트웨어 객체로
구현하는 과정이라고 설명한다.

현실세계의 추상화라고도 하는데, 객체지향 세계는 현실 세계의 단순 모방이 아니다.

그렇다면 둘의 가장 큰 차이는 무엇일까?

현실 세계의 객체는 수동적인 존재이지만 소프트웨어 객체는 능동적이라는 것이다.
우리는 현실 세계의 객체를 모방하지 않고 전혀 다른 특징들을 부여한다.
계좌가 스스로 금액을 이체하거나, 상품이 스스로 계산 금액을 기입할 수 없지만
객체지향 세계에서의 객체들은 어떤 일이든 스스로 할 수 있는 전지전능한 존재가 된다.

이는 추상화라기 보다는 의인화 라고 할 수 있다.


질문

  1. 협력에서 객체가 "자율적"이어야 한다는 의미는 무엇인가?
    한 객체가 다른 객체와 협력할 수 있게 개방적인 동시에 스스로 협력에 참여하는 방법을
    결정할 수 있도록 해야함을 의미한다. 이는 캡슐화를 강화한다.

  2. 객체와 단순한 값의 차이는 무엇인가?
    단순한 값은 상태값으로 동일 여부를 판단하지만 객체는 자신만의 식별자가 있는 존재이므로
    내부 상태 값이 같다고 하더라도 구분 할 수 있다. 또한 객체의 상태는 시간에 따라 변화할 수 있어 가변적이고 상태값은 변화하지않아 불변적이다.

  3. 객체지향 설계에서 "행동이 상태를 결정한다" 는 원칙의 의미와 중요성은?
    객체의 상태는 행동을 통해서 변하고 행동의 결과값은 그 전의 상태값에 의존된다.
    우리는 상태 중심 설계가 아닌 행동 중심 설계를 통해 객체의 역할을 효과적으로 수행해야함을
    의미한다.

  4. 책임 주도 설계 RDD 란 무엇이고 왜 중요한가?
    객체의 책임을 먼저 정의하고 그 책임을 수행하는데 필요한 행동과 상태를 설계하는 방법이다.
    이는 객체간의 결합도를 낮추고 재사용성과 유연성을 높이는데 기여한다.

  5. 현실 세계의 객체와 객체지향 세계에서의 객체의 차이는 무엇인가?
    현실 세계의 객체는 수동적인 반면 객체지향 세계에서의 객체는 자율적으로 상태를 관리하고
    행동을 결정할 수 있어 능동적인 존재이다.

  6. 클래스 기반 설계가 객체지향의 유연성을 저해할 수 있는 이유는 무엇인가?
    클래스 기반 설계는 객체의 역할보다는 데이터 구조에 초점을 맞추는 경향이 있다.
    이는 다음과 같은 문제를 초래할 수 있다.

    변경 시 클래스 계층구조 전체에 영향을 미치는 것
    상속을 과도하게 사용하면 코드 재사용이 아닌 강한 결합을 초래하는 것
    역할이 아닌 구체 클래스에 의존하게 되어 다형성과 확장성이 제한되는 것

profile
개발일기

0개의 댓글