역할, 책임, 협력
- 객체지향 패러다임의 핵심(객체지향은 클래스지향이 아니다.)
- 역할(Role)
- 책임(Responsibility)
- 협력(Collaboration)
- 객체지향의 본질은 협력하는 객체들의 공동체를 창조하는 것
- 협력을 위해 어떤 역할과 책임이 필요한 지 고민한다.
협력(Collaboration)
💡 사전적 의미 : 힘을 합하여 돕는 것
💡 객체들이 애플리케이션의 기능을 구현하기 위해 수행하는 상호작용
- 두 객체 사이의 협력은 하나의 객체가 다른 객체에게 도움을 요청할 때 시작된다.
- 메시지 전송 : 객체 사이의 협력을 위해 사용할 수 있는 유일한 커뮤니케이션 수단
- 상호작용을 통해 더 큰 책임을 수행한다.
- 메시지를 수신한 객체는 메서드를 실행해 요청에 응답한다.
- 캡슐화 : 자율적인 존재가 되기 위해 자신이 알고 있는 정보를 이용해 직접 책임을 다하는 것
- 협력이 설계를 위한 문맥을 결정한다.
- 객체 : 상태와 행동을 함께 캡슐화 하는 실행 단위
- 상태와 행동을 어떤 기준으로 결정해야 하는가? —> 협력
- 객체 : 상태와 행동을 함께 캡슐화 하는 실행 단위
- 영화 예매 시스템에서 Movie는 예매하기 위한 협력에 참여하고 있고, 요금을 계산하는 책임을 지고 있다.
- 객체가 참여하는 협력이 객체를 구성하는 행동과 상태를 모두 결정한다.
따라서 협력은 객체를 설계하는 데 필요한 일종의 문맥(Context)를 제공한다.
책임(Responsibility)
💡 사전적 의미 : 맡아서 행하지 않으면 안 되는 임무
- 협력을 위해 객체가 수행하는 행동
- 객체에 의해 정의되는 응집도 있는 행위의 집합
—> 객체가 유지해야 하는 정보와 수행할 수 있는 행동에 대해 개략적으로 서술한 문장- 무엇을 알고 있는가?
- 무엇을 할 수 있는가?
- 객체지향 설계에서 가장 중요한 것
- 적절한 책임을 할당해야 설계의 전체적인 품질을 결정할 수 있다.
💡 CRC 카드 Candidate(후보), Responsibility(책임), Collaborator(협력자)를 나열한 카드
- 선이 없는 면 : 후보의 목적을 기술
- 선이 있는 면 : 후보와 책임을 적고, 우측에 협력할 협력자들을 나열한다.
하는 것
- 객체를 생성하거나 계산을 수행하는 등의 스스로 하는 것
- 다른 객체의 행동을 시작시키는 것
- 다른 객체의 활동을 제어하고 조절하는 것
아는 것
- 사적인 정보에 관해 아는 것
- 관련된 객체에 관해 아는 것
- 자신이 유도하거나 계산할 수 있는 것에 관해 아는 것
Screening
- 하는 것
- 영화를 예매한다.
- 아는 것
- 자신이 상영할 영화
Movie
- 하는 것
- 요금을 계산한다.
- 아는 것
- 가격
- 적용된 할인 정책
자율적인 객체를 만들기 위해선 책임을 수행하는 데 필요한 정보를 가장 잘 알고 있는 전문가에게 그 책임을 할당하는 것이다.
- Movie는 요금을 알고 있기 때문에, 계산의 책임을 할당한다.
- 책임을 할당하기 위해선 협력이라는 문맥을 먼저 정의해야 한다.
책임 주도 설계(Responsibility - Driven Design, RDD)
- 시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악한다 (예매하라)
- 시스템 책임을 더 작은 책임으로 분할한다
- 분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당한다
- 객체가 책임을 수행하는 도중 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다
- 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 한다.
메시지가 객체를 결정한다.
- 책임을 할당하려면 필요한 메시지를 먼저 식별하고 메시지를 처리할 객체를 나중에 선택한다.
- 메시지에 의해 객체가 선택된다.
- 최소한의 인터페이스를 갖게 된다.
- 필요한 메시지가 식별될 때까지 객체의 퍼블릭 인터페이스에 어떤 것도 추가하지 않게 된다.
- 추상적인 인터페이스를 갖게 된다.
- 인터페이스는 무엇(what)을 하는 지 표현해야 하지만, 어떻게(how)를 수행하는지를 노출해서는 안 된다 (캡슐화 ; 자율적인 객체)
행동이 상태를 결정한다.
- 객체가 다른 객체에게 제공하는 행동으로부터 협력이 일어난다 (메시지 전송)
- 객체지향 패러다임에선 객체의 행동에 초점을 맞춰야 한다(not 상태)
역할(Role)
💡 사전적 의미 : 대상이 어떤 일에 있어서 가지는 자격이나 의무
역할 : 객체가 어떤 특정한 협력 안에서 수행하는 책임의 집합
- 실제로 협력을 모델링할 때는 특정한 객체가 아니라 역할에게 책임을 할당한다고 생각하는게 좋다
예를 들어, 영화 예매 협력에서
예매하라
라는 메시지를 처리하기에 적합한 객체로Screening
을 선택했다.- 영화를 예매할 수 있는 적절한 역할이 무엇인가?
- 역할을 수행할 객체로 Screening 인스턴스 선택(책임)
- 정리해보면, 역할을 먼저 고려하고 적절한 책임을 부여해야 한다.
- 왜 역할을 고려하는 과정을 거쳐야 하는가? 역할이 없어도 객체만으로 충분히 협력을 설계할 수 있는거 아닌가 ?
유연하고 재사용 가능한 협력
- 역할을 통해 유연하고 재사용 가능한 협력을 얻을 수 있다.
- 만약 역할을 고려하지 않는다면?
- 예시)
할인 요금 계산
협력에서 역할을 고려하지 않고 책임을 부여한다면?
- 예시)
- 이런 방법으로 구현하면 대부분 코드가 중복된다. 중복은 모든 문제의 근원이기 때문에 피해야 한다.
- 문제를 해결하기 위해 책임이 아닌 역할에 초점을 맞춰야 한다.
- 책임을 다시 생각해보면, 동일하게
할인 요금 계산
이라는 동일한 책임을 수행하고 있다.- 다른 두 가지 협력을 하나로 통합할 수 있다.
- 대표자 = 객체를 갈아 끼울 수 있는 슬롯
💡 역할은 다른 것으로 교체할 수 있는 책임의 집합이다.
- 역할은 여러 종류의 구체적인 객체를 포괄하는 추상화와 같다.
- 역할의 구현
- 추상클래스 / 인터페이스 사용
💡 개인적인 생각) 기계적으로
역할 == 인터페이스
로 보는 것은 지양 해야 할 것 같다
객체 vs 역할
- 협력에 적합한 책임을 수행하는 대상이 단일 = 객체
- 협력에 적합한 책임을 수행하는 대상이 다수 = 역할(추상클래스 / 인터페이스)
- 역할은 협력 안에서 각자의 위치를 가지는 객체들에 대한 별칭
- 설계 초기에 적절한 책임과 협력의 큰 그림을 탐색해야 하고, 역할과 객체를 명확하게 구분하는 것은 중요하지 않다.
- 변경에 유연하게 대응할 수 있는 구조로 만들고, 필요한 순간에 객체로부터 역할을 분리해내는 것이 가장 좋은 설계
역할과 추상화
- 역할은 일종의 객체의 추상화
- 추상화의 장점이 협력의 관점에서 역할에도 동일하게 적용된다.
추상화의 장점
- 세부 사항에 억눌리지 않고도 상위 수준의 정책을 쉽고 간단하게 표현한다(인터페이스)
- 설계를 유연하게 만들 수 있다
- 역할은 여러 객체를 갈아 끼울 수 있는 일종의 슬롯
배우와 배역
- 실세계로 추상화를 해봅시다
- 나 라는 존재의 역할과 책임은? 누구와 협력하는가?
- 직장인
- 운전자
- 보행자
- 스터디원
- 배우자
- 부모
- 나 라는 존재의 역할과 책임은? 누구와 협력하는가?
- 객체는 다양한 역할을 가질 수 있습니다.
- 협력에서 하나의 역할로 보여집니다.
- 여러 협력에 참여할 수 있습니다.
- 역할은 특정한 객체의 종류를 캡슐화하기 때문에 동일한 역할을 수행하고 계약을 준수하는 대체 가능한 객체들은 다형적입니다.
생각해보자
캡슐화의 진정한 의미
- 진정한 의미 : 자율적인 객체 ; 메시지 ; public interface
- 교과서적으로의 의미 :
정보은닉 ; 데이터 은닉 ; 멤버 변수 ; 상태가 아닌 데이터
객체지향을 실무에 자연스럽게 적용할 수 있는 방법이 뭐가 있을까?
“저희 CRC 카드를 작성 해 볼까요?”