Role & Responsibility & Cooperation(역할 & 책임 & 협력)

협력

협력은 한 객체가 다른 객체에 요청할 때 시작되며, 결과적으로 협력은 다수의 요청과 응답으로 구성된다. 그 요청과 응답은 협력에 참여하는 객체가 수행할 책임을 정의하게 된다.

책임

책임은 객체 지향 설계 품질을 결정하는 가장 중요한 요소이며, 크게 두 가지 분류로 나눌 수 있다.

  • Knowing(정보): 자신의 정보 / 관련된 객체의 정보 / 유도하거나 계산할 수 있는 정보

  • Doing(서비스): 객체를 생성하거나 계산을 수행하는 등의 스스로 하는 것 / 다른 객체의 행동을 시작 혹은 제어하는 것

위 객체의 정보와 서비스를 이용해 공용 인터페이스(public interface)를 구성할 수 있다. 이 공용 인터페이스는 객체지향의 중요한 특성인 캡슐화로 이어진다.

인터페이스

객체지향적인 사고 방식을 하기 위해선 인터페이스에 관련된 아래 세 가지 원칙을 따르는 것이 중요하다.

  • 추상적인 인터페이스

    • 상세한 수준의 메시지를 보내는 것은 객체의 자율성을 저해하기 때문에 메시지의 의도를 중점적으로 표현하는 것이 좋다

  • 최소 인터페이스

    • 외부에서 사용할 필요가 없는 인터페이스는 노출하지 않는 것이 좋다.

    • 객체의 내부를 수정하더라도 외부에 미치는 영향을 최소화할 수 있다.

  • 인터페이스와 구현 분리

    • 객체를 구성하지만 외부에 노출된 인터페이스에 포함되지 않은 모든 것이 구현에 포함된다.

    • 소프트웨어는 항상 변경될 수 있기 때문에 객체 내부를 수정하더라도 외부에 영향을 미치지 않도록 하는 것이 좋다.

    • 변경 가능성이 있는 부분은 객체 내부에 감추어 외부 인터페이스에 노출되지 않도록 한다.

    • 이는 캡슐화 원칙을 따르게 된다.

책임과 메시지

객체는 다른 객체에게 주어진 책임을 수행하도록 요청을 보내는 메시지 전송(message-send)이 이루어졌을 때만 책임을 수행하며, 메시지 수신자가 책임을 결정하게 된다. 이는 곧 객체는 메시지를 전송하여 다른 객체에 접근하며, 유일한 방법 또한 메시지를 통해서만 가능하다는 것을 의미한다. 메시지를 클래스의 메서드로 나타낼 수 있으며, 메시지에 필요한 다른 정보는 메서드의 인자로 나타내 수행할 수 있다.

역할

여러 가지의 협력은 포괄하여 하나의 역할로 표현할 수 있게 된다. 동일한 역할을 수행한다는 것은 동일한 책임의 집합을 수행한다는 것을 의미한다. 이를 확장하면 객체지향 설계의 단순성(simplicity), 유연성(flexibility), 재사용성(reusability)을 뒷받침하는 핵심 개념이 된다.

협력의 추상

역할을 부여함으로써 가장 큰 효과는 하나의 협력 안에 여러 종류의 객체가 참여할 수 있게 하여 협력을 추상화할 수 있다는 것이다. 협력의 추상화는 다뤄야하는 협력의 개체를 줄이면서 구체적 객체를 추상화된 역할로 대체함으로써 애플리케이션의 설계를 이해하기 쉬워진다.

대체 가능성

역할은 협력 안에서 구체적인 객체로 대체될 수 있는 추상적인 협력자이므로, 다른 객체에 의해 대체 가능함을 의미한다. 그렇다고 아무 객체가 역할을 대체하는 것이 아닌 해당 역할(책임의 집합)을 모두 수행할 수 있어야 한다.(해당 역할보다 더 많은 책임을 가질 수 있다.)

역할의 대체 가능성 = 행위의 호환성 = 동일한 책임의 수행

객체의 모양을 결정하는 협력

객체가 시스템에 필요한 데이터를 저장하기 위해 존재한다고 오해하기 쉽지만, 객체는 데이터를 포함하고 행위를 수행하는 데 필요할 뿐, 행위를 수행하며 협력에 참여하기 위해 존재한다. 각 객체를 독립적으로 바라보면 안 되고, 협력이라는 문맥을 고려하여 설계해야 클래스 중심이 아닌 객체지향적인 설계할 수 있다. 협력이라는 문맥에서 벗어나 독립적인 객체에 고민하는 것은 클래스 초점의 설계로 이어지며, 이는 객체지향 설계의 장점을 잃게 된다.

협력을 따라 흐르는 객체의 책임

깔끔한 협력 설계로부터 올바른 객체 설계가 시작된다. 올바른 협력 설계를 하기 위해서는 아래의 플로우를 따라가는 것이 좋다.

  1. 협력에 참여하는 객체들이 어떤 책임을 수행할지 할당

  2. 할당 된 책임을 통해 개체가 외부에 제공하게 될 행동을 결정

  3. 객체가 수행하게 될 적절한 책임을 수행하는 데 필요한 데이터를 결정

  4. 데이터와 행동이 결정 된 후에 클래스 구현 방법 결정

객체지향 설계 기법

역할 / 책임 / 협력 관점에서 애플리케이션을 설계하는 유용한 세 가지 기법이 있다.

책임-주도 설계(Responsibility-Driven Design)

책임-주도 설계에서는 시스템의 책임을 객체의 책임으로 변환하여, 각 객체가 책임 수행 중 필요한 협력자를 찾아 책임을 할당하는 순차적인 방식으로 협력 공동체를 설계한다. 개별 객체 상태가 아닌 객체의 책임과 상호작용(메시지)에 초점을 맞추어 설계하므로, 협조적인 객체를 만들 수 있다. 책임-주도 설계를 하기 위한 절차는 아래와 같다.

  • 시스템이 사용자에게 제공해야 하는 기능(시스템 책임) 파악

  • 시스템 책임을 더 작은 책임으로 분할

  • 분할된 책임을 수행할 수 있는 적절한 객체(역할)을 찾아 책임을 할당

  • 객체가 책임을 수행하는 중에 다른 객체의 도움이 필요한 경우 이를 책임질 객체(역할) 탐색

  • 해당 객체(역할)에 책임을 할당함으로써 두 객체 협력 관계 시작

결론적으로 '누가'를 먼저 결정하고 '무엇'을 결정하는 것이 아니라 '무엇'을 먼저 결정하고 '누가'를 결정하는 것이다. 설계를 할 때에 '누구'에게 시킬지 고민하기 전에 '무엇'을 해야할지가 먼저 선행되어야 하며, 이렇게 설계를 하게 되면 캡슐화는 자연스럽게 이루어지며 송/수신자의 의존성이 느슨하게 결합된다.

디자인 패턴

책임-주도 설계는 객체의 역햘/책임/협력을 고한하기 위한 방법 및 절차를 제시한 반면, 디자인 패턴은 책임-주도 설계의 결과를 표현한다. 이미 잘 알려지고 검증된 설계를 재사용할 수 있도록 패턴화한 것으로, 빠르고 손쉽게 결과물을 만들 수 있도록 도와준다.

테스트-주도 개발

단순히 테스트를 작성하는 것이 아니라 책임을 수행할 객체 또는 클라이언트가 기대하는 책임과 협력을 테스트 코드 형태로 작성하는 것이다. 책임-주도 설계의 기본 개념을 따르기 때문에 객체지향에 대해 깊이 있는 지식을 요구하게 된다.

참고자료

Last updated