책임 할당하기

  • 설계에서 책임에 초점을 맞추는 것이 좋다.
  • 그러나 책임에 초점을 맞춰서 설계할 때 가장 큰 어려움은 어떤 객체에게 어떤 책임을 할당할지를 결정하기 어렵다는 것이다.
  • GRASP 패턴을 이용하면 이 어려움을 덜 수 있다.

GRASP

  • General Responsibility Assignment Software Patterns
  • Object-Oriented 디자인의 핵심은 각 객체에 책임을 부여하는 것.
  • 책임을 부여하는 원칙들을 말하고 있는 패턴.
  • 구체적인 구조는 없지만, 철학을 배울 수 있다.
  • 총 9가지의 원칙을 가지고 있다.

1. Information Expert

  • 책임에 걸맞는 객체에 데이터를 부여하는 것
  • 객체는 데이터와 처리로직이 함께 묶여 있는 것.
  • 정보 은닉을 통해 자신의 데이터를 감추고 오직 Method로만 데이터를 처리하고, 외부에는 그 기능(책임)만을 제공한다.것
  • 객체는 스스로를 처리하는 자율적인 존재
  • 수행할 정보를 알고 있는 객체에 책임을 할당

2. Creator

  • A 객체와 B 객체의 관계의 관계가 다음 중 하나라면 A의 생성을 B의 책임로 부여.
  • B 객체가 A 객체를 포함하고 있다.
    • B 객체가 A 객체의 정보를 기록하고 있다.
    • A 객체가 B 객체의 일부이다.
    • B 객체가 A 객체를 긴밀하게 사용하고 있다.
    • B 객체가 A 객체의 생성에 필요한 정보를 가지고 있다.
  • Factory Pattern

3. Controller

  • 시스템 이벤트(사용자의 요청)를 처리할 객체를 만들자.
  • 만약 어떤 서브시스템안에 있는 각 객체의 기능을 직접 사용한다면?
  • 직접적으로 각 객체에 접근하게 된다면 서브시스템과 외부간의 Coupling이 증가되고
  • 서브시스템의 어떤 객체를 수정할 경우, 외부에 주는 충격이 크게 된다.
  • 서브시스템을 사용하는 입장에서 보면, 이 Controller 객체만 알고 있으면 되므로 사용하기 쉽다.

4. Low Coupling

  • 객체들간, 서브 시스템들간의 상호의존도가 낮게 책임을 부여.
  • Low Coupling은 각 객체, 서브시스템의 재 사용성을 높이고, 시스템 관리에 편하게 한다.
  • Object-Oriented 시스템은 각 객체들간의 Communication을 통하여 비즈니스를 완성시킴.
  • 각 객체들 사이에 Coupling이 존재하지 않을 수는 없다.
  • 이 패턴은 요구사항은 충족시키면서도 각 객체들, 각 서브시스템 간의 Coupling를 낮은 수준으로 유지하는 방향으로 디자인.

5. High Cohesion

  • 각 객체가 밀접하게 연관된 책임들만 가지도록 구성.
  • 한 객체, 한 시스템이 자기 자신이 부여받은 책임만을 수행하도록 짜임새 있게 구성되어 있다면?
  • 자신이 부여 받은 책임을 충족시키기 위해 다른 객체나 시스템을 참조하는 일이 적으며 자연스럽게 Low Coupling이 된다.
  • 변경의 이유에 따라 클래스를 분리하다 보면 자연스레 응집도가 높아진다.

    응집도 판단

    1. 클래스가 하나 이상의 이유로 변경돼야 한다면 응집도가 낮은 것이다. 변경의 이유를 기준으로 클래스를 분리하라.
    2. 클래스의 인스턴스를 초기화하는 시점에 경우에 따라 서로 다른 속성들을 초기화하고 있다면 응집도가 낮은 편이다. 초기화되는 속성의 그룹을 기준으로 클래스로 분리
    3. 메소드 그룹이 속성 그룹을 사용하는지 여부로 나뉜다면 응집도가 낮은 것이다. 이들 그룹을 기준으로 클래스를 분리하라.

6. Polymorphism

  • 객체의 종류에 따라 행동양식이 바뀐다면, Polymorphism 기능을 사용하자.
  • 만약 객체의 종류에 따라 행동이 바뀐다면 객체의 종류를 체크하는 조건문을 사용하지 말고
  • Object-Oriented 시스템의 Polymorphism 기능을 사용하라.
  • 역할의 개념이 수면 위로 떠오른다. 역할은 협력 안에서 대체 가능성을 의미한다.
  • 역할을 제시하고 실질적인 행동을 숨기면 의존성을 제한할 수 있다. ( 객체의 구체적인 타입을 추상화 할 수 있다.)

7. Pure Fabrication

  • 도메인에 관련된 문제를 대표하는 것이 아니라면 기능적인 책임을 별도로 한 곳으로 관리하는 객체를 만들자.
  • 데이터베이스 정보를 저장하거나, 로그 정보를 기록하는 책임에 대해 생각해 보자. 각 정보는 각각의 객체들이 가지고 있을 것이다.
  • Information Expert 패턴을 적용하면?
  • 각 객체들이 정보를 저장하고, 로그를 기록하는 책임을 담당해야 하지만, 실제로 그렇게 사용하는 사람들은 없다.
  • 시스템 전반적으로 사용하고 있는 기능을 변경한다면?
  • 모든 객체를 수정해야 하는 결과를 가져온다.
  • 즉 Low Coupling의 원칙이 깨어지게 된다.
  • 이럴 경우에는 공통적인 기능을 제공하는 책임을 한 곳으로 모아서 가상의 객체, 서브시스템을 만들어라.

8. Indirection

  • 두 객체 사이의 직접적인 Coupling을 피하고 싶으면, 그 사이에 다른 매개체를 통해 전달하는 것.
  • 주로 다른 매개체는 인터페이스인 경우가 많다.
  • 그런 특별한 경우는 아래에 설명된 Protected Variations 패턴이라고 부를 수 있다.

9. Protected Variations

  • 변경을 캡슐화하도록 책임을 할당하는 것을 의미한다.
  • 변경될 여지가 있는 그 주위에 안정된 인터페이스를 형성하도록 책임을 할당하라
  • 설계에서 변하는 것이 무엇인지 고려하고 변하는 개념을 캡슐화하라

책임 주도 설계 지향

  1. 데이터보다는 행동을 먼저 결정 ( “이 행동을 하기 위해서 어떤 데이터가 필요한가?” 로 접근하자)
  2. 협력이라는 문맥 안에서 책임을 결정 (메시지를 전송하는 클라이언트의 의도에 적합한 책임을 할당해야 한다.)

    더 자세하게

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