본 포스팅은 오브젝트 CHAPTER 05 책임 할당하기의 이론적 내용을 정리한 글입니다. 구체적인 사례는 책에 잘 설명되어 있기에 읽어보시길 권장드립니다.
데이터 중심 설계는 데이터를 먼저 결정하고 고립된 객체의 상태에 초점을 맞추기 때문에 캡슐화를 위반하기 쉽고, 요소들 사이의 결합도가 높아지면 코드를 변경하기 어려워진다. 이를 해결하기 위한 가장 기본적인 방법은 데이터가 아닌 책임에 초점을 맞추는 것이다.
동일한 문제를 해결 할 수 있는 다양한 책임 할당 방법이 존재하며, 어떤 방법이 최선이지는 상황과 문맥에 따라 달라진다. 따라서 올바른 책임을 할당하기 위해서는 다양한 관점에서 설계를 평가할 수 있어야한다.
책임 주도 설계를 향해
데이터보다 행동을 먼저 결정하라
- 데이터 중심의 설계에서는
이 객체가 포함해야 하는 데이터가 무엇인가
를 결정한 후 필요한 오퍼레이션을 결정한다.
- 책임 중심의 설계에서는
이 객체가 수행해야 하는 책임은 무엇인가
를 결정한 후에 필요한 데이터를 결정한다.
협력이라는 문맥 안에서 책임을 결정하라
- 책임은 객체의 입장이 아니라 객체가 참여하는 협력에 적합해야한다.
- 객체가 메시지를 선택하는 것이 아니라 메시지가 객체를 선택하게 해야한다.
- "이 클래스는 무엇을 해야하지?" 가아니라 "메시지를 누구에게 전송해야하지?" 로 질문하는 것이 메시지 기반 설계로 향하는 첫걸음이다.
- 메시지를 먼저 결정하면 메시지를 보내는 송신자는 수신자에 대해 어떠한 가정도 할 수 없다. 즉 메시지 수신자가 캡슐화된다.
- 클라이언트가 전송할 메시지를 결정한 후에야 비로소 객체의 상태를 저장하는 데 필요한 내부데이터에 관해 고민하기 시작한다.
책임 주도 설계
- 책임 주도 설계 흐름
- 시스템이 사용자에게 제공해야하는 기능인
시스템 책임을
파악한 후 더 작은 책임으로 분할
한다.
- 분할된 책임을 수행 할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당한다.
- 객체가 책임을 수행하는 도중 다른 객체의 도움이 필요할 경우 이를 책임질 객체 또는 역할을 찾는다.
- 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 한다.
- 책임 주도 설계의 핵심은
책임을 결정한 후에 책임을 수행할 객체를 결정
하는 것이다.
책임 할당을 위한 GRASP 패턴
도메인 개념에서 출발하기
- 설계를 시작하는 단계에는 개념들의 의미와 관계가 정확하거나 완벽할 필요가 없다.
- 시작 단계에서는 객체의 종류와 관계에 대한 유요한 정보를 제공 할 수 있다면 충분하다.
정보 전문가에게 책임을 할당하다
메시지를 전송할 객체는 무엇을 원하는가?
라는 질문을 통해 메시지 이름을 결정한다.
메시지를 수신할 적합한 객체는 누구인가
- 객체는 자신의 상태를 스스로 처리하는 자율적인 존재여야한다.
- 책임을 수행할 정보를 알고 있는 객체에게 책임을 할당한다. 이를
Information expert
패턴이라 부른다.
Information expert
가 알고 있는 정보는 데이터뿐 아니라 정보를 제공할 수 있는 다른 객체나 필요한 정보를 계산해서 제공 할 수 있는 정보들도 포함된다. 즉 정보전문가가 데이터를 반드시 저장하고 있을 필요는 없다.
- 스스로 처리 할 수 없는 작업이 있다면 외부에 도움을 요청한다. 이 요청은 새로운 메시지가 되고 이 같은 연쇄적인 메시지 전송과 수신을 통해 협력 공동체가 된다.
창조자에게 객체 생성 책임을 할당하라
- GRASP의 CRATOR 패턴은 객체를 생설할 책임을 어떤 객체에게 할당하지에 대한 지침을 제공한다.
- 객체 A를 생성해야 할 때 어떤 객체에게 객체 생성 책임을 할당해야하는가는 아래 조건을 최대한 많이 만족하는 B에게 객체 생성 책임을 할당하라
- B가 A 객체를 포함하거나 참조한다.
- B가 A 객체를 기록한다.
- B가 A 객체를 긴밀하게 사용한다.
- B가 A 객체를 초기화 하는데 필요한 데이터를 가지고 있다.
클래스 응집도 판단하기
- 변경에 취약한 클래스란 코드를 수정해야 하는 이유를 하나 이상 가지는 클래스이다.
- 클래스가 하나 이상의 이유로 변경돼야 한다면 응집도가 낮은 것이다. 변경의 이유를 기준으로 클래스를 분리하라.
- 클래스 인스턴스 초기화하는 시점에 경우에 따라 서로 다른 속성들을 초기화하고 있다면 응집도가 낮은 것이다. 초기화 되는 속성의 그룹을 기준으로 클래스를 분리하다.
- 메소드 그룹이 속성 그룹을 사용하는지 여부로 나뉜다면 응집도가 낮은 것이다. 이들 그룹을 기준으로 클래스를 분리하다.