메시지와 인터페이스 내용이다.
자세한 내용이 궁금하면 오브젝트를 펼쳐보는 걸 추천드립니다.📖
이번 장을 시작하면서
OOP의 흔한 오해는 애플리케이션의 클래스의 집합이라는 생각이다. 클래스는 중요하지만 훌륭한 객체지향 코드를 얻기 위해서는 객체를 지향해야 한다. 협력안에서 객체가 수행하는 책임에 초점을 맞춰야한다. 여기서 중요한 건 책임은 객체가 수신할 메시지의 기반이 되는 것이다.
애플리케이션은 클래스로 구성되지만 메시지를 통해 정의된다는 사실을 기억하라 [Metz12]
협력과 메시지
클라이언트-서버 모델
협력은 어떤 객체가 다른 객체에게 무언가를 요청할 때 시작된다
두 객체 사이의 혀벽 관계를 설명하기 위한 전통적인 메타포는 클라이언트-서버 모델이다. 협력안에서 메시지를 전송하는 객체를 클라이언트, 메시지를 수신하는 객체를 서버라고 한다.
메시지와 메시지 전송
메시지는 오퍼레이션명(operation name)과 인자(argument)로 구성되며, 메시지 전송은 여기에 메시지 수신자를 추가한 것이다.
수신자 오퍼레이션명 인자
discountPolicy.calculateDiscountAmount(screening)
메시지와 메서드
메시지를 수신했을 때 실행되는 함수 또는 프로시저를 메서드라고 한다. 여기서 중요한 것은 코드 상에서 동일한 이름의 변수에게 메시지를 보내도 타입에 따라 실행되는 메서드가 달라질 수 있다는 것이다. 즉, 컴파일 시점과 실행 시점의 의미가 달라질 수 있다.
* 실행 시점에 바인딩하는 매커니즘이 결합도를 낮추고 유연성이 있는 설계로 만들어준다.
퍼블릭 인터페이스와 오퍼레이션
객체는 내외부를 구부하는 경계를 가진다. 소통을 위해 외부에 공개하는 메시지의 집합을 퍼블릭 인터페이스라 부른다.
퍼블릭 인터페이스에 포함된 메시지를 오퍼레이션(operation)이라 한다. 오퍼레이션은 어떤 행동에 대한 추상화다.
시그니처
오퍼레이션의 이름과 파라미터 목록을 합쳐 시그니쳐(signature)라 한다.
정리하자면
- 메시지 : 객체가 다른 객체와 협력하기 위한 의사소통 메커니즘
- 오퍼레이션 : 객체가 다른 객체에게 제공하는 추상적인 서비스
- 메서드 : 메시지의 응답을 위해 실행되는 코드 블록
- 퍼블릭 인터페이스 : 협력에 참여하기 위한 외부에 수신할 메시지의 묶음
- 시그니처 : 오퍼레이션이나 메서드의 명세
인터페이스와 설계 품질
디미터(Law of Demeter) 법칙
객체의 내부 구조에 강하게 결합되지 않도록 협력 경로를 제한하라는 것이 디미터의 법칙이다.
"낯선자에게 말하지 말라"
"인접한 이웃하고만 말하라"
"오직 하나의 도트만 사용하라"
한마디로 요악하자면 객체안의 객체안의 객체에게 접근하지 말라는 뜻이다.
public class Theater {
private TicketSeller ticketSeller;
...
public void enter(Audience audience) {
if (audience.getBag().hasInvitation()) {
// 객체안의 객체안의 객체에 접근한다.
Ticket ticket = ticketSeller.getTicketOffice().getTicket();
audience.getBag().setTicket(ticket);
} else {
...
}
}
}
초반 예제인 Theater 코드다. ticketSeller.getTicketOffice().getTicket() 같은 형태가 전형적인 디미터의 법칙 위반 사례다.
* 디미터 법칙은 캡슐화를 다른 관점에서 표현한 것이다.
묻지말고 시켜라
절차적인 코드는 정보를 얻은 후에 결정한다. 객체지향 코드는 객체에게 그것을 하도록 시킨다.
상태를 묻지 말고 행동 요청으로 대체하는게 인터페이스 품질을 향상시키는 좋은 습관이다.
의도를 드러내는 인터페이스
켄트 벡의 메서드 명명하는 두 가지 방법
- 메서드가 어떤 작업을 수행하는 지 이름 짓는다.
- '어떻게'가 아니라 '무엇'을 하는지 드러내는 것이다.
(* 주의점은 내부 구현 방법을 이름에 드러내면 안된다.)
원칙의 함정
설계는 트레이드오프의 산물이다. 반드시 원칙을 준수하기 보다는 상황에 따라 원칙이 부적합 경우엔 무시해야한다.
디미터의 법칙은 하나의 도트(.)를 강제하는 규칙이 아니다.
디미터의 법칙은 결합도와 관련된 것이다. 디미터의 법칙을 위반하는 것은 객체의 내부 구조가 노출되는 경우로 한정된다.
결합도와 응집도의 충돌
항상 객체에게 시키는 것이 가능하지는 않다. 가끔 상태를 묻는 외엔 다른 방법이 없는 경우가 존재한다. 컬렉션에 포함된 객체들이 주된 사례다.
명령-쿼리 분리(Command-Query Separation) 원칙
명령-쿼리 분리 원칙은 퍼블릭 인터페이스에 오퍼레이션 정의에 가이드를 제공한다. 먼저 프로시저와 함수의 차이를 알아보자.
- 프로시저 : 부수효과를 발생하지만 값을 반환하지 않는다.
- 함수 : 값을 반환하지만 부수효과는 없다.
명령과 쿼리는 프로시저와 함수의 또 다른 의미이다. 명령은 객체를 수정하는 오퍼레이션이고, 쿼리는 객체의 정보를 반환하는 오퍼레이션이다.
명령-쿼리 분리 원칙은 오퍼레이션이 객체를 수정하면서 정보를 반환하는 작업을 동시에 하지 말라 는 원칙이다.
한마디로 "질문이 답변을 수정해서는 안된다"는 것이다.
명령-쿼리 분리와 참조 투명성(referential transparency)
명령과 쿼리를 분리하면 참조 투명성을 어느 정도 누릴 수 있다.
참조 투명성이란 "어떤 표현식 e가 있을 때 e의 값으로 e가 나타나는 모든 위치를 교체하더라도 결과가 달라지지 않는 특성"을 의미하며 참조 투명성을 만족하는 식은 두 가지의 장점을 제공 한다.
- 모든 함수를 이미 알고 있는 하나의 결괏값으로 대체할 수 있기 때문에 식을 쉽게 계산할 수 있다.
- 모든 곳에서 함수의 결괏값이 동일하기 때문에 식의 순서를 변경하더라도 각 식의 결과는 달라지지 않는다.
정리하자면
- 디미터 법칙 : 협력이라는 문맥안에서 객체보다 메시지를 먼저 결정하면 두 객체 사이의 구조적인 결합도를 낮출 수 있다
- 묻지 말고 시켜라 : 메시지를 먼저 선택하면 협력을 구조화할 수 있다.
- 의도를 드러내는 인터페이스 : 클라이언트의 관점에서 메시지의 이름을 정하면, 클라이언트가 무엇을 원하는지 의도가 드러난다.
- 명령-쿼리 분리 원칙 : 예측 가능한 협력을 만들기 위해 명령과 쿼리를 분리하게 된다.
'서적 > 오브젝트: 코드로 이해하는 객체지향 설계' 카테고리의 다른 글
오브젝트 08_ 의존성 관리하기 (0) | 2021.06.09 |
---|---|
오브젝트 07_ 객체 분해 (0) | 2021.06.09 |
오브젝트 05_ 책임 할당하기 (0) | 2021.06.09 |
오브젝트 04_ 설계 품질과 트레이드 오프 (0) | 2021.06.08 |
오브젝트 03_ 역할, 책임, 협력 (0) | 2021.06.08 |