객체지향의 관점에서 핵심은 역할, 책임, 협력 이다. 객체지향의 본질은
협력하는 객체들의 공동체를 창조하는 것이다.
객체들이 어플리케이션의 기능을 구현하기 위해 수행하는 상호작용을 협력
이라고 한다. 객체가 협력에 참여하기 위해 수행하는 로직을 책임이라고 부른다.
객체들이 협력 안에서 수행하는 책임들이 모여 객체가 수행하는 역할을 구성한다.
메시지 전송은 객체 사이의 협력을 위해 사용할 수 있는 유일한 커뮤니케이션
수단이다. 다른 객체의 상세한 내부 구현에 접근할 수 없기 때문에 오직 메시지
전송을 통해서만 자신의 요청을 전달할 수 있다. 메시지를 수신한 객체는
메서드를 실행해 요청에 응답한다. 여기서 객체가 메시지를 수신할 방법을
스스로 선택한다는 점이 중요하다.
만약, 앞선 영화 예매 시스템의 코드에서 Screening이 Movie의 fee 필드와
discountPolicy에 직접 접근해야 한다면 Movie의 자율성이 훼손될 것이다.
따라서 Screening이 Movie에게 요금을 계산하도록 위임해야 Movie가 자신의
상태를 직접 관리하게 되어 자율성이 보존된다.
결과적으로 객체를 자율적으로 만드는 가장 기본적인 방법은 내부 구현을 캡슐화
하는 것이다. 자율적인 객체는 자신에게 할당된 책임을 수행하던 와중에 필요한 정보를
알지 못하거나 외부의 도움이 필요한 경우 적절한 객체에게 메시지를 전송해서 협력을
요청한다.
애플리케이션 안에 어떤 객체가 필요하다면 그 이유는 단 하나, 그 객체가 어떤 협력에
참여하고 있기 때문이다. 결론적으로 객체의 행동을 결정하는 것은 객체가 참여하고 있는
협력이다. 협력이 존재하기 때문에 객체가 존재한다.
객체의 행동을 결정하는 것이 협력이라면 객체의 상태를 결정하는 것은 행동이다. 객체의
상태는 그 객체가 행동을 수행하는 데 필요한 정보가 무엇인지로 결정된다. 결과적으로
객체가 참여하는 협력이 객체를 구성하는 행동과 상태 모두를 결정한다. 따라서 협력은
객체를 설계하는 데 필요한 일종의 문맥을 제공한다.
협력에 참여하기 위해 객체가 수행하는 행동을 책임이라고 부른다.
객체의 책임은 크게 하는 것(doing)과 아는 것(knowing)의 두 가지 범주로 나누어
세분화하고 있다.
하는 것
아는 것
CRC 카드를 이용해 앞 장에서 기술하였던 영화 예매 시스템을 표현하면 다음과 같다.

협력 안에서 객체에게 할당한 책임이 외부의 인터페이스와 내부의 속성을 결정한다.
일반적으로 책임이 메시지보다 추상적이고 개념적으로 더 크며, 책임이 여러 개의
메시지로 분할되거나 분산되어 있던 책임이 하나로 통합될 필요가 생기기도 한다.
중요한 사실은 '아는 것'과 '하는 것'이 밀접하게 연관되어 있으며, 객체는 책임 수행에
필요한 정보를 알고 자신이 할 수 없는 작업을 도와줄 객체도 알고 있을 책임이 있다.
CRC라는 단어는 Candidate, Responsibility, Collaborator의 첫 글자를 따서 만들어졌다.
하나의 CRC 카드는 협력에 참여하는 하나의 후보를 표현한다. 후보는 역할, 객체, 클래스
어떤 것이라도 될 수 있다. 목적은 후보가 외부에 제공해야 하는 서비스를 하나의 문장으로
표현한다.

좌측 하단에는 목적을 세분화해서 무엇을 알고 무엇을 해야 하는지에 대해
책임을 차례대로 적는다. 카드의 우측에는 책임을 수행하면서 함께 협력할
협력자들을 나열한다.
자율적인 객체를 만드는 가장 기본적인 방법은 책임을 수행하는 데 필요한 정보를
가장 잘 알고 있는 전문가에게 그 책임을 할당하는 것이다. 이를 책임 할당을 위한
INFORMATION EXPERT(정보 전달) 패턴이라고 부른다.
객체에게 책임을 할당하기 위해서는 먼저 협력이라는 문맥을 정의해야 한다.
객체지향 설계는 시스템의 책임을 완료하는 데 필요한 더 작은 책임을 찾아내고 이를
객체에게 할당하는 반복적인 과정을 통해 모양을 갖춰간다.
영화 예메 시스템에 이를 적용하면 다음 과정을 거쳐 설계가 이뤄진다.

