결국엔 프로그래밍
[OBJECT] 오브젝트 Chapter 3 - 역할, 책임, 협력 본문
객체지향에서 가장 중요한 것은 역할, 책임, 협력이다.
클래스, 상속, 지연 바인딩도 중요하지만 구현 측면에 치우쳐있어 객체지향 패러다임의 본질과는 거리가 있다.
어떤 협력이 필요하고 협력을 위해 어떤 역할과 책임이 필요한지 고민해야 한다.
협력 - 객체들이 애플리케이션 기능을 구현하기 위해 수행하는 상호작용
책임 - 객체가 협력에 참여하기 위해 수행하는 로직
역할 - 객체들이 협력 안에서 수행하는 책임들이 모여 역할을 이룬다.
협력
객체는 사회적 존재이다.
메시지 전송을 통해서 객체들은 상호작용한다.
메시지를 통해 다른 객체에게 위임하거나 서로 협력한다.
메서드를 통해 수신한 메시지를 처리한다.
자율적인 객체가 되기 위해 필요한 정보와 이에 기반한 행동을 하나의 객체에 둬야 한다.
만약, A라는 객체가 B라는 객체의 정보를 이용해 이와 관련된 행동을 하는 경우 이 정보와 행동이 A, B로 나눠지게 된다. 이렇게 되면 B객체는 수동적인 객체로 전락한다.
이를 방지하기 위해 캡슐화를 한다.
그 결과, 자율적인 객체는 자신에게 할당된 책임을 수행하고 모르는 정보가 있거나 도움이 필요한 경우 메시지를 통해 다른 객체와 협력한다.
협력이 설계를 위한 문맥을 결정
협력이 객체 설계에 필요한 문맥(context)을 제공
[ 협력 → 행동 → 상태 ]
객체가 협력에 참여하기 위해 협력에 필요한 행동을 해야 한다.
즉, 객체의 행동을 결정하는 것은 객체가 참여하고 있는 행동이다.
그리고 객체는 자신의 상태를 스스로 결정하고 관리하는 자율적 존재기 때문에 행동에 필요한 상태를 갖고 있어야 한다.
public class Movie{
private Money fee;
private DiscountPolicy discountPolicy;
public Money calculateMovieFee(Screening screening){
return fee.minus(discountPolicy.calculateDiscountAmount(screening));
}
}
Movie가 fee와 discountPolicy를 인스턴스 변수로 갖는 이유는 calculateMovieFee라는 행동을 수행하는데 이 정보들이 필요하기 때문이다.
결과적으로 객체가 참여하는 협력이 객체를 구성하는 행동과 상태를 모두 결정하게 된다.
책임
협력에 참여하기 위해 객체가 수행하는 행동
객체가 유지해야 하는 정보와 수행할 수 있는 행동에 대해 서술한 문장이다.
크게 '아는 것'과 '하는 것'으로 나뉜다.
- 하는 것
- 객체를 생성하거나 계산을 수행하는 등의 스스로 하는 것
- 다른 객체의 행동을 시작시키는 것
- 다른 객체의 활동을 제어하고 조절하는 것
- 아는 것
- 사적인 정보에 관해 아는 것
- 관련된 객체에 관해 아는 것
- 자신이 유도하거나 계산할 수 있는 것에 관해 아는 것
협력의 안에서 객체에게 할당된 책임은 외부의 인터페이스와 내부의 속성을 결정한다.
책임은 메시지보다 추상적이고 넓은 개념을 갖고 있다.
객체는 책임을 수행하기 위해 필요한 정보를 알아야 한다. 또한 자신이 할 수 없는 일을 도와줄 수 있는 객체도 알고 있을 책임이 있다.
협력이 중요한 이유는 객체에게 할당할 책임을 결정하는 문맥을 제공하기 때문이다.
적절한 협력이 적절한 책임을 제공하고, 적절한 책임을 적절한 객체에 할당해야 유연한 설계를 할 수 있다.
가장 중요한 것은 책임이다. 얼마나 적절한 책임을 부여하는지가 전체적인 품질을 결정한다.
03장 02절 p.80까지
책임 할당
Information Expert Pattern(정보 전문가 패턴)
자율적인 객체를 만드는 기본적인 방법 → 책임을 수행하는데 가장 잘 아는 전문가에게 책임을 할당
객체에 책임을 할당하기 위해서 가장 먼저 협력이라는 문맥을 정의해야 한다.
협력을 위해선 가장 먼저 사용자에게 제공할 기능을 하나의 책임으로 봐야 한다.
그리고 하나의 책임 안에서 더 작은 책임을 찾고 이를 객체들에 할당하는 반복적 과정을 수행한다.
기본적으로 책임을 수행할 정보 전문가를 찾는 방식으로 책임을 할당해야 하고
이 과정에서 객체지향 설계는 협력에 필요한 메시지를 찾고 그에 적절한 객체를 선택하는 반복적인 과정을 통해 이뤄진다.
책임 주도 설계
Responsibility-Driven Design, RDD(책임 주도 설계)
책임을 찾고 책임을 수행할 적절한 객체를 찾아 책임을 할당하는 방식으로 협력을 설계하는 방법
- 시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악
- 시스템 책임을 더 작은 책임으로 분할
- 분할된 책임을 수행할 수 있는 적절한 객체 혹은 역할을 찾아 책임을 할당
- 객체가 책임을 수행하는 도중 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 혹은 역할을 찾는다.
- 해당 객체 혹은 역할에게 책임을 할당하면서 두 객체는 협력한다.
책임 주도 설계는 유연하고 견고한 객체지향 시스템을 위해 가장 중요한 책임에 집중한다.
메시지가 객체를 결정한다
객체에게 책임을 할당하는 데 필요한 메시지를 먼저 식별하고 메시지를 처리할 객체를 나중에 선택하는 것이 중요하다.
이유
1) 최소한의 인터페이스를 가질 수 있다.
필요한 메시지가 식별될 때까지 퍼블릭 인터페이스에 어떤 것도 추가되지 않기 때문
2) 충분히 추상적인 인터페이스를 가질 수 있다.
메시지는 외부의 객체가 요청하는 것을 의미한다. 따라서 메시지를 먼저 식별하면 무엇을 수행할지에 초점을 맞추고 어떻게 수행하는지에 대해서는 노출시키지 않을 수 있다.
example) 영화 예매 시스템
메시지: '예매하라' → 수신할 적절한 객체: Screening (메시지: '계산하라' → 수신할 적절한 객체: Movie)
행동이 상태를 결정한다
객체는 행동을 제공하고 협력에 참여한다.
우리는 캡슐화를 위반하지 않기 위해 구현에 대한 결정은 뒤로 미루면서
객체의 행위를 고려하기 위해선 협력이라는 문맥 안에서 객체를 생각해야 한다.
즉, 객체의 상태가 아니라 행동이 중요하다.
협력이 객체의 행동을 결정하고 행동이 상태를 결정한다.
그리고 행동이 바로 객체의 책임이 된다.
역할
객체가 협력 안에서 수행하는 책임의 집합
실제로 협력을 모델링할 때 객체가 아니라 역할에 책임을 할당한다.

