3. 역할, 책임, 협력
- 객체지향 패러다임의 핵심
- 역할(role)
- 책임(responsibility)
- 협력(collaboration)
- 객체지향의 본질은 협력하는 객체들의 공동체를 창조하는 것
- 협력을 구성하기 위해 적절한 객체를 찾고 적절한 책임을 할당
- 클래스와 상속은 구현 메커니즘일뿐
- 구현에 치우치면 변경이 어렵고 유연하지 못한 코드를 낳는다
3.1. 협력
영화예매시스템 돌아보기
- 객체지향 애플리케이션의 제어 흐름은 다양한 객체들에 분배되어 있음
- 협력: 객체들이 애플리케이션의 기능을 구현하기 위해 수행하는 상호작용
- 책임: 객체가 협력에 참여하기 위해 수행하는 로직
- 역할: 객체들이 협력 안에서 수행하는 책임들의 모음
협력
- 객체는 사회적인 존재
- 협력은 한 객체가 다른 객체에게 도움을 요청할 때 시작된다
- 메시지 전송(send a message)은 객체간의 유일한 커뮤니케이션 수단
- 객체는 다른 객체의 세부 구현에 직접 접근할 수 없다
- 메시지 수신 객체는 메서드를 실행해 요청에 응답 (스스로 메시지를 처리)
- 캡슐화: 객체를 자율적으로 만드는 기본적인 방법
- 내 상태는 내가 알아서 한다
- 변경하기 쉬워진다
협력이 설계를 위한 문맥을 결정한다
- 애플리케이션에 어떤 객체가 필요하다면 그 이유는 단 하나여야 한다. (SRP)
- 객체가 협력에 참여하고 있기 때문
- 협력에 필요한 적절한 행동(상태)를 보유했기 때문
- 협력은 객체가 필요한 이유와 객체의 행동 동기를 제공
- 협력은 객체의 행동을 결정, 행동은 객체의 상태를 결정
- 자율적인 객체는 행동에 필요한 상태를 가지고 있어야 한다.
→ 데이터 관점에서 설계하면 자율적인 객체를 설계하기 힘든 것 같다.
- 협력은 객체 설계에 필요한 문맥(context)을 제공
3.2. 책임
책임이란 무엇인가
- 협력이 갖춰지면 협력에 필요한 행동을 수행할 객체를 찾아야 한다.
- 책임: 협력하는 객체의 행동
- 객체에 의해 정의되는 응집도 있는 행위의 집합
- 무엇을 알고있는가? 무엇을 할 수 있는가?
- doing
- 객체 생성, 계산 수행 (constructor, method)
- 다른 객체의 행동을 시작 (send a message?)
- 다른 객체의 활동을 제어, 조절
- knowing
- 사적인 정보에 대해 아는 것 (state?)
- 관련된 객체에 관해 아는 것 (dependency?)
- 자신이 유도하거나 계산할 수 있는 것에 관해 아는 것 (state?)
- 영화시스템의 책임 예
- Screening: 영화 예매 (doing), 상영할 영화를 기억 (knowing)
- Movie: 요금 계산 (doing), 가격과 할인정책을 기억 (knowing)
- 아는 것과 하는 것은 밀접하게 연관되어 있음
- 책임을 적절하게 할당하는 것은 객체지향 설계의 핵심!!
→ CRC 카드의 첫 번째 C도 Class였으니 워드 커닝햄도 클래스 기반 설계에 초점을 맞춘게 아닐까? 적어도 처음엔
책임 할당
- 자율적인 객체를 만드려면 필요한 정보를 가장 잘 알고 있는 전문가에게 책임을 할당해야 한다. → 정보 전문가 패턴(Information Expert pattern)
- 책임을 할당하는 방법
- 시스템이 사용자에게 제공하는 기능을 하나의 책임으로 바라본다
- 시스템의 책임을 완료하는데 필요한 더 작은 책임을 찾는다. (책임 쪼개기)
- 객체에게 책임을 할당
- 2~3 반복
책임 주도 설계
- 책임을 찾고 책임을 수행할 적절한 객체를 찾아 책임을 할당하는 방식으로 협력을 설계하는 방법
- 구현이 아닌 책임에 집중할 수 있다
메시지가 객체를 결정한다
- 메시지를 식별한 후에 메시지를 처리할 객체를 선택한다
- 객체가 메시지를 선택하지 않는다
- 객체는 최소한의 인터페이스만 가질 수 있다.
- 추상적인 인터페이스를 가질 수 있다.
→ 메시지 처리라는 필요에 의해 설계하게 되니 자연스럽게 SRP, ISP를 지킬수 있겠다.
→ 내가 경험했던 데이터 정의 >> 구현은 이렇게 생각하기가 어렵게 느껴진다.
행동이 상태를 결정한다
- 객체는 협력에 참여하기 위해 존재한다
- 객체는 다른 객체에게 제공하는 행동이 중요한다
→ getter를 남발하지 말고 직접 처리하자
- 데이터 주도 설계를 지양하자
- 협력이라는 문맥 안에서 객체를 생각해야 한다
- 협력에 초점을 맞춰야 응집도가 높고 결합도가 낮은 객체를 설계할 수 있다
- 상태는 행동에 필요한 재료일뿐
- 협력이 객체의 행동을 결정, 행동이 상태를 결정, 행동이 객체의 책임
2.3. 역할
역할과 협력
- 객체의 목적? 협력 안에서 객체가 맡게 되는 책임의 집합 → 역할
- 객체의 목적이 곧 역할
- 적절한 역할을 찾고
- 역할을 수행할 객체를 선택
유연하고 재사용 가능한 협력
- 역할을 통해 유연하고 재사용 가능한 협력을 얻을 수 있다
→ 역할은 인터페이스??
역할은 다른 것으로 교체할 수 있는 책임의 집합이다.
- 역할은 구체적인 객체를 포괄하는 추상화
- 역할을 이용하면 불필요한 중복 코드를 제거할 수 있다. (추상화의 이점)
- 새로운 할인정책을 위해 협력을 추가할 필요가 없어짐 (이미 추상화했기 때문에)
객체 대 역할
- 역할은 객체가 참여할 수 있는 일종의 슬롯
- 한 종류의 객체만 존재하는데 역할(추상클래스/인터페이스)이 필요할까?
- 그럴 필요없다
- 어떤게 역할이고 객체인지 뚜렷하게 드러나지 않음
- 특히 설계 초반에는 더더욱
- 설계 초반에는 책임과 협력을 탐색하는 것이 중요한 목표
- 책임과 협력을 정제해가면서 필요한 순간에 객체로부터 역할을 분리하자
역할과 추상화
- 역할은 객체의 추상화
- 세부 사항에 억눌리지 않고 상위 수준의 정책을 쉽고 간단하게 표현할 수 있다
- 설계를 유연하게 만든다
- 역할은 슬롯
- 프레임워크나 디자인 패턴의 핵심 요소가 역할!!
배우와 배역
- 배우(객체) - 배역(역할)
- 역할은 협력 안에서의 일시적인 개념
- 객체는 다양한 역할을 가질 수 있다