객체지향의 사실과 오해(역할, 책임, 협력 관점에서 본 객체지향) - dnwls16071/Backend_Study_TIL GitHub Wiki
📖 요청(Request)과 응답(Response)으로 구성된 협력(Collaboration)
- 문제 해결에 필요한 지식을 알고 있거나 서비스를 제공해줄 수 있는 사람에게 도움을 요청
- 요청을 받은 사람은 주어진 책임을 다하면서 필요한 서비스나 지식을 제공
- 요청과 응답을 통해 다른 사람과의 협력
📖 역할(Role)과 책임(Responsibility)
- 역할은 어떤 협력에 참여하는 특정한 사람이 협력 안에서 차지하는 책임 혹은 의무를 말한다.
- 특정한 역할은 특정 책임을 가진다.
- Ex1. 손님에게는 커피를 주문할 책임이 있다.
- Ex2. 캐셔에게는 주문 내용을 바리스타에게 전달할 책임과 커피가 준비됐다는 사실을 손님에게 알릴 책임이 있다.
- Ex3. 바리스타는 커피를 제조할 책임이 있다.
- 협력의 핵심은 특정한 책임을 수행하는 역할들 간의 연쇄적인 요청과 응답을 통해 목표를 달성한다.
- 애플리케이션 기능은 더 작은 책임으로 분할되고 그런 책임들은 적절한 역할을 수행할 수 있는 객체에 의해 수행된다.
- 객체는 자신의 책임을 수행하면서 다른 객체에게 도움을 요청하기도 한다.
- 시스템은 역할과 책임을 수행하는 객체로 분할되며 시스템 기능은 객체 간의 연쇄적인 요청과 응답을 통해 구성된 협력으로 구현된다.
📖 협력 속에 사는 객체
- 협력
- 외부의 도움을 무시한 채 모든 것을 스스로 처리하려고 하는 전지전능한 객체는 내부 복잡도의 증가로 인해 자멸한다.
- 객체는 다른 객체의 요청에 응답만 할 뿐이다.
- 자율
- 객체지향은 객체를 지향하는 것이지 클래스를 지향하라는 것이 아니다.
📖 상태와 행동
- 객체의 행동은 상태에 영향을 받는다.
- 객체의 행동으로 상태를 변화시킨다.
📖 식별자
- 동등성(Equality) : 값의 상태가 같으면 두 인스턴스는 동일한 것으로 판단하고 상태가 다르면 두 인스턴스는 다른 것으로 판단한다.
- 동일성(Identical) : 식별자를 기반으로 객체가 같은지를 판단할 수 있는 성질
📖 역할,책임,협력
- 협력은 다수의 요청과 응답으로 구성되며 전체적으로 협력은 다수의 연쇄적인 요청과 응답의 흐름으로 구성된다.
- Ex. 재판 속의 협력
- 누군가 왕에게 재판을 요청함으로써 재판이 시작된다.
- 왕이 하얀 토끼에게 증인을 부를 것을 요청한다.
- 왕의 요청을 받은 토끼는 모자 장수에게 증인석으로 입장할 것을 요청한다.
- 모자 장수 입장은 왕이 토끼에게 요청했던 증인 호출에 대한 응답이기도 하다.
- 왕은 모자 장수에게 증언할 것을 요청한다.
- 모자 장수는 자신이 알고 있는 내용을 증언함으로써 왕의 요청에 응답한다.
- 어떤 객체가 어떤 요청에 대해 대답해주거나 적절한 행동을 할 의무가 있는 경우 해당 객체가 책임을 가진다고 말한다.
- 협력 안에서 객체는 다른 객체로부터 요청이 전송됐을 경우에만 자신에게 주어진 책임을 수행한다.
- 두 객체 간의 협력은 메시지를 통해 이루어진다.
- 메시지를 전송함으로써 협력을 요청하는 객체를 송신자라 하고 메시지를 받아 요청을 처리하는 객체를 수신자라 한다.
- 메시지는 협력을 위해 한 객체가 다른 객체에 접근할 수 있는 유일한 수단이다.
- 역할은 재사용성을 위해 필요한 수단이다. 역할을 사용하면 협력을 추상화함으로써 단순화할 수 있다.
- Ex. 재판 속의 협력
- 왕은 판사라고 부르고 모자 장수를 증인이라고 부르는 이유는 역할의 재사용성을 강조하기 위함이다.
- 누군가 (판사)에게 재판을 요청함으로써 재판이 시작된다.
- (판사)이 (증인)에게 증인을 부를 것을 요청한다.
- (판사)의 요청을 받은 토끼는 (증인)에게 증인석으로 입장할 것을 요청한다.
- (증인) 입장은 (판사)이 토끼에게 요청했던 증인 호출에 대한 응답이기도 하다.
- (판사)은 (증인)에게 증언할 것을 요청한다.
- (증인)는 자신이 알고 있는 내용을 증언함으로써 (판사)의 요청에 응답한다.
- 역할은 협력 안에서 구체적인 객체로 대체될 수 있는 추상적인 협력자이다.
- 객체가 역할을 대체하기 위해서는 행동의 호환성이 이루어져야 한다는 점에 주목해야한다.
📖 객체의 모양을 결정하는 협력
- 협력을 설계한다 == 설계에 참여하는 객체들이 주고받을 요청과 응답의 흐름을 결정한다.
📖 객체지향 설계 기법
- 책임-주도 설계 방법은 협력에 필요한 책임들을 식별하고 적합한 객체에게 책임을 할당하는 방식으로 애플리케이션을 설계한다.
- 디자인 패턴은 전문가들이 반복적으로 사용하는 해결 방법을 정의해 놓은 설계 템플릿의 모음이다.
- 테스트-주도 개발 방법은 테스트를 먼저 작성하고 테스트를 통과하는 구체적인 코드를 추가하면서 애플리케이션을 완성해가는 방식이다.
📖 책임과 메시지
- 자율적인 책임 - 타율에 의한 책임 수행보다 객체가 책임을 자율적으로 수행하도록 해야 한다.
- 추상적인 책임을 피해라 - 협력에 참여한 의도가 모호해지기 때문에 최소한 협력 의도를 뚜렷하게 표현할 수 있어야 한다.
- 어떻게가 아니라 무엇을 - 자율적인 책임의 특징은 객체가 어떻게 해야하는가가 아니라 객체가 무엇을 해야하는가를 설명할 수 있어야 한다.
- 하나의 객체는 메시지를 전송함으로써 다른 객체에 접근한다.
- 객체지향 세계에서 객체들이 서로 협력하기 위해 사용할 수 있는 유일한 방법은 메시지를 전송하는 것이다.
- 객체지향 애플리케이션의 중심 사상은 연쇄적으로 메시지를 전송하고 수신하는 객체들 사이의 협력 관계를 기반으로 사용자에게 유용한 기능을 제공한다.
📖 What/Who 사이클
- What : 어떤 행위를 수행할 것인지를 결정
- Who : 누가 그 행위를 수행할 것인지를 결정
- 객체가 어떤 메시지를 수신하고 처리할 수 있냐가 객체의 책임을 결정한다.
📖 묻지 말고 시켜라
- 객체를 자율적으로 만들고 캡슐화를 보장하며 결합도를 낮게 유지시킨다.
- 객체가 다른 객체의 상태를 묻지 말아야 한다.
- 객체가 다른 객체의 상태를 묻는다는 것은 메시지를 전송하기 이전에 객체가 가져야 하는 상태에 관해 너무 많이 고민하고 있었다는 증거이다. 다른 객체의 상태까지 신경쓰기보다 필요한 메시지를 전송하기만 하고 메시지를 수신하는 객체가 스스로 메시지 처리 방법을 결정하도록 해야 한다.
📖 메시지를 믿어라
- 메시지를 전송하는 객체 관점에서 자신이 전송하는 메시지를 수신할 수만 있다면 협력하는 객체의 종류가 무엇인지는 중요하지 않다.
- 내가 커피를 시켰는데 누가 주문을 받던지 상관없다.
- 중요한 것은 메시지를 수신한 객체가 메시지 의미를 이해하고 메시지를 전송한 객체가 의도한 대로 요청을 처리할 수 있는지가 중요하다.
- 메시지를 이해할 수 있다면 다양한 타입의 객체로 협력 대상을 자유롭게 교체하여 재사용성을 높일 수 있기 때문에 설계가 유연해진다.
📖 인터페이스와 구현의 분리
- 좀 더 추상적인 인터페이스
- 세부 사항을 제거하고 메시지 의도를 표현하기 위해 사용한 기법은 추상화다.
- 너무 구체적인 인터페이스보다는 추상적인 인터페이스를 설계하는 것이 좋다.
- Ex❌. 목격했던 장면을 떠올려라, 떠오르는 기억을 시간 순서대로 재구성해라, 말로 간결하게 표현하라 (X)
- Ex⭕. 증언하라 (O)
- 최소 인터페이스
- 외부에서 사용할 필요가 없는 인터페이스는 최대한 노출하지 말라.
- 다시 말해 모든 것을 추상화해 인터페이스를 놓고 개발하는 것이 관리 포인트를 늘릴 수 있기 때문에 상황에 맞는 설계를 통해 해결해나가는 것이 중요하다는 것이다.
- 구현
- 객체는 상태를 가진다. 상태는 어떤 식으로든 객체에 포함되겠지만 외부에 노출되는 공용 인터페이스의 일부는 아니다. 따라서 상태를 어떻게 표현할 것인가는 객체의 구현에 해당한다.
- 객체는 행동을 가진다. 행동은 메시지를 수신했을 때만 실행되는 일종의 메시지 처리 방법으로 메서드라고 한다. 메서드를 구성하는 코드 자체에는 객체 외부에 노출되는 공용 인터페이스 일부는 아니기 때문에 객체의 구현 부분에 포함된다.
- 인터페이스와 구현의 분리 원칙
- 훌륭한 객체란 구현을 모른 채 인터페이스만 알면 쉽게 상호작용할 수 있는 객체를 의미한다.
- 구현을 변경할 때 외부에 대한 파급효과를 최소화하기 위해서는 외부 객체는 공용 인터페이스에만 의존해야 하고 구현 세부 사항에 대해서는 직접적으로 의존해서는 안 된다.
- Ex. 운전자가 자동차 엑셀을 밞으면 어떤 원리에 의해서 가속이 이루어지는지 알 필요가 없이 엑셀만 밞아도 앞으로 가듯이 운전자는 원리를 몰라도 된다.
📖 캡슐화
- 객체의 자율성을 보존하기 위해 구현을 외부로부터 감추는 것을 캡슐화라고 한다.
- 객체는 상태와 행의를 함께 캡슐화함으로써 충분히 협력적이고 만족스러울 정도로 자율적인 존재가 될 수 있다.
[상태와 행위의 캡슐화]
- 객체는 상태와 행위의 조합이다.
- 객체는 상태와 행위를 한데 묶은 후 외부에서 반드시 접근해야만 하는 행위만 골라 공용 인터페이스를 통해 노출시켜야 한다.
[사적인 비밀의 캡슐화]
- 외부에서 객체와 의사소통할 수 있는 고정된 경로를 공용 인터페이스라고 한다.
- 변경이 빈번하게 일어나는 불안정한 비밀을 안정적인 인터페이스 뒤로 숨길 수 있다.(정보 은닉)
📖 예제 : 커피 전문점 도메인
* 예제의 목적은 커피 전문점에서 커피를 주문하는 과정을 객체들의 협력 관계로 구현하는 것에 있다.
* 커피 전문점에서는 아메리카노, 카푸치노, 카라멜 마키아또, 에스프레소의 네 가지 커피를 판매하고 있다.
* 손님이 테이블에 앉아 메뉴판을 잠시 훑어본 후 커피를 주문한다. 이제 주문받은 커피를 제조하는 것은 바리스타의 책임이다.
- 주어진 커피 전문점 도메인 예제에서 객체지향 관점에서 설계를 해본다면 아래와 같다고 생각한다.
- 손님 : 커피를 주문한다, 커피를 메뉴판에서 수령한다, 커피를 수령한다
- 바리스타 : 커피를 제조한다
- 메뉴판 : 커피 메뉴들이 존재한다