이 과정을 통해 결정된 메시지가 객체의 퍼블릭 인터페이스를 구성한다는 것을
눈여겨 봐야 한다. 협력을 설계하며 객체의 책임을 식별하는 과정에서 최종적으로
얻게 되는 것은 시스템을 구성하는 객체들의 인터페이스와 오퍼레이션의 목록이다.
책임을 찾고 책임을 수행할 적절한 객체를 찾아 책임을 할당하는 방식으로 협력을
설계하는 방법을 책임 주도 설계(RDD)라고 부른다.
책임 주도 설계의 방법 과정을 정리하면 다음과 같다.
메시지가 객체를 선택하게 해야 하는 두 가지 중요한 이유가 있다.
첫째, 객체가 최소한의 인터페이스를 가질 수 있게 된다. 필요한 메시지가
식별될 때까지 객체의 퍼블릭 인터페이스에 어떤 것도 추가하지 않기 때문에
객체는 꼭 필요한 적절한 크기의 퍼블릭 인터페이스를 가질 수 있다.
둘째, 객체는 충분히 추상적인 인터페이스를 가질 수 있게 된다. 메시지는 외부의 객체가 요청하는 무언가를 의미하기 때문에 메시지를 먼저 식별하면 무엇을 수행할지에 초점을 맞추는 인터페이스를 얻을 수 있다.
객체의 존재 이유는 협력에 참여하기 위함이다. 객체의 행동은 객체가 협력에 참여할
수 있는 유일한 방법이고, 따라서 객체가 협력에 적합한지를 결정하는 것은 그 객체의
상태가 아니라 행동이다.
객체의 상태를 먼저 결정하고 그에 필요한 행동을 결정하는 설계를
데이터-주도 설계(DDD) 라고 부르는데 이는 객체의 내부 구현이 퍼블릭
인터페이스를 노출하게 만들어 캡슐화를 저해한다.
중요한 것은 객체의 행동이다. 객체가 가질 수 있는 상태는 행동을 결정하고
나서야 비로소 결정할 수 있다. 협력이 객체의 행동을 결정하고 행동이 상태를
결정한다. 그리고 그 행동이 바로 객체의 책임이 된다.
객체가 어떤 특정한 협력 안에서 수행하는 책임의 집합을 역할이라고 부른다.
익명의 역할을 찾고 그 역할을 수행할 수 있는 객체를 선택하는 방식으로
설계가 진행될 수 있다.
역할이 중요한 이유는 역할을 통해 유연하고 재사용 가능한 협력을 얻을 수
있기 때문이다.
영화 예매 도메인에는 금액 할인 정책과 비율 할인 정책이라는 두 가지 종류의
가격 할인 정책이 존재하기 때문에 AmountDiscountPolicy 와
PercentDiscountPolicy가 그에 맞추어 정의되어 있었다. 이 때
두 협력을 개별로 구현하면 코드가 상당히 중복될 것이다.
문제를 해결하기 위해선 객체가 아닌 책임에 초점을 맞춰야 한다. 책임의
관점에선 두 객체 모두 할인 요금 계산이라는 동일한 책임을 수행하고 있다.
따라서 객체라는 존재를 지우고 할인 요금을 계산하라는 메시지에 집중하면
두 협력을 하나로 통합할 수 있다. 이 통합되어 대체될 수 있는 형태가 바로
역할이다.
여기서의 역할은 두 종류의 구체적인 객체를 포괄하는 추상화다.
요점은 동일한 책임을 수행하는 역할을 기반으로 두 개의 협력을 하나로
통합할 수 있다는 것이다.
역할의 구현
역할을 구현하는 가장 일반적인 방법은 추상 클래스와 인터페이스를
사용하는 것이다. 추상 클래스는 역할 수행이 가능한 모든 객체들이 공유하는
상태와 기본 구현이 존재할 때 사용하고, 인터페이스는 공통의 구현이
필요 없고 단지 책임의 목록만 정의하면 되는 경우 사용한다.
역할은 객체를 추상화 해서 객체 자체가 아닌 협력에 초점을 맞출 수 있게 한다.
역할은 객체가 참여할 수 있는 일종의 슬롯이다. 협력에 적합한 책임을
수행하는 대상이 한 종류라면 간단히 객체로 간주하지만, 만약 여러 종류
객체들이 참여할 수 있다면 역할이라고 부르면 된다.
대부분의 경우 역할과 객체를 명확하게 분리하기 어렵다. 특히나 설계 초반에는
더욱 그렇다. 설계 초반에는 적절한 책임과 협력의 큰 그림을 구성하는 데
집중하는 것이 좋고 단순히 객체로 시작하여 반복적으로 책임, 협력을
정제해가면서 필요한 순간에 객체로부터 역할을 분리해내는 것이 가장 좋은
방법이라고 생각된다.
동일한 책임을 서로 다른 방식으로 수행할 수 있는 객체들이 필요해질 때
역할의 도입을 고려해도 늦지 않다.
역할은 공통의 책임을 바탕으로 객체의 종류를 숨기기 때문에 이런 관점에서
역할을 객체의 추상화로 볼 수 있다.