3. 역할, 책임, 협력

  • 협력: 객체들이 에플리케이션의 기능을 구현하기 위해 수행하는 상호작용
  • 책임: 객체가 협력에 참여하기 위해 수행하는 로직
  • 객체들이 협력 안에서 수행하는 책임들이 모여 객체가 수행하는 역할을 구성한다.

협력

  • 메시지 전송(message sending) 은 협력을 위해 사용할 수 있는 유일한 커뮤니케이션 수단

  • 객체가 스스로 메시지를 처리할 방법(메서드)을 자율적으로 선택

  • 자율적인 객체가 되기 위해서는 자신이 할 수 없는 일을 다른 객체에게 위임하면 협력에서 전체적인 자율성이 향상

    • 가장 기본적인 방법은 캡슐화 이다.

협력이 설계를 위한 문맥을 결정한다

  • 객체의 행동을 결정하는 것은 객체가 참여하고 있는 협력이다.

  • 협력은 객체가 필요한 이유와 객체가 수행하는 행동의 동기를 제공한다.

  • Movie의 행동을 결정하는 것은 영화 예매를 위한 협력이다.

    • 협력이라는 문맥을 고려하지 않고 Moive의 행동을 결정하는 것은 아무런 의미가 없다.
  • 상태는 객체가 행동하는 데 필요한 정보에 의해 결정되고 행동은 협력 안에서 객체가 처리할 메시지로 결정 된다.

  • 객체가 참여하는 협력이 객체를 구성하는 상태와 행동 모두를 결정한다.

    • 협력은 설계에 필요한 context(문맥) 을 제공한다.

책임

  • 책임이란 객체에 의해 정의되는 응집도 있는 행위의 집합
  • 객체의 책임은 ‘무엇을 알고 있는가(knowing)’, ‘무엇을 할 수 있는가(doing)’ 으로 구성 된다.
    • 두 개는 밀접하게 연관되어 있다.
    • 객체는 책임을 수행하는 데 필요한 정보를 알고 있을 책임
    • 할 수 없는 작업을 도와줄 객체를 알고 있을 책임
    • 그 책임을 수행하는 데 필요한 정보도 알아야할 책임
  • 책임은 메시지 보다 추상적이면서 개념적으로 더 크다.
  • 책임은 객체지향 설계의 핵심, 책임을 능숙하게 소프트웨어 객체에게 할당하는 것은 매우 중요하다.
  • 객체의 구현 방법은 책임보다 상대적으로 덜 중요하고 책임 이후에 고민해도 늦지 않다.

책임 할당

  • 자율적인 객체를 만드는 가장 기본적인 방법은 책임을 수행하는 데 필요한 정보를 잘 알고 있는 전문가에게 그 책임을 할당하는 것

    • 정보 전문가 패턴(Information Expert) 이라 한다.
  • 객체에게 책임을 할당하기 위해서는 협력이라는 문맥을 정의해야 한다.

  • 협력을 설계하는 출발점은 시스템이 사용자에게 제공하는 기능을 시스템이 담당할 하나의 책임으로 바라보는 것

    • 객체지향 설계는 필요한 더 작은 책임을 찾아내고,이를 객체들에게 할당하는 반복적인 과정
  • 객체가 책임을 수행하게 하는 유일한 방법은 메시지 전송 이므로, 책임을 할당한다는 것은 메시지의 이름을 결정하는 것과 같다.

    • 이렇게 결정된 메시지가 객체의 퍼블릭 인터페이스를 구성한다.
  • 협력을 설계하면서 객체의 책임을 식별해 나가는 과정에서 최종적으로 얻게 되는 결과물은 시스템을 구성하는 객체들의 인터페이스와 오퍼레이션 목록이다.

  • 책임 주도 설계(RDD): 책임을 찾고 책임을 수행할 적절한 객체를 찾아 할당하는 방식으로 협력을 설계하는 방법

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