역할은 다른 것으로 교체할 수 있는 책임의 집합이다.
예를 들어, '할인 요금을 계산하라'라는 메시지를 수행하는 역할은 금액 할인, 비율 할인 둘이 맡을 수 있다.
하나의 역할은 일종의 슬롯과 같아서 다른 종류의 객체를 교대로 바꿔 끼는 것이 가능하다.

이렇게 하면 코드의 중복을 방지하고 유연하게 재사용 가능한 협력을 얻을 수 있다.
역할을 구현하는 일반적인 방법이 추상 클래스와 인터페이스를 사용하는 것이다.
둘은 협력의 관점에서 모두 역할을 정의할 수 있는 구현 방법이라는 공통점을 갖는다.
다시 말해 역할은 구체적인 객체들의 타입을 캡슐화하는 추상화이다.
객체 vs 역할
역할은 객체가 참여할 수 있는 일종의 슬롯이라 한다. 역할은 재사용 가능한 설계라는 점에서 아주 중요하다. 그렇다면 한 종류의 객체만의 협력에 참여하는 상황에도 역할이라는 개념에 적용해야 할까?
결론부터 말하자면, 협력에 적합한 책임을 수행하는 대상이 한 종류라면 간단하게 객체로 간주한다. 여러 종류의 객체들이 참여할 때만 역할이라고 부른다.

린스 카우에 따르면 협력은 역할들의 상호작용으로 구성되고, 협력을 구성하기 위해 역할에 적합한 객체가 선택되며, 객체는 클래스를 이용해 구현되고 생성된다.
설계 초반에는 어떤 것이 역할이고 어떤 것이 객체인지 결정하기 어렵다. 따라서 적절한 책임과 협력의 큰 그림을 탐색하는 것이 중요하다. 단순하게 객체로 시작하고 반복적으로 책임과 협력을 정제하면서 필요할 때 객체로부터 역할을 분리하는 것이 가장 좋은 방법이다. 즉, 처음에는 협력을 위해 어떤 책임이 필요한지를 이해하는 것이 중요하다.
역할과 추상화
역할과 추상화라는 제목을 갖고 있는데 난 역할이라는 추상화로 제목을 바꾸고 싶다. 역할은 객체의 추상화로 볼 수 있다. 그렇기 때문에 추상화가 갖는 두 가지의 장점을 역할도 가질 수 있다.
첫 번째, 상위 수준의 정책을 쉽고 간단하게 표현할 수 있다. 추상화를 통해 불필요한 세부 사항을 생략하고 핵심적인 개념을 강조할 수 있다. 협력이라는 관점에서는 세부적인 사항을 무시하고 추상화에 집중하는 것이 유용하다. 이 경우 객체 사이의 상호 작용이 더 또렷하게 드러난다. 역할이 중요한 이유는 동일한 협력을 수행하는 객체들을 추상화할 수 있기 때문이다.


두 번째, 설계를 유연하게 할 수 있다. 협력 안에서 역할이라는 추상화를 통해 기존 코드를 수정하지 않고도 새로운 행동을 추가할 수 있다. 그 결과 유연한 설계가 가능하다.
추가적으로, 객체는 여러 역할을 가질 수 있지만 특정한 협력안에서는 일시적으로 오직 하나의 역할만이 보여진다. 객체는 다수의 역할을 보유할 수 있지만 객체가 참여하는 특정 협력은 객체의 한가지 역할만 바라볼 수 있다.
3장 끝.
'객체지향프로그래밍 > [책] Object 오브젝트' 카테고리의 다른 글
| [OBJECT] 오브젝트 Chapter 5 - 책임 할당하기 (0) | 2022.01.23 |
|---|---|
| [OBJECT] 오브젝트 Chapter 4 - 설계 품질과 트레이드오프 (0) | 2022.01.16 |
| [OBJECT] 오브젝트 Chapter 2 - 객체지향 프로그래밍 (part2) (0) | 2022.01.07 |
| [OBJECT] 오브젝트 Chapter 2 - 객체지향 프로그래밍 (0) | 2022.01.03 |
| [OBJECT] 오브젝트 Chapter 1 - 객체, 설계 (0) | 2022.01.02 |