메시지와 인터페이스
책임 중심 설계를 위한 메시지 & 인터페이스 정의하기
객체지향 애플리케이션의 가장 중요한 재료는 클래스가 아니라 객체들이 주고 받는 메시지이다.
객체가 수신하는 메시지들이 객체의 퍼블릭 인터페이스를 구성한다.
협력과 메시지
클라이언트 - 서버(Client-Server) 모델
두 객체 사이의 협력 관계를 설명하기 위해 사용하는 전통적인 메타포는 클라이언트-서버(Client-Server) 모델이다.
협력은 어떤 객체가 다른 객체에게 무언가를 요청할 때 시작된다.
협력 안에서 메시지를 전송하는 객체를 클라이언트, 메시지를 수신하는 객체를 서버라 부른다.
메시지(Message)와 메시지 전송(Message Sender)
메시지란 객체들이 렵력하기 위해 사용할 수 있는 유일한 의사소통 수단이다.
한 객체가 다른 객체에게 도움을 요청하는 것을 메시지 전송 도는
메시지 패싱(message passing)
이라 부른다.메시지를 전송하는 객체를
메시지 전송자(message sender)
라고 부르고, 메시지를 수신하는 객체를 메시지 수신자(message receiver)라고 부른다.메시지(Message)
오퍼레이션명과 인자로 구성되며, 메시지 전송은 여기에 메시지 수신자를 추가한 것이다.
메시지 전송(Message Send)
메시지 수신자, 오퍼레이션명, 인자의 조합이다.
메시지(Message)와 메서드(Method)
메시지를 수신했을 때 실제로 실행되는 함수 또는 프로시저를 메서드
코드 상에서 동일한 이름의 변수에게 동일한 메시지를 전송하더라도 객체의 타입에 따라 실행되는 메서드가 달라질 수 있다.
메시지
와메서드
의 구분은메시지 전송자
와메시지 수신자
가 느슨하게 결합메시지는 객체가 메시지와 메서드라는 두 가지 서로 다른 개념을 실행 시점에 연결해야 하기 때문에 컴파일 시점과 실행 시점의 의미가 달라질 수 있다.
퍼블릭 인터페이스(Public Interface)와 오퍼레이션(Operation)
객체가 의사소통을 위해 외부에 공개하는
메시지의 집합
을퍼블릭 인터페이스
라고 부른다.프로그래밍 언어의 관점에서
퍼블릭 인터페이스에 포함된 메시지
를오퍼레이션
이라고 부른다.메서드는 오퍼레이션에 대한 구현이다.
메서드는 오퍼레이션과 연관된 알고리즘 또는 절차를 명시한다.
시그니처(Signature)
오퍼레이션의 이름
과파라미터 목록
을 합쳐시그니처
라고 부른다.오퍼레이션은 실행 코드 없이 시그니처만을 정의한 것이다.
메서드는 이 시그니처에 구현을 더한 것이다.
용어 정리
메시지
객체가 다른 객체와 협력하기 위해 사용하는 의사소통 메커니즘
일반적으로 객체의 오퍼레이션이 실행되도록 요청하는 것을
메시지 전송
이라 부른다.
오퍼레이션
객체가 다른 객체에게 제공하는 추상적인 서비스
오퍼레이션은 메시지를 수신하는 객체의 인터페이스를 강조한다.
메시지 수신이란 메시지에 대응되는 객체의 오퍼레이션을 호출하는 것을 의미한다.
메서드
메시지에 응답하기 위해 실행되는 코드 블록을 메서드라고 부른다.
메서드는 오퍼레이션의 구현이다.
동일한 오퍼레이션이라고 해도 메서드는 다를 수 있다.
오퍼레이션과 메서드의 구분은 다형성의 개념과 연결된다.
퍼블릭 인터페이스
객체가 협력에 참여하기 위해 외부에서 수신할 수 있는 메시지의 묶음.
클래스의 퍼블릭 메서드들의 집합이나 메시지의 집합을 가리키는데 사용된다.
객체를 설계할 때 가장 중요한 것은 훌륭한 퍼블릭 인터페이스를 설계하는 것이다.
시그니처
시그니처는 오퍼레이션이나 메서드의 명세를 나타낸 것으로, 이름과 인자의 목록을 포함한다.
대부분의 언어는 시그니처의 일부로 반환 타입을 포함하지 않지만 반환 타입을 시그니처의 일부로 포함하는 언어도 존재한다.
인터페이스와 설계 품질
퍼블릭 인터페이스의 품질에 영향을 미치는 조건
디미터 법칙
묻지말고 시켜라
의도를 드러내는 인터페이스
명령-쿼리 분리
디미터 법칙(Law of Demeter)
협력하는 객체의 내부 구조에 대한 결합으로 발생하는 설계 문제를 해결하기 위해 제안된 원칙
객체의 내부 구조를 강하게 결합되지 않도록 협력 경로를 제한하라는 것
오직 하나의 도트만 사용하기
이를 통해 결합도를 효과적으로 낮출 수 있다.
디미터 법칙과 캡슐화
디미터 법칙은 캡슐화를 다른 관점에서 표현한 것
디미터 법칙이 가치 있는 이유는 클래스를 캡슐화하기 위해 따라야 하는 구체적인 지침을 제공하기 때문이다.
캡슐화 원칙이 클래스 내부의 구현을 감춰야 한다는 사실을 강조한다면 디미터 법칙은 협력하는 클래스의 캡슐화를 지키기 위해 접근해야 하는 요소를 제한한다.
묻지 말고 시켜라
디미터의 법칙
은 훌륭한 메시지는 객체의 상태에 관해 묻지 말고 원하는 것을 시켜야 한다는 사실을 강조한다.메시지 전송자
는메시지 수신자
의 상태를 기반으로 결정을 내린 후 메시지 수신자의 상태를 바꿔서는 안된다.상태를 묻는 오퍼레이션을 행동을 요청하는 오퍼레이션으로 대체함으로써 인터페이스를 향상 시켜라
의도를 드러내는 인터페이스
메서드를 명명하는 두 가지 방법
메서드가 작업을 어떻게 수행하는 지를 나타내도록 이름 짓는 것
메서드에 대해 제대로 커뮤니케이션 하지 못한다는 문제점, 내부 구현을 정확하게 이해해야한다는 문제점
메서드 수준에서 캡슐화를 위반한다는 문제점, 책임을 수행하는 방법을 드러내는 메서드를 사용한 설계는 변경에 취약할 수 밖에 없다.
어떻게가 아니라 무엇을 하는지를 드러내는 것
객체가 협력 안에서 수행해야 하는 책임에 관해 고민, 클라이언트의 의도를 담을 수 있도록 해야한다.
메서드가 어떻게 수행하느냐가 아니라 무엇을 하느냐에 초점을 맞추면 클라이언트의 관점에서 동일한 작업을 수행하는 메서드들을 하나의 타입 계층으로 묶을 수 있는 가능성이 커진다.
무엇을 하느냐에 따라 메서드의 이름을 짓는 패턴을 의도를 드러내는 선택자(Intention Revealing Selector)라고 부른다.
의도를 드러내는 선택자를 인터페이스 레벨로 확장한 의도를 드러내는 인터페이스(Intention Revealing Interface)
구현과 관련된 모든 정보를 캡슐화하고 객체의 퍼블릭 인터페이스에는 협력과 관련된 의도만을 표현하는 것이다.
명령-쿼리 분리의 원칙(Command-Query Separation)
명령-쿼리 분리 원칙은 퍼블릭 인터페이스에 오퍼레이션을 정의할 때 참고할 수 있는 지침을 제공한다.
용어 정리
어떤 절차를 묶어 호출 가능하도록 이름을 부여한 기능 모듈을 루틴(routine)이라 부른다.
루틴은 다시 프로시저(procedure)와 함수(function)로 구분할 수 있다.
프로시저: 정해진 절차에 따라 내부의 상태를 변경하는 루틴의 한 종류
함수: 어떤 절차에 따라 필요한 값을 계산해서 반환하는 루틴의 한 종류
프로시저와 함수 구분
프로시저는 부수효과를 발생시킬 수 있지만 값을 반환할 수 없다.
함수는 값을 반환할 수는 있지만 부수효과를 발생시킬 수 없다.
명령(Command)와 쿼리(Query)는 객체의 인터페이스 측면에서 프로시저와 함수를 부르는 또다른 이름이다.
명령: 객체의 상태를 수정하는 오퍼레이션
쿼리: 객체와 관련된 정보를 반환하는 오퍼레이션
명령-쿼리 분리 원칙의 요지
어떤 오퍼레이션도 명명인 동시에 쿼리여서는 안된다.
객체의 상태를 변경하는 명령은 반환값을 가질 수 없다.
객체의 정보를 반환하는 쿼리는 상태를 변경할 수 없다.
명령-쿼리 분리와 참조 투명성
명령과 쿼리를 분리함으로써 명령형 언어의 틀 안에서 참조 투명성(referential transparency)의 장점을 제한적이나마 누릴 수 있게 된다.
참조 투명성이란
"어떤 표현식 e가 있을 때 e의 값으로 e가 나타나는 모든 위치를 교체하더라도 결과가 달라지지 않는 특성"
참조 투명성을 통한 두 가지 장점
모든 함수에서 이미 알고 있는 하나의 결과값으로 대체할 수 있기 때문에 식을 쉽게 계산할 수 있다.
모든 곳에서 함수의 결괏값이 동일하기 때문에 식의 순서를 변경하더라도 각 식의 결과는 달라지지 않는다.
명령형 프로그래밍과 함수형 프로그래밍
명령형 프로그래밍은 부수효과를 기반으로 하는 프로그래밍 방식이다.
함수형 프로그래밍은 부수효과가 존재하지 않는 수학적인 함수에 기반한다. 따라서 참조 투명성의 장점을 극대화할 수 있으며, 프로그래밍의 실행 결과를 이해하고 예측하기 더 쉽다.
책임에 초점을 맞춰라
위 네 가지 원칙의 장점
디미터 법칙
협력이라는 컨텍스트 안에서 객체보다 메시지를 먼저 결정하면 두 객체 사이의 구조적인 결합도를 낮출 수 있다.
수신할 객체를 알지 못한 상태에서 메시지를 먼저 선택하기 때문에 객체의 내부 구조에 대해 고민할 필요가 없어진 다.
따라서 메시지가 객체를 선택하게 함으로써 의도적으로 디미터 법칙을 위반할 위험을 최소화할수 있다.
묻지 말고 시켜라
메시지를 먼저 선택하면 묻지 말고 시켜라 스타일에 따라 협력을 구조화하게 된다.
클라이언트의 관점 에서 메시지를 선택하기 때문에 필요한 정보를 물을 필요 없이 원하는 것을 표현한 메시지를 전송하면 된다.
의도를 드러내는 인터페이스
메시지를 먼저 선택한다는 것은 메시지를 전송하는 클라이언트의 관점에서 메시지의 이름을 정한다는 것이다.
당연히 그 이름에는 클라이언트가 무엇을 원하는지, 그 의도가 분명하게 드러날 수밖에 없다.
명령-쿼리 분리 원칙
메시지를 먼저 선택한다는 것은 협력이라는 문맥 안에서 객체의 인터페이스에 관해 고민한다는 것 을 의미한다.
객체가 단순히 어떤 일을 해야 하는지 뿐만 아니라 협력 속에서 객체의 상태를 예측하고 이해하기 쉽게 만들기 위한 방법에 관해 고민하게 된다.
따라서 예측 가능한 협력을 만들기 위해 명령과 쿼리를 분리하게 될 것이다.
Last updated