Chapter 04 역할, 책임, 협력
객체지향에 갓 입문한 사람들의 가장 흔한 실수는 협력이라는 문맥을 고려하지 않은 채 객체가 가져야 할 상태와 행동부터 고민하기 시작한다는 것이다. 객체들 간의 요청과 응답 속에서 창발 하는 협력에 초점을 맞춰 애플리케이션을 설계해야 한다. 협력이 자리를 잡으면 저절로 객체의 행동이 드러나고 뒤이어 적절한 객체의 상태가 결정된다.
📌 설계를 하는 중에 객체 하나하나를 보았을 때, 객체가 비합리적이고 너무 비효율적이면 객체를 수정할 생각만 하고 있었다. 객체 자체를 좀 더 효율적이고 간단하게 만드려고만 했었는데 나도 무의식적으로 객체에만 집중을 했던 것 같다. 객체들을 따로 떼어놓고 보았을 때 겉모습이 다소 이상하고 기괴하더라도 협력이 훌룡하다면 훌룡한 객체지향 설계라는 것을 깨달았다.
협력
⚡ 협력은 다수의 요청과 응답으로 구성되며 전체적으로 협력은 다수의 연쇄적인 요청과 응답의 흐름으로 구성된다.
책임
책임은 객체지향의 가장 중요한 재료이다. 명확한 책임이 애플리케이션의 미래를 결정짓는다.
⚡ 객체지향의 세계에서는 어떤 객체가 어떤 요청에 대해 대답해줄 수 있거나, 적절한 행동을 할 의무가 있는 경우 해당 객체가 책임을 가진다고 말한다.
"객체지향에서 가장 중요한 능력은 책임을 능숙하게 소프트웨어 객체에 할당하는 것" -Craig Larman-
객체의 책임은 "객체가 무엇을 알고 있는가"와 "무엇을 할 수 있는가"로 구성된다.
하는 것 doing
- 객체를 생성하거나 계산을 하는 등의 스스로 하는 것
- 다른 객체의 행동을 시작시키는 것
- 다른 객체의 활동을 제어하고 조절하는 것
아는 것 knowing
- 개인적인 정보에 관해 아는 것
- 관련된 객체에 관해 아는 것
- 자신이 유도하거나 계산할 수 있는 것에 관해 아는 것
💡 즉, 책임은 객체의 외부에 제공해 줄 수 있는 정보(아는 것의 측면)와 외부에 제공해 줄 수 있는 서비스(하는 것의 측면)의 목록이다. 따라서 책임은 객체의 공용 인터페이스 public interface를 구성한다.
💡 객체지향 설계는 협력에 참여하기 위해 어떤 객체가 어떤 책임을 수행해야 하고 어떤 객체로부터 메세지를 수신할 것인지를 결정하는 것으로부터 시작된다. 어떤 클래스 필요하고, 어떤 메서드 포함하고~ 이런 건 책임과 메세지에 대한 대략적인 윤곽을 잡은 후에 하도록 하자!
역할
⚡ 역할role은 협력 내에서 다른 객체로 대체할 수 있음을 나타내는 일종의 표식이다. 역할을 대체할 수 있는 객체는 동일한 메세지를 이해할 수 있는 객체로 한정된다.
역할은 객체지향 설계의 단순성, 유연성, 재사용성을 뒷받침하는 핵심 개념이다.
협력의 추상화
하나의 협력 안에 여러 종류의 객체가 참여할 수 있게 함으로써 협력을 추상화할 수 있다.(협력은 구체적인 객체를 추상적인 역할로 대체함으로써 하나의 추상적인 협력으로 대체할 수 있다.) 역할을 이용하면 협력을 추상화함으로써 단순화할 수 있다.
대체 가능성
객체가 역할을 대체하기 위해서는 협력 안에서 역할이 수행하는 모든 책임을 동일하게 수행할 수 있어야 한다.
또한! 객체가 역할에 주어진 책임 이외에 다른 책임을 수행할 수도 있기 때문에 객체는 역할이 암시하는 책임보다 더 많은 책임을 가질 수 있다.
대부분의 경우에 객체의 타입과 역할 사이에는 일반화/특수화 관계가 성립한다. 일반화/특수화 관계에서 좀 더 일반적인 개념을 의미하는 역할은 일반화이고, 좀 더 구체적인 개념을 의미하는 객체의 타입은 특수화다.
⚡ 역할의 대체 가능성은 행위 호환성을 의미하고, 행위 호환성은 동일한 책임의 수행을 의미한다.
객체의 모양을 결정하는 협력
💡흔히 생각하는 오류 바로잡기💡
- 데이터는 단지 객체가 행위를 수행하는 데 필요한 자료일 뿐, 데이터를 위해 객체가 존재하는 것이 아니다.
- 클래스는 단지 시스템에 필요한 객체를 표현하고 생성하기 위해 프로그래밍 언어가 제공하는 구현 메커니즘이라는 사실을 기억하고 너무 클래스의 정적인 측면에 중점을 두지 말자.
일단 객체에게 책임을 할당하고 나면 책임은 객체가 외부에 제공하게 될 행동이 된다. 협력이라는 문맥에서 객체가 수행해야 될 적절한 책임, 즉 행동을 결정한 후에 그 행동을 수행하는데 필요한 데이터를 고민해야 한다. 그리고 객체가 협력에 참여하기위한 행동과 데이터가 어느정도 결정이 된 후에 클래스의 구현 방법을 결정해야 한다.
📌 데이터와 행동, 책임을 고려하고 클래스를 구현해야 한다는 것이 가장 중요한 부분 같았다.
객체의 행위에 초점을 맞추기 위해서는 협력이라는 실행 문맥 안에서 책임을 분배해야 한다. 각 객체가 가져야 하는 상태와 행위에 대해 고민하기 전에 그 객체가 참여할 문맥인 협력을 정의하라. 객체를 충분히 협력적으로
객체지향 설계 기법
역할, 책임, 협력의 관점에서 애플리케이션을 설계하는 유용한 세 가지 기법
1. 책임-주도 설계 Responsability-Driven Design
: 협력에 필요한 책임들을 식별하고 적합한 객체에게 책임을 할당하는 방식으로 설계하는 방법
객체의 책임을 중심으로 시스템을 구축하는 설계 방법.
객체의 상태가 아니라 객체의 책임과 상호작용에 집중한다.
- 시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악한다.
- 시스템 책임을 더 작은 책임으로 분할한다.
- 분할된 책임을 수행할 수 있는 적절한 객체 또는 역할을 찾아 책임을 할당한다.
- 객체가 책임을 수행하는 중에 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다.
- 해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 한다.
2. 디자인 패턴 Design Pattern
: 전문가들이 반복적으로 사용하는 해결 방법을 정의해 놓은 설계 템플릿 모음
디자인 패턴은 설계의 결과를 표현한다. 일반적으로 디자인 패턴은 반복적으로 발생하는 문제와 그 문제에 대한 해법의 쌍으로 정의된다. 패턴은 해결하려고 하는 문제가 무엇인지를 명확하게 서술하고, 패턴을 적용할 수 있는 상황과 적용할 수 없는 상황을 함께 설명한다. 패턴은 반복해서 일어나는 특정한 상황에서 어떤 설계가 왜 더 효과적인지에 대한 이유를 설명한다.
만약 특정한 상황의 디자인 패턴을 잘 알고 있다면 책임-주도 설계의 절차를 빠르게 구현할 수 있다.
3. 테스트 주도 개발 Test-Driven Development
: 테스트를 먼저 작성하고 테스트를 통과하는 구체적인 코드를 추가하면서 애플리케이션 방식을 따른다.
실패하는 테스트를 작성하고, 테스트를 통과하는 가장 간단한 코드를 작성한 후, 리팩터링을 통해 중복을 제거하는 것이다. 결과적으로 "작동하는 깔끔한 코드"를 얻을 수 있다.
이미 객체가 존재한다고 가정하고 객체에게 어떤 메세지를 전송할 것인지에 관해 먼저 생각하라고 충고한다. 테스트를 작성하는 것이 아니라 책임을 수행할 객체 또는 클라이언트가 기대하는 객체의 역할이 메세지를 수신할 때 어떤 결과를 반환하고 그 과정에서 어떤 객체와 협력할 것인지에 대한 기대를 코드의 형태로 작성하는 것이다.
테스트라는 안정장치를 통해 좀 더 빠르고 견고한 방법으로 도달할 수 있도록 해주는 최상의 설계 프랙티스다.
테스트-주도 개발은 책임-주도 설계의 기본 개념과 다양한 원칙과 프랙티스, 패턴을 종합적으로 이해하고 좋은 설계에 대한 감각과 경험을 길러야만 적용할 수 있는 설계 기법이다.
📌객체지향 설계를 할 때 실질적으로 고려해야 하는 부분들이 자세하게 설명되어 있어서 좋았다. 앞에서 이해한 객체의 특성을 통해서 객체 지향 설계를 해나갈 때 전반적으로 생각해야 하는 점들을 배울 수 있었다. 앞으로 객체지향 설계를 할 때 이번 4장에 나온 내용들을 기반으로 설계를 해나가야겠다.
같이 스터디 진행하는 데보션 영 김경욱님의 링크 참고!!
'Book Review' 카테고리의 다른 글
객체지향의 사실과 오해 Chapter 06 리뷰 (0) | 2022.09.27 |
---|---|
객체지향의 사실과 오해 Chapter 05 리뷰 (0) | 2022.09.20 |
객체지향의 사실과 오해 Chapter 03 리뷰 (0) | 2022.09.07 |
객체지향의 사실과 오해 Chapter 02 리뷰 (0) | 2022.08.31 |
객체지향의 사실과 오해 Chapter 01 리뷰 (0) | 2022.08.22 |