Study/오브젝트

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

voider 2022. 11. 30. 23:42

클라이언트-서버 모델

협력은 어떤 객체가 다른 객체에게 무언가 요청할 때 시작된다. 메시지는 객체 사이의 협력을 가능하게 하는 매개체다. 객체가 다른 객체에 접근할 수 있는 유일한 방법은 메시지를 전송하는 것뿐. 객체는 희망하는 일을 메시지라는 형태로 전송하고, 수신 객체는 요청을 적절히 처리한 뒤에 응답한다.

이 메시지를 매개로하는 요청과 응답의 조합이 두 객체 사이의 협력을 구성한다.

두 객체 사이의 협력 관계를 설명하기 위해 사용하는 전통적인 메타포는 클라이언트-서버 모델이다.

협력 안에서 메시지를 전송하는 객체를 클라이언트, 메시지를 수신하는 객체를 서버라고 부른다. 협력은 클라이언트가 서버의 서비스를 요청하는 단방향 상호작용이다.

영화 예매 시스템이 있다면 이런 협력 관계를 가질 수 있다.

Screening은 클라이언트, Movie는 서버 역할을 수행한다. 메시지를 전송하고, 응답함으로서 객체 간 협력을 만들어낸다.

Movie가 최종 예매 요금을 계산하기 위해서 할인 요금이 필요하지만, Movie에는 할인 요금을 계산하기 위해 필요한 정보가 부족하다. 따라서 Movie는 할인 요금을 계산하라는 메시지를 DiscountPolicy의 인스턴스에 전송해서 할인 요금을 반환 받는다. 여기서 Movie는 클라이언트가 된다.

Movie의 예에서 알 수 있는 것처럼 객체는 협력에 참여하는 동안 클라이언트와 서버의 역할을 동시에 수행한다. 협력의 관점에서 두 가지 종류의 메시지 집합으로 구성된다. 하나는 객체가 수신하는 메시지의 집합이고, 다른 하나는 외부의 객체에게 전송하는 메시지의 집합이다. 대부분 사람들은 객체가 수신하는 메시지 집합에만 초점을 맞추지만, 협력에 적합한 객체를 설계하기 위해서는 외부에 전송하는 메시지 집합도 함께 고려하는 것이 바람직하다.

요점은 객체가 독립적으로 수행할 수 있는 것보다 더 큰 책임을 수행하기 위해서는 다른 객체와 협력해얗 ㅏㄴ다는 것.

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

메시지와 메시지 전송

메시지는 객체들이 협력하기 위해 사용할 수 있는 유일한 의사소통 수단.

한 객체가 다른 객체에게 요청하는 것을 메시지 전송 또는 메시지 패싱이라고 한다.

이때 메시지를 전송하는 객체를 메시지 전송자sender라고 부르고 수신 객체를 메시지 수신자receiver라고 부른다. 클라이언트-서버 모델 관점에서는 클라이언트, 서버라고 부르기도 한다.

메시지는 오퍼레이션ㅁ명과 인자로 구성되며, 메시지 전송은 여기에 메시지 수신자를 추가한 것이다. 따라서 메시지 전송은 메시지 수신자, 오퍼레이션명, 인자의 조합이다.

//condition: 수신자
//isSatisfied: 오퍼레이션 이름
//screening: 인자
condition.isSatisfiedBy(screening);

메시지와 메서드

메시지를 수신했을 때 실제로 어떤 코드가 실행되는지는 메시지 수신자의 실제 타입이 무엇인가에 달려있다. condition.isSatisfiedBy(screening) 이라는 메시지 전송 구문에서 메시지 수신자인 conditionDiscountCondition 이라는 인터페이스 타입으로 정의돼 있지만, 실제로 실행되는 코드는 인터페이스를 실체화한 클래스의 종류에 따라 달라진다.

이처럼 메시지를 수신했을 때 실제로 실행되는 함수 또는 프로시저를 메서드라고 부른다. 중요한 것은 코드 상에서 동일한 이름의 변수에게 동일한 메시지를 전송하더라도 객체의 타입에 따라 실행되는 메서드가 달라질 수 있다는 것이다.