메시지가 객체를 결정한다

  • 객체가 메시지를 결정하는 것이 아니라, 메시지가 객체를 선택하게 했다

    1. 객체가 최소한의 인터페이스를 가질 수 있게 된다.
    2. 객체는 충분히 추상적인 인터페이스를 가질 수 있게 된다.
      • 인터페이스는 what(무엇)을 하는 지 표현해야 하지만, how(어떻게) 수행하는지는 노출하면 안 된다.
  • 메시지(예매하라)를 선텍하는 것으로 설계를 시작 그리고, 그 메시지를 수신할 객체를 선택(Screening)

행동이 상태를 결정한다

  • 객체의 행동은 객체가 협력에 참여할 수 있는 유일한 방법

    • 협력에 얼마나 적합한지 결정하는 것은 상태(데이터) 가 아니라 행동이다.
  • 객체의 내부 구현에 초점을 맞춘 설계 방법은 데이터-주도 설계(Data-Driven Design) 이라 한다.

  • 상태는 단지 객체가 행동을 정상적으로 수행하기 위해 필요한 재료일 뿐이다.

역할

  • 객체는 협력이라는 문맥 안에서 특정한 목적을 갖게 된다.

    • 목적은 협력 안에서 객체가 맡게 되는 책임의 집합(=역할) 으로 표시
  • 역할은 다른 것으로 교체할 수 있는 책임의 집합이다.

  • 역할은 구체적인 객체를 포괄하는 추상화 이다.

    • 추상적인 이름을 부여해야 한다. (Ex. DiscountPolicy)
  • 책임을 수행하는 역할을 기반으로 두 개의 협력을 하나로 통합할 수 있다.

    • 역할을 이용하면 불필요한 중복 코드를 제거할 수 있다.
    • ‘새로운 할인 정책을 추가하기 위해 새로운 협력을 추가할 필요가 없어짐’
  • 역할을 구현하는 가장 일반적인 방법은 추상 클래스와 인터페이스를 사용하는 것

    • 추상 클래스는 책임의 일부를 구현해 놓은것
    • 인터페이스는 구현 없이 책임의 집합만을 나열
  • 역할이 다양한 종류의 객체를 수용할 수 있는 슬롯이자 구체적인 객체들의 타입을 캡슐화하는 추상화 이다.

    • 협력 안에서 역할이 어떤 책임을 수행해야 하는지 결정하는 것이 중요

객체 대 역할

  • 협력에 참여하는 후보가 여러 종류의 객체에 의해 수행될 필요가 있다면 그 후보는 역할

  • 단지 한 종류의 객체만이 협력에 참여할 필요가 있다면 후보는 객체

  • 역할은 서로 다른 방법으로 실행할 수 있는 책임의 집합

  • 역할을 객체들에 대한 별칭이라고 정의하기도 한다.

    • 객체는 클래스를 이용해 구현되고 생성
  • 협력 -reference-> 역할 -select from-> 객체 -instance of-> 클래스

  • 초기 설계에는 책임과 협력의 큰 그림을 탐색하는게 중요, 역할과 객체를 명확하게 구분하는 것은 그렇게 중요하지 않다.

배우와 배역

  • 연극: 협력

  • 배우: 협력 안에서 역할을 수행하는 객체

  • 극본: 코드

  • 객체의 페르소나: 역할

  • 역할은 모양이나 구조에 의해 정의될 수 없으며 오직 시스템의 문맥 에서만 정의될 수 있다.

  • 배우가 여러 연극에 참여해 여러 배역을 연기할 수 있듯이, 객체는 다양한 역할 수행

    • 특정한 협력 안에서는 일시적으로 오직 하나의 역할만이 보여짐
    • 참여하는 특정 협력은 객체의 한 가지 역할만 바라 볼 수 있다.
  • 배우는 연극이 끝나면 배역을 잊고 원래의 자기 자신을 되찾는다

Reference