Skip to content
On this page

오트젝트 06 메시지와 인터페이스

[오브젝트: 코드로 이해하는 객체지향 설계] 를 읽고 정리한 내용입니다.

객체지향 프로그래밍에 대한 가장 흔한 오해는 애플리케이션이 클래스의 집합으로 구성된다는 것이다

  • 클래스가 아니더라도, 객체가 수행하는 책임에 초점을 맞춰 객체간에 메시지를 송수신하는 방식으로 코드를 작성하는 것이 객체지향 프로그래밍인듯 하다.

협력과 메시지

클라이언트-서버모델

두 객체 사이의 협력 관계를 설명하기 위해 사용하는 전통적인 메타포는 클라이언트-서버(Client-Server) 모델이다. 협력 안에서 메시지를 전송하는 객체를 클라이언트, 메시지를 수신하는 객체를 서버라고 부른다.

두 객체 사이의 협력을 가능하게 해주는 매개체는 바로 메시지이다.

메시지와 메시지 전송

메시지(message)는 객체들이 협력하기 위해 사용할 수 있는 유일한 의사소통 수단이다. 한 객체가 다른 객체에게 도움을 요청하는 것을 메시지 전송(message sending) 또는 메시지 패싱(message passing)이라고 부른다. 이때 메시지를 전송하는 객체를 메시지 전송자(message sender)라고 부르고 메시지를 수신하는 객체를 메시지 수신자(message receiver)라고 부른다. 클라이언트-서버 모델 관점에서는 메시지 전송자는 클라이언트, 메시지 수신자는 서버라고 부르기도 한다. 메시지는 오퍼레이션명(operation name)과 인자(argument)로 구성되며 메시지 전송은 여기에 메시지 수신자를 추가한 것이다. 따라서 메시지 전송은 메시지 수신자, 오퍼레이션명, 인자의 조합이다

퍼블릭 인터페이스와 오퍼레이션

프로그래밍 언어의 관점에서 퍼블릭 인터페이스에 포함된 메시지를 오퍼레이션(operation)이라고 부른다.

시그니쳐

오퍼레이션(또는 메서드)의 이름과 파라미터 목록을 합쳐 시그니처(signature)라고 부른다

인터페이스와 설계 품질

디미터 법칙을 간단하게 요약하면 객체의 내부 구조에 강하게 결합되지 않도록 협력 경로를 제한하라는 것이다. 디미터 법칙은 낯선 자에게 말하지 말라(dont talk to strangers) 또는 오직 인접한 이웃하고만 말하라(only talk to your immediate neighbors)로 요약할 수 있다.

  • 되도록이면 하나의 도트만 사용하되, 필요한 부분에서는 여러개의 도트를 사용할 수도 있다.
  • 기차충돌: 여러개의 도트를 사용해 연쇄적으로 메소드를 호출하고 있는 코드.

묻지 말고 시켜라

ReservationAgency는 Screening 내부의 Movie에 접근하는 대신 Screening에게 직접 요금을 계산하도록 요청했다. 요금을 계산하는 데 필요한 정보를 잘 알고 있는 Screening에게 요금을 계산할 책임을 할당한 것이다. ...

묻지 말고 시켜라(Tell, Dont Ask)는 이런 스타일의 메시지 작성을 장려하는 원칙을 가리키는 용어다.

상태를 묻는 오퍼레이션을 행동을 요청하는 오퍼레이션으로 대체함으로써 인터페이스를 향상시켜라. 협력을 설계하고 객체가 수신할 메시지를 결정하는 매 순간 묻지 말고 시켜라 원칙과 디미터 법칙을 머릿속에 떠올리는 것은 퍼블릭 인터페이스의 품질을 향상시킬 수 있는 좋은 습관이다.

의도를 드러내는 인터페이스

메서드 이름을 변경한다는 것은 메시지를 전송하는 클라이언트의 코드도 함께 변경해야 한다는 것을 의미한다. 따라서 책임을 수행하는 방법을 드러내는 메서드를 사용한 설계는 변경에 취약할 수밖에 없다.

메서드의 이름을 짓는 두 번째 방법은 어떻게가 아니라 무엇을 하는지를 드러내는 것이다

근본적으로 디미터 법칙을 위반하는 설계는 인터페이스와 구현의 분리 원칙을 위반한다. 기억해야 할 점은 객체의 내부 구조는 구현에 해당한다는 것이다.

오퍼레이션의 이름은 협력이라는 문맥을 반영해야 한다. 오퍼레이션은 클라이언트가 객체에게 무엇을 원하는지를 표현해야 한다. 다시 말해 객체 자신이 아닌 클라이언트의 의도를 표현하는 이름을 가져야 한다. sellTo, buy, hold라는 이름은 클라이언트가 객체에게 무엇을 원하는지를 명확하게 표현한다. setTicket은 그렇지 않다.

원칙의 함정

앞에서 설명한 것처럼 디미터 법칙은 오직 하나의 도트만을 사용하라라는 말로 요약되기도 한다. 따라서 대부분의 사람들은 자바 8의 IntStream을 사용한 아래의 코드가 기차 충돌을 초래하기 때문에 디미터 법칙을 위반한다고 생각할 것이다.

모든 상황에서 맹목적으로 위임 메서드를 추가하면 같은 퍼블릭 인터페이스 안에 어울리지 않는 오퍼레이션들이 공존하게 된다. 결과적으로 객체는 상관 없는 책임들을 한꺼번에 떠안게 되기 때문에 결과적으로 응집도가 낮아진다.

  • 필요한 곳과 아닌 곳을 구분할 것

명령-쿼리 분리 원칙

명령-쿼리 분리 원칙은 퍼블릭 인터페이스에 오퍼레이션을 정의할 때 참고할 수 있는 지침을 제공한다.

어떤 절차를 묶어 호출 가능하도록 이름을 부여한 기능 모듈을 루틴(routine)이라고 부른다. 루틴은 다시 프로시저(procedure)와 함수(function)로 구분할 수 있다

명령과 쿼리를 분리하기 위해서는 다음의 두 가지 규칙을 준수해야 한다.

객체의 상태를 변경하는 명령은 반환값을 가질 수 없다. 객체의 정보를 반환하는 쿼리는 상태를 변경할 수 없다.

명령과 쿼리를 분리함으로써 명령형 언어의 틀 안에서 참조 투명성(referential transparency)의 장점을 제한적이나마 누릴 수 있게 된다.?참조 투명성이라는 특성을 잘 활용하면?버그가 적고,?디버깅이 용이하며, 쿼리의 순서에 따라 실행 결과가 변하지 않는 코드를 작성할 수 있다.

참조 투명성이란 어떤 표현식e가 있을 때 모든 e를 e의 값으로 바꾸더라도 결과가 달라지지 않는 특성이라는 점을 기억하라.

  • 약간 함수형 프로그래밍과도 연관이 있는 것 같다.

컴퓨터의 세계와 수학의 세계를 나누는 가장 큰 특징은 부수효과(side effect)의 존재 유무다.?프로그램에서 부수효과를 발생시키는 두 가지 대표적인 문법은 대입문과 (원래는 프로시저라고 불려야 올바른) 함수다. 수학의 경우 x의 값을 초기화한 후에는 값을 변경하는 것이 불가능하지만 프로그램에서는 대입문을 이용해 다른 값으로 변경하는 것이 가능하다. 함수는 내부에 부수효과를 포함할 경우 동일한 인자를 전달하더라도 부수효과에 의해 그 결괏값이 매번 달라질 수 있다.

LINKS TO THIS PAGE

Edit this page
최근 수정 시각 11/22/2022