오트젝트 03 역할, 책임, 협력
[오브젝트: 코드로 이해하는 객체지향 설계] 를 읽고 정리한 내용입니다.
역할, 책임, 협력
위 세 단어가 객체지향 패러다임의 관점에서의 핵심이다. 클래스, 상속, 지연바인딩도 중요하지만 이들은 구현 측면에 치우쳐져있다.
협력
여기서 중요한 것은 다양한 객체들이 영화 예매라는 기능을 구현하기 위해 메시지를 주고 받으면서 상호작용한다는 점이다. 이처럼 객체들이 애플리케이션의 기능을 구현하기 위해 수행하는 상호작용을 협력이라고 한다.
객체는 고립된 존재가 아니라 시스템의 기능이라는 더 큰 목표를 달성하기 위해 다른 객체와 협력하는 사회적인 존재다.
- 협력할 필요없는 경우 객체로 만들 필요가 없다.
메시지 전송(message sending)은 객체 사이의 협력을 위해 사용할 수 있는 유일한 커뮤니케이션 수단이다.
객체지향은 객체를 중심에 놓는 프로그래밍 패러다임이다. 여기서 객체란 상태와 행동을 함께 캡슐화하는 실행 단위다
객체의 행동을 결정하는 것이 협력이라면 객체의 상태를 결정하는 것은 행동이다. 객체의 상태는 그 객체가 행동을 수행하는 데 필요한 정보가 무엇인지로 결정된다. 객체는 자신의 상태를 스스로 결정하고 관리하는 자율적인 존재이기 때문에 객체가 수행하는 행동에 필요한 상태도 함께 가지고 있어야 한다.
- 이 부분이 프론트엔드에 적용하기 가장 힘든 부분인거 같다.
책임
협력에 참여하기 위해 객체가 수행하는 행동을 책임이라고 부른다.
즉, 객체의 책임은 객체가 무엇을 알고 있는가와 무엇을 할 수 있는가로 구성된다. 크레이그 라만(Craig Larman)은 이러한 분류 체계에 따라 객체의 책임을 크게 하는 것(doing)과 아는 것(knowing)의 두 가지 범주로 나누어 세분화하고 있다.
- 하는 것
Movie
가 예매 가격을 계산할 책임을 지는 것
- 아는 것
Screening
이 자신이 상영할 영화를 알고 있어야하는 것
여기서 중요한 사실은 책임의 관점에서 아는 것과 하는 것이 밀접하게 연관돼 있다는 점이다. 객체는 자신이 맡은 책임을 수행하는 데 필요한 정보를 알고 있을 책임이 있다. 또한 객체는 자신이 할 수 없는 작업을 도와줄 객체를 알고 있을 책임이 있다
자율적인 객체를 만드는 가장 기본적인 방법은 책임을 수행하는 데 필요한 정보를 가장 잘 알고 있는 전문가에게 그 책임을 할당하는 것이다. 이를 책임 할당을 위한 INFORMATION EXPERT(정보 전문가) 패턴이라고 부른다.
- 여기서 정보 전문가는 책임해결을 위헤 필요한 정보를 가지고 있는 객체
객체지향 설계는 시스템의 책임을 완료하는 데 필요한 더 작은 책임을 찾아내고 이를 객체들에게 할당하는 반복적인 과정을 통해 모양을 갖춰간다.
- 객체지향 설계는 프랙탈적인 성향을 띈다.
메시지를 선택했으면 메시지를 처리할 적절한 객체를 선택해야 한다.
어떤 경우에는 응집도와 결합도의 관점에서 정보 전문가가 아닌 다른 객체에게 책임을 할당하는 것이 더 적절한 경우도 있다. 하지만 기본적인 전략은 책임을 수행할 정보 전문가를 찾는 것이다. 정보 전문가에게 책임을 할당하는 것만으로도 상태와 행동을 함께 가지는 자율적인 객체를 만들 가능성이 높아지기 때문이다.
책임을 찾고 책임을 수행할 적절한 객체를 찾아 책임을 할당하는 방식으로 협력을 설계하는 방법을 책임 주도 설계라고 부른다.
다시 말해 객체가 메시지를 선택하는 것이 아니라 메시지가 객체를 선택하게 했다
- 여러번 나오지만 메시지를 중점으로 생각하는것이 중요하다.
객체지향 패러다임에 갓 입문한 사람들이 가장 쉽게 빠지는 실수는 객체의 행동이 아니라 상태에 초점을 맞추는 것이다. 초보자들은 먼저 객체에 필요한 상태가 무엇인지를 결정하고, 그 후에 상태에 필요한 행동을 결정한다. 이런 방식은 객체의 내부 구현이 객체의 퍼블릭 인터페이스에 노출되도록 만들기 때문에 캡슐화를 저해한다.
역할
이처럼 객체가 어떤 특정한 협력 안에서 수행하는 책임의 집합을 역할이라고 부른다.
- 가장이라는 역할은 가족을 보살피고, 의식주를 책임져야한다. 가장은 아버지가 아니더라도 수행할 수 있는 역할이다.
역할이라는 개념을 고려하지 않고 객체에게 책임을 할당한다고 가정해보자
연극 안에서 배역을 연기하는 배우라는 은유는 협력 안에서 역할을 수행하는 객체라는 관점이 가진 입체적인 측면들을 훌륭하게 담아낸다. 협력은 연극과 동일하고 코드는 극본과 동일하다. 배우는 연극이 상영될 때 배역이라는 특정한 역할을 연기한다. 객체는 협력이라는 실행 문맥 안에서 특정한 역할을 수행한다. 연극 배우는 연극이 끝나면 자신의 배역을 잊고 원래의 자기 자신을 되찾는다. 객체는 협력이 끝나고 협력에서의 역할을 잊고 원래의 객체로 돌아올 수 있다.
- 가장이 해야할 일을 가족의 구성원들이 흩어져서 맡게된다고 생각해보자.
순수하게 책임의 관점에서 두 협력을 바라보면 AmountDiscountPolicy와 PercentDiscountPolicy 모두 할인 요금 계산이라는 동일한 책임을 수행한다는 사실을 알 수 있다. 따라서 객체라는 존재를 지우고 할인 요금을 계산하라라는 메시지에 응답할 수 있는 대표자를 생각한다면 두 협력을 하나로 통합할 수 있을 것이다. 이 대표자를 협력 안에서 두 종류의 객체를 교대로 바꿔 끼울 수 있는 일종의 슬롯으로 생각할 수 있다. 이 슬롯이 바로 역할이다.
- 슈퍼페미콤에 끼우던 슬롯을 생각해보자
인터페이스 업캐스팅, 다형성, 늦은 바인딩, 상속, 컴파일 시간 의존성과 실행 시간 의존성의 차이와 같은 다양한 기술적 메커니즘이 숨겨져 있다. 하지만 여기서 중요한 것은 이러한 기술적 메커니즘들이 모여 유연하고 재사용 가능한 협력을 만들 수 있는 기반을 제공한다는 것이다.
협력에 참여하는 후보가 여러 종류의 객체에 의해 수행될 필요가 있다면 그 후보는 역할이 되지만 단지 한 종류의 객체만이 협력에 참여할 필요가 있다면 후보는 객체가 된다.
- 솔직히 잘 이해가 안되는 부분이다..
처음에 특정 시나리오에 대한 협력을 구상할 때는 아마도 도메인 모델에 있는 개념들을 후보로 선택해 직접 책임을 할당할 것이다. 다양한 시나리오를 설계로 옮기면서 협력을 지속적으로 정제하다 보면 두 협력이 거의 유사한 구조를 보인다는 것을 발견하게 될 것이다. 이 경우 두 협력을 하나로 합치면서 두 객체를 포괄할 수 있는 역할을 고려해서 객체를 역할로 대체할 수 있다.
첫 번째 장점은 추상화 계층만을 이용하면 중요한 정책을 상위 수준에서 단순화할 수 있다는 것이다. 두 번째 장점은 설계가 좀 더 유연해진다는 것이다.
- 상위수준에서 단순화되면 사용하는 입장에서 더 편하다. == 적은 정보만 알면된다.
- 설계가 유연해지면 서비스를 유지보수하기 편해진다.
따라서 객체는 다양한 역할을 가질 수 있다. 객체는 여러 역할을 가질 수 있지만 특정한 협력 안에서는 일시적으로 오직 하나의 역할만이 보여진다는 점에 주의하라. 이것은 배우가 하나의 연극에서 오직 하나의 배역을 연기하는 것과 동일하다. 객체가 다른 협력에 참여할 때는 이전의 역할은 잊혀지고 해당 협력에서 바라보는 역할의 측면에서 보여질 것이다