본문 바로가기

Spring/Object

[Object] 책임 주도 설계 내용 정리

본 포스팅은 책 오브젝트의 "5장 책임 할당하기"를 읽고 정리한 내용입니다.

 


 

데이터 중심의 설계에서 책임 중심의 설계로 전환하기 위해서는 두 가지 원칙을 따라야 한다.

 

1. 데이터보다는 행동을 먼저 결정하라
2. 협력이라는 문맥 안에서 책임을 결정하라

 

핵심은 설계를 진행하는 동안 데이터가 아니라 객체의 책임과 협력에 초점을 맞추라는 것이다.

 

데이터보다 행동을 먼저 결정하라

객체에게 중요한 것은 데이터가 아니라 외부에 제공하는 행동이다.

데이터 중심의 설계에선 "이 객체가 포함해야 하는 데이터가 무엇인가"를 먼저 결정한 후에 "데이터를 처리하는 데 필요한 오퍼레이션은 무엇인가"를 결정한다.

반면, 책임 중심의 설계에서는 "이 객체가 수행해야 하는 책임은 무엇인가"를 결정한 후에 "이 책임을 수행하는 데 필요한 데이터는 무엇인가"를 결정한다.

 

다시 말해, 책임 중심의 설계에서는 객체의 행동, 즉 책임을 먼저 결정한 후에 객체의 상태를 결정한다는 것이다.

 

협력이라는 문맥 안에서 책임을 결정하라

그럼 어떤 객체에게 어떤 책임을 할당해야 할까? 바로 협력에서 해결의 실마리를 찾을 수 있다.

책임은 객체의 입장이 아니라, 객체가 참여하는 협력에 적합해야 한다.

협력을 시작하는 주체는 메시지 전송자이기 때문에 협력에 적합한 책임이란 메시지 수신자가 아니라 메시지 전송자에게 적합한 책임을 의미한다.

 

다시 말해서

 

메시지를 전송하는 클라이언트의 의도에 적합한 책임을 할당해야 한다는 것이다.

 

 

또한 먼저 객체를 선택한 후에 메시지를 결저앟는 것이 아니라, 메시지를 결정한 후에 객체를 선택해야 한다.

 

클라이언트가 전송할 메시지를 결정한 후에야 비로소 객체의 상태를 저장하는 데 필요한 내부 데이터에 대해 고민하기 시작한다.

 

 

책임 주도 설계

책임 주도 설계의 흐름을 정리하면,

 

1. 시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악한다.
2. 시스템 책임을 더 작은 책임으로 분할한다.
3. 분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당한다.
4. 객체가 책임을 수행하는 도중 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다.
5. 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 된다.

 

 

이를 바탕으로 GRASP 패턴 (General Responsibility Assignment Software Pattern) 을 적용하여 책의 예제에 나와있는 데이터 중심의 설계로 구현된 영화 예매 시스템을 책임 중심으로 설계해보겠다.

 

영화 예매 시스템 개괄

p.38에 상세 내용이 있다.

 

영화

  • 제목, 상영기간, 가격 정보와 같이 영화가 가지고 있는 기본적인 정보

 

상영

  • 실제로 관객들이 영화를 관람하는 사건을 표현
  • 상영 일자, 시간, 순번 등
  • 사용자가 실제로 예매하는 대상은 상영임

 

할인

  • 특정 조건을 만족하는 예매자는 요금 할인 받을 수 있음
  • 할인 조건, 할인 정책이 할인액을 결정함
  • 사용자에게 예매 정보가 할인 조건 중 하나라도 만족하는 결정
    • 하나라도 할인 조건을 만족한다면 할인 정책을 이용하여 할인 요금 계산
    • 할인 정책은 적용되어 있지만 할인 조건을 만족하지 못하는 경우 또는 아예 할인 정책이 사용되어 있지 않은 경우에는 요금 할인 안 함 

 

할인조건

  • 할인 조건은 가격의 할인 여부를 결정하며 순서 조건(discount condition)과 기간 조건(period condition)의 두 가지 종류로 나눌 수 있음
  • 영화 별로 다수의 할인 조건 할당 가능 (순서 조건과 기간 조건 섞는 것도 가능)
  • 순서 조건은 상영 순번을 이용해 할인 여부를 결정하는 규칙 
    • 순서 조건의 순번이 10인 경우 매일 10번째로 상영되는 영화를 예매한 사용자들에게 할인 혜택을 제공
  • 기간 조건은 영화 상영 시작 시간을 이용해 할인 여부를 결정하는 규칙
    • 기간 조건은 요일, 시작 시간, 종료 시간 세 부분으로 구성되며 영화의 시작 시간이 해당 기간 안에 포함될 경우 요금을 할인
    • 요일이 월요일 시작 시간이 오전 10시, 종료 시간이 오후 1시인 기간 조건을 사용하면 매주 월요일 오전 10시부터 오후 1시 사이에 상영되는 모든 영화에 대해 할인 혜택을 적용할 수 있음