객체지향은 메시지 전송과 메서드 호출을 명확하게 구분한다.

메시지 전송을 코드 상에 표기하는 시점에는 어떤 코드가 실행될 것인지를 정확하게 알 수 없다. 실행 시점에 실제로 실행되는 코드는 메시지를 수신하는 객체 타입에 따라 달라지기 때문에 우리는 그저 메시지에 응답할 수 있는 객체가 존재하고, 그 객체가 적절한 메서드를 선택해서 응답할 것이라고 믿어야 한다.

메시지와 메서드 구분은 메시지 전송자와 수신자가 느슨하게 결합될 수 있게 한다. 메시지 전송자는 자신이 어떤 메시지를 전송해야 하는지만 알면 된다. 수신자가 어떤 클래스의 인스턴스인지, 어떤 방식으로 요청을 처리하는지 모르더라도 협력이 가능하다. 수신자 역시 누가 메시지를 전송하는지는 알 필요 없다. 단지 메시지가 도착했다는 사실만 알면 된다.

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

객체는 안과 밖을 구분하는 뚜렷한 경계를 가진다. 외부에서 볼 때 객체 안쪽은 검은 장막으로 가려진 미지의 영역이다. 외부 객체는 오직 객체가 공개하는 메시지를 통해서만 객체와 상호작용할 수 있다. 이처럼 객체가 의사소통을 위해서 외부에 공개하는 메시지의 집합을 퍼블릭 인터페이스라고 부른다.

프로그래밍 언어의 관점에서 퍼블릭 인터페이스에 포함된 메시지를 오퍼레이션이라고 부른다. 오퍼레이션은 수행 가능한 어떤 행동에 대한 추상화다. 흔히 오퍼레이션이라고 부를 때는 내부의 구현 코드는 제외하고 단순히 메시지와 관련된 시그니처를 가르키는 경우가 대부분이다. 앞에서 예로 든 DiscountCondition 인터페이스에 정의된 isSatisfiedBy 가 오퍼레이션에 해당한다.

그에 비해 메시지를 수신했을 때 실제로 실행되는 코드는 메서드라고 부른다. SequenceConditionPeriodCondition 의 두 메서드는 DiscountCondition 인터페이스에 정의된 isSatisfiedBy 오퍼레이션의 여러 가능한 구현 중 하나다.

프로그래밍 언어 관점에서 객체가 다른 객체에게 메시지를 전송한다면 런타임시스템은 메시지 전송을 오퍼레이션 호출로 해석하고 메시지를 수신한 객체의 실제 타입을 기반으로 적절한 메서드를 찾아 실행한다. 따라서 퍼블릭 인터페이스와 메시지 관점에서 보면 ‘메서드 호출'보다 ‘오퍼레이션 호출'이라는 용어를 사용하는 것이 더 적절하다.

시그니처

오퍼레이션의 이름과 파라미터 목록을 합쳐 시그니처라고 부른다. 오퍼레이션은 실행 코드 없이 시그니처만 정의한 것이다. 메서드는 이 시그니처에 구현을 더한 것이다. 일반적으로 메시지를 수신하면 오퍼레이션의 시그니처와 동일한 메서드가 실행된다.

정리

  • 메시지
    • 객체가 다른 객체와 협력하기 위해 사용하는 의사소통 매커니즘. 오퍼레이션이 실행되도록 요청하는 것을 메시지 전송이라고 함.
  • 오퍼레이션
    • 객체가 다른 객체에게 제공하는 추상적인 서비스. 오퍼레이션은 수신하는 객체의 인터페이스를 강조한다.
  • 메서드
    • 오퍼레이션의 구현체. 동일한 오퍼레이션이라고 해도 메서드는 다를 수 있다.
  • 퍼블릭 인터페이스
    • 객체가 협력에 참여하기 위해 외부에서 수신할 수 있는 메세지의 묶음.
  • 시그니처
    • 오퍼레이션이나 메서드의 명세.