객체지향의 역할, 책임, 협력

역할, 책임, 협력

하나의 프로그램을 만들기 위해서는 다양한 객체가 자신의 로직을 실행해서 전체 기능을 완성한다.

중요한 건, 다양한 객체가 한 기능을 만들기 위해 메시지 를 주고 받으며 상호작용한다는 사실이다.

이처럼 어플리케이션의 기능을 완성하기 위해 여러 객체가 상호작용하는 것을 협력이라고 한다.

각 객체들이 수행하는 자신의 로직을 책임이라고 하고, 객체들이 협력 안에서 수행하는 책임이 모여 객체가 수행하는 역할을 구성한다.

협력

두 객체 사이의 협력은 한 객체가 다른 객체에 도움을 요청하면서 시작된다.
메시지 전송은 객체 사이의 협력을 만드는 유일한 커뮤니케이션 수단이다.

즉 협력이란 어떤 객체가 다른 객체에게 무엇인가를 요청하는 행위다.
협력은 역할을 수행하기 위한 특정 책임을 잘 수행할 수 있는 다른 객체에게 위임하는 행위다.

협력과 자율성

메시지를 수신한 객체는 메서드를 실행해 요청을 실행한다.
이때 협력을 요청한 객체는 응답하는 객체가 어떤 방식으로 메시지를 처리할지 알지 못한다.
요청하는 객체가 해당 책임에 대해 지나치게 개입하면 안된다! (다른 객체의 내부구현에 손대지말라.)
(ex. 협력에 참여하는 객체의 인스턴스 변수에 직접 접근하는 경우는 해당 객체의 자율성을 훼손 -> private 키워드로 캡슐화)

객체의 행동과 상태

객체는 어떤 협력에 참여할 지에 따라 상태와 행동이 정의되어야 한다.
협력이 객체가 필요한 이유와 객체가 수행하는 행동의 동기를 제공한다.
협력이 달라지면 객체의 행동도 달라질 수 있다. 협력없는 행동은 아무 의미 없다!

그렇다면 상태는 왜 존재하는가?
상태는 행동에 사용되기 때문에 존재한다.

즉 협력은 객체의 행동을 정의하고
객체의 행동이 필요한 정보에 따라 객체의 상태가 결정된다.

결국 협력은 객체의 모든 것을 설계하는 문맥을 제공한다.

책임

책임은 협력에 참여하기 위해 객체가 수행하는 행동이다.

책임을 지는 객체는 책임을 완수하기 위해 필요한 정보를 알고 있어야 한다.
혹은 그 책임을 할 수 없는 객체가 그 책임이 필요한 경우, 그 책임을 할 수 있는 객체를 알고 있어야 한다.

책임은 단순한 행동을 해야 하는 것 뿐만 아니라, 그 행동에 필요한 정보도 알고 있어야 하는 것을 의미한다.

객체지향에서 제일 중요한 것이 객체에게 적절한 책임을 지게 하는 것이다.

책임 할당

책임 할당을 위한 기본적인 방법은 그 책임을 수행하기 위해 필요한 정보를 가장 잘 아는 전문가에게 책임을 주는 것이다.

이제 이 책임을 할당하는 과정을 살펴보자.

  1. 하나의 큰 메시지를 정의한다.
    (시스템이 사용자에게 제공하는 큰 기능을 하나의 책임으로 본다)
  2. 메시지를 정의했으면 그 메시지를 처리할 객체를 고른다.
    (이때 메시지가 크기 때문에 그 객체 혼자서 처리 못한다.)
  3. 그 객체가 처리하지 못하는 책임은 다른 전문가(!)를 찾아서 메시지를 전달한다.
  4. 이 과정을 2번과 3번을 반복한다.

책임 주도 개발

위 과정을 책임 주도 개발로 표현하면 다음과 같다

  1. 일단 시스템이 사용자에게 제공하는 기능을 시스템이 담당할 하나의 책임으로 본다.
    (시스템의 책임을 파악)
  2. 이제 하나의 큰 책임을 더 작은 책임으로 잘게 분해한다.
  3. 분해된 책임들을 객체들에게 할당한다.
  4. 책임을 수행하던 객체가 다른 객체의 도움이 필요하면 적절한 객체 혹은 역할을 찾는다.
  5. 해당 객체가 참여하게 되면서 두 객체는 협력하게 된다.

역할

역할은 특정한 협력 안에서 수행하는 책임의 집합.
실제로 협력에서 객체에게 책임을 할당한다기 보다는 역할에 책임을 할당한다고 보는 게 좋다.

역할은 유연하고 재사용 가능한 협력을 얻을 수 있게 한다.
역할은 다른 것으로 교체할 수 있는 책임의 집합이다.

즉 동일한 책임을 가진 여러 객체가 있다면, 그것을 추상화 한 것이 역할이다.

영화 예매를 예시로 들면,
영화 요금을 할인 하는 두 가지 방식이 있다고 하자.
하나는 요금의 퍼센트로 할인하는 방식이고,(10퍼센트 할인..)
다른 하나는 예매 표 중 일부 값을 할인하는 방식이 있다.(두 표사면 한 표는 할인..)

이 두 방식 모두 객체로 표현된다면, 이 두 객체는 요금을 할인한다는 동일한 책임을 가진다.
그렇다면 우리는 이 같은 책임을 하나의 역할로 추상화하여 표현할 수 있다.
이렇게 하면 할인 방식에 따라 협력을 일일히 만들지 않고, 역할이 할인 정책을 추상화하여 담당하게 된다.

(자바에서 역할을 구현하는 방식은 추상 클래스와 인터페이스를 사용한다.)

객체냐 역할이냐

그렇다면 동일 책임을 지는 다른 객체가 없는,
즉 하나의 객체만이 해당 책임을 지는 경우에도 그 객체를 역할로 추상화 해줘야 할 까?

답은 아니다.

책임 수행하는 대상이 한 종류면, 간단하게 객체로 간주해도 좋다.
다만 책임 수행하는 객체가 여러 종류면, 역할로 간주하라.

사실 설계 초반에는 객체와 역할을 명확히 하긴 힘들다.
다양한 객체들이 협력에 참여한다는 것이 확실하면 역할로 시작해라.
애매하고 확실하지 않은 경우는 객체로 시작하자. (진행하면서 역할로 대체하면 된다.)

Share