할인정책

  • 할인 정책에는 금액 할인 혜택(amount discount policy)과 비율 할인 정책(percent discount policy)이 있음
  • 영화 별로 하나의 할인 정책만 할당 가능 (없어도 됨)
  • 금액 할인 정책은 예매 요금에서 일정 금액을 할인해주는 방식 
    • 금액 할인 정책이 800원일 경우 9000원에서 800원 뺀 8200원 됨
  • 비율 할인 정책은 정가에서 일정 비율의 요금을 할인해주는 방식
    • 비율 할인 정책이 10%일 경우 9000원에서 10% 뺀 8100원이 됨

 

도메인 개념에 따라 클래스 구조 연결해보기

일반적으로 사용되는 UML을 이용하여 도메인 개념에 따라 클래스 구조를 그려보겠다.

 

다중성을 표현하고, 클래스들 사이의 관계를 나타내기 위해 UML(시스템을 모델로 표현해주는 대표적인 모델링 언어)을 어떻게 표현하는지 아래 포스팅을 보고 오자.

 

 

[UML] 클래스 다이어그램 작성법 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

처음에 그린 도메인 구조

 

위의 사진은 처음에 그린 도메인 구조이다.

 

여기서 구현을 도메인의 관계에 따라 몇 가지 수정해야 하는 사항이 있어 수정을 했다.

 

1. 먼저 예매라는 동작을 할 수 있는 도메인을 추가하고 상영을 연결해주었다.

2. 영화와 상영의 위치를 바꿔주었다. 하나의 영화당 0..1개의 할인 조건과 연결을 바로 해줄 수 있다. 또한 예매 시 상영의 대상이 1개의 영화이기 때문에 상영 다음에 영화를 넣었다.

3. 할인 조건과 할인 정책의 위치를 바꿔주었다. 구현을 생각해볼 때, 영화에 할인 정책이 있는지 먼저 검증해주고 있을 때만 할인 조건을 만족하는 게 있는지 파악하면 되기 때문에 위치를 바꾸어주었다.

 

수정한 도메인 구조는 아래와 같다.

 

수정한 도메인 구조

 

cf. 올바른 도메인 모델이란 존재하지 않지만 필요한 것은 구현에 도움이 되는 모델이다. 실용적이면서도 유용한 모델이 답이다.

 

정보 전문가에게 책임을 할당하라

책임 주도 설계 방식의 첫 단계는 애플리케이션이 제공해야 하는 기능을 애플리케이션의 책임으로 생각하는 것이다.

즉, 이번엔 "애플리케이션은 영화를 예매할 책임이 있다"고 간주할 수 있다.

이제 이 책임을 수행하는 데 필요한 메시지를 결정해야 한다.

메시지는 메시지를 수신(받는)할 객체가 아니라 메시지를 전송할 객체의 의도를 반영해서 결정해야 한다.

 

따라서 다음과 같은 질문을 해야 한다.

 

메시지를 전송할 객체는 무엇을 원하는가?
메시지를 받을 적합한 객체는 누구인가?

 

두 번째 질문에 대해서는 INFORMATION EXPERT (정보 전문가) 패턴을 적용하여 객체의 책임과 책임을 필요한 상태는 동일한 객체 안에 존재해야 한다 라는 사실을 생각하고 적용하면 된다.

 

즉, 책임을 수행하는 데 필요한 정보를 가지고 있는 객체에게 할당하면 된다.

이를 통해 정보와 행동을 최대한 가까운 곳에 위치시키기 때문에 캡슐화를 유지할 수 있게 된다.

 

창조자에게 객체 생성 책임을 할당하라

그렇다면 Reservation 인스턴스는 어디에서 생성하는 것이 적합할까?

이때는 CREATOR 패턴을 사용하여 해당 인스턴스를 잘 알고 있거나, 긴밀하게 사용하거나, 초기화에 필요한 데이터를 가지고 있는 객체에서 객체를 생성해주는 게 좋다. 

구현 시엔 Screening에서 예매 정보를 생성하는 데 필요한 영화, 상영 기간, 상영 순번 등에 대해 알고 있으며 예매 요금 계산 시에 필수적인 Movie도 알고 있다.

 

커뮤니케이션 다이어그램 만들어보기

 

구현해볼 클래스들의 이름을 적용해서 커뮤니케이션 다이어그램을 만들어보았다.

 

이제 진짜 구현을 시작해보자!

 

구현은 다음 포스팅에서..