책임과 메세지(1)

공병주(Chris)·2021년 9월 16일
0

자율적인 책임

설계를 좌우하는 책임

💡 자율성 : 자기 스스로의 원칙에 따라 어떤 일을 하거나 자신을 통제해서 절제하는 성질이나 특성

💡 객체가 어떤 행동을 하는 유일한 이유는 다른 객체로부터 요청을 수신했기 때문

💡 책임 : 객체가 요청을 처리하기 위해 수행하는 행동

✔️ 자율적인 객체 : 스스로의 의지와 판단에 따라 각자 맡은 책임을 수행하는 객체

객체 지향 설계의 아름다움

책임-주도 설계에 따라 적절한 객체에게 적절한 책임 → 자율적인 객체 ( 본인이 처리할 수 있는 임무를 맡았기 때문에 스스로의 의지와 판단에 따라 책임 수행 가능 ) → 자율적인 객체들이 모여 유연하고 단순한 협력 → 전체적으로 좋은 설계

자신의 의지에 따라 책임을 수행할 수 있는 자유

✔️ 객체의 자율적 책임 수행을 위해서는 객체에게 할당되는 책임이 자율적이어야한다.

ex 1) 사장이 알바생에게 아메리카노 한잔을 만들어돌라고 요청한다.

ex 2) 사장이 알바생에게 아메리카노 한잔을 만드는데, 얼음은 5개 넣고 컵은 커피머신의 버튼을 클릭한 후에 선반에서 빼고, 뚜껑은 커피가 컵에 따라지고 30초 후에 닫으라고 요청한다.

→ ex1에 비해 ex2의 문제는 사장이 알바생에게 아메리카노 한잔을 만들기 위해 선택할 수 있는 자유를 지나치게 제한한다. 알바생에게 할당되는 책임이 비교적 자율적이지 않기 때문에, 알바생은 자율적으로 책임을 수행할 수 없다.

→ ex2에 비해 ex1의 경우는 사장의 아메리카노 한잔의 요청이 알바생의 자율성을 보장할 수 있을만큼 추상적이지만, 알바생이 할 일( 아메리카노 한잔 만들기 )을 정확히 명시하고 있다.

너무 추상적인 책임

포괄적이고 추상적인 책임이 객체의 자율성을 보장해주고 더 다양한 환경에서 재사용할 수 있도록 유연성을 제공한다. 그러나

✔️ 책임은 협력에 참여하려는 의도를 명확하게 설명할 수 있는 수준에서 추상적이어야한다.

ex ) 사장이 알바생에게 아메리카노 한잔이 아닌 '커피 한 잔 만들어줘'를 요청한다면 알바생은 라떼를 만들어야할지, 아메리카노를 만들어야 할지 혼동이 올 것이다.
→ 책임이 너무 추상적이기 때문에, 알바생은 협력에 있어서 자신의 책임을 명확히 알지 못한다.

ex ) 사장님이 알바생에게 '아메리카노 한 잔'을 요청한다.
책임이 명확함과 동시에 알바생의 자율성을 보장해준다.

→ 책임은 객체의 자율성을 보장할 수 있을 정도로 충분히 추상적이면서

협력의 의도를 뚜렷하게 알 수 있을 정도로 충분히 구체적이어야한다.

❗️책임의 자율적임을 판단하는 기준은 문맥에 따라 다르다.

ex ) 사장이 알바생에게 "다음 주문들을 위해 힘내게 커피 한잔 마셔"라고 하는 요청은 알바생으로하여금, 본인이 마시고 싶은 커피를 선택할 수 있는, 선택한 커피를 자신의 방식으로 만들 수 있는 자율성을 제공함과 동시에 커피 한잔이라는 명확한 의도를 파악할 수 있도록 하기때문에, 이 문맥에서는 '커피한잔 만들어줘'라는 요청이 적절하다.

'어떻게'가 아니라 '무엇'을

✔️ 자율적 책임의 측징은 객체가 '어떻게' 해야하는가가 아니라 '무엇을' 해야하는가를 설명하는 것이다.

ex) 위에서 예로 들었던 '아메리카노 한잔 만들어줘'라는 요청은 아메리카노 한잔을 위한 아메리카노의 제조 방식(어떻게)까지 붙혀 요청하는 것이 아닌 아메리카노 한잔(무엇)만을 요청하는 적절한 요청이다.

책임을 자극하는 메시지

✔️ 객체지향에서 책임을. 즉, 행동을 수행하도록 하는 것은 오로지 메시지뿐이다.

객체들은 외부에서 어떤 요청을 받았을 때만 어떤 행동을 시작한다. 객체가 다른 객체에게 접근할 수 있는 유일한 방법, 또한 객체가 요청을 받는 유일한 방법은 메시지를 수신하는 것이다.


메시지와 메서드

메시지

위에서 다른 객체에 접근하는 방법, 다른 객체에 요청을 보내는 유일한 방법은 메시지라고 했다.

메시지이름

위의 예에서, 사장이 알바생에게 전송하는 메시지를 가리키는 '아메리카노 한잔 만들어줘'라고 하는 부분을 메시지이름이라고 한다.

인자(Argument)

메시지를 전송할 때, 추가적인 정보가 필요한 경우 메시지의 인자를 통해 추가정보를 제공할 수 있다.
ex) 9시까지 아메리카노 10잔 포장 주문이 들어와 사장은 알바생에게 "9시까지 아메리카노 10잔 만들어줘"라는 요청을 할 수 있다.
→ 아메리카노 만들어줘 ( 완료시간 9시, 10잔)

✔️ 메시지 = 수신자 + 메시지 이름 + 인자

메시지 전송은 메시지를 받는 수신자와 메시지의 조합이다. 그런데 메시지는 메시지 이름과 인자의 조합이기 때문에 결국 메시지는 수신사, 메시지 이름, 인자로 구성된다.

✔️ 따라서 메시지 전송은 수신사.메시지이름(인자)와 같은 형식이다.

ex ) 알바생.아메리카노한잔제조( 완료시간 9시, 10잔 )

✔️ 객체가 수신할 수 있는 메시지의 모양이 객체가 수행할 책임의 모양을 결정

메시지를 수신받은 객체는 우선 자신이 해당 메시지를 처리할 수 있는지 확인하고 처리할 수 있다면 객체가 해당 메시지에 해당하는 행동을 수행해야 할 책임이 있다는 것

→ 따라서 메시지의 개념은 책임의 개념과 연결된다.

ex) 오래된 알바생은 아메리카노 제조를 빨리 할 수 있어, '알바생.아메리카노한잔제조( 완료시간 9시, 10잔)'이라는 메시지를 수신할 수 있지만, 오늘 처음 온 알바생은 제조를 빨리 할 수 없어 '알바생.아메리카노한잔제조()'라는 메시지 밖에 수신할 수 없다. 따라서,
오래된 알바생은 '알바생.아메리카노한잔제조()'와 '알바생.아메리카노한잔제조( 완료시간 9시, 10잔)'라는 책임의 모양을 가지지만,
오늘 처음 온 알바생은 '알바생.아메리카노한잔제조()'라는 책임의 모양을 가진다.

✔️ 객체는 수신받은 메시지를 자율적인 방법으로 처리할 수 있다.

ex ) 만약, 알바생이 사장에게서 '사장.아메리카노한잔제조()'라는 메시지를 수신했고, 커피는 보이지 않는 주방에서 제조된다고 가정해보자. 사장은 알바생이 컵에 얼음을 넣고 커피머신을 작동시키는지, 커피머신을 작동시키는 동시에 컵에 얼음을 넣는지 등의 알바생이 어떻게 아메리카노를 만드는지에 대해 알 수가 없고, 알바생은 어떠한 방식으로든(자율성) 아메리카노 한잔을 제조하기만 하면 된다.

메서드

✔️ 메서드란, 객체가 수신한 메시지를 처리하기 위해 내부적으로 선택하는 방법

객체는 메시지를 수신하고 자신이 처리할 수 있다고 판단되면 메시지를 처리할 방법인 메서드를 선택한다. 또한 메시지는 '어떻게' 처리할지는 명시하지 않고, 단지 Operation을 통해 '무엇'을 처리할지만 명시한다. 어떤 메서드를 선택할지는 전적으로 수신자가 결정하는 것이다.

💡 객체 지향 프로그래밍 언어에서 메서드는 보통 클래스 안에 포함된 함수나 프로시저를 통해 구현된다. 그리고 절차지향 프로그래밍 언어은 프로시저 호출에 대한 실행코드를 컴파일 시간에 결정하지만 객체지향 프로그래밍 언어는 이를 런타임(실행시간)에 결정한다.

다형성

✔️ 다형성이란, 서로 다른 유형의 객체가 동일한 메시지에 대해 서로 다르게 반응하는 것

서로 다른 타입에 속하는 객체들이 동일한 메시지를 수신할 경우, 서로 다른 메서드로 메시지를 처리하는 메커니즘을 의미한다.

앞서 말한 것처럼, 메시지는 무엇을 처리할지를 명시하지 어떻게 처리할지를 명시하지 않기 때문에, 서로 다른 방식의 메서드를 이용해 처리할 수 있다. ( 객체는 자율적인 존재이기 때문 )

ex) 아메리카노 한 잔 제조라는 요청에 대해 알바생 A는 커피를 만들 때 얼음통을 먼저 꺼내고 커피머신을 작동 시킬 수 있지만, 알바생 B는 커피머신을 작동시키고 얼음통을 꺼낼 수 있다.

→ 어떤 방법을 사용하던 결과적으로 아메리카노 한잔이 제조된다. ( 동일한 결과 )

✔️서로 다른 객체들이 다형성을 만족시킨다는 것은 객체들이 동일한 책임을 공유한다는 것

메시지 수신자들이 송신자의 요청을 서로 다른 방식으로 처리한다고해도, 메시지 송신자는 다형적인 수신자들을 처리 방식에 따라 구별할 필요도 없고 관심도 없다. 수신자들은 송신자의 요청을 수행할 책임을 지닌다는 관점에서 동일하다.

✔️ 다형성은 동일한 역할을 수행할 수 있는 객체들 사이의 대체 가능성을 의미한다.

메시지를 수신하는 객체들의 메시지를 처리하기 위한 메서드는 달라도 송신자의 입장에선 동일한 메시지를 처리할 수 있는 존재들이기 때문에, 대체 가능하다는 것을 의미한다.

✔️ 다형성은 객체들의 대체 가능성을 이용해 설계를 유연하고 재사용 가능하게 만든다.

다형성을 사용하면 송신자가 수신자의 종류를 모르더라도 메시지를 전송할 수 있다. 즉, 다형성은 수신자의 종류를 캡슐화한다. 사장은 알바생 다수들에게 '아메리카노 한잔 제조'를 요청하지만 이를 처리하는 알바생이 오늘 처음 온 알바생인지, 3달 된 알바생인지, 2년된 알바생인지 알 필요가 없다. 누구던 아메리카노 한잔을 제조해오면 되는 것이다.

💡 객체 지향 용어로 표현하면, 다형성은 송신자와 수신자 간의 객체 타입에 대한 결합도를 메시지에 대한 결합도로 낮춤으로써 달성된다.

(사장과 A알바생, 사장과 B알바생, 사장과 C알바생) —재사용→ (사장과 알바생)

→ 다형성을 사용하면 메시지를 이해할 수 있는, 수신할 수 있는 어떤 객체와도 협력할 수 있는 유연하고 확장 가능한 구조를 만들 수 있다.

유연하고 확장가능하고 재사용성이 높은 협력의 의미

1. 협력이 유연해진다.

송신자는 자신의 메시지를 이해할 수 있다면 수신자가 누구라도 상관없다. 송신자는 수신자에 대해 어떤 가정도 하지 않기 때문에, 수신자를 다른 타입의 객체로 대체하더라도 송신자는 알 수 없다.
→ 송신자에 대한 파급효과 없이 유연하게 협력을 변경할 수 있다.

2. 협력이 수행되는 방식을 확장할 수 있다.

수신자를 바꿔도 송신자에게는 아무런 영향을 미치지 않기 때문에 협력의 세부 수행 방식을 쉽게 수정 가능하다.
ex) 사장의 '아메리카노 한잔 제조'라는 주문에 알바생이 아메리카노 제조 순서를 어떻게 하던 상관없다.

✔️협력이 동작하는 수신자의 세부 행동은 바뀔 수 있지만, 협력의 구조 자체는 변하지 않는다.

→ 협력을 확장하고 싶으면 간단하게 새로운 유형의 객체를 협력에 끼워 맞추기만 하면 된다.

3. 협력이 수행되는 방식을 재사용할 수 있다.

협력에 영향을 미치지 않는 선에서도, 객체들이 메시지 수신자의 자리를 대체할 수 있기 때문에 다양한 문맥에서 협력을 재사용할 수 있다.

ex) 사장의 '아메리카노 한잔 제조'라는 주문을 A알바생이하던, B알바생이하던, 협력에 영향을 미치지 않는다.

💡 객체의 조합을 변경함으로써 시스템의 행위를 변경할 수 있다.

객체-지향 시스템은 협력하는 객체들의 연결망이다. 시스템은 객체를 생성하고 상호 간에 메시지를 송신할 수 있게 이들을 끼워 맞춤으로써 구축된다. 객체의 조합을 관리하기 위해 작성하는 코드는 객체 연결망이 어떻게 행동할 것인지에 대한 선언적인 정의다. 그런데 객체 연결망 속에는 객체들이 있고, 우리는 객체들이 어떻게 행동하는지보다 무엇을 할 것인지에 초첨을 맞추기 때문에 시스템의 행위를 변경하기가 쉽다.

송신자와 수신자를 약하게 연결하는 메시지

송신자의 입장에서 메시지

송신자는 수신자의 타입을 모르고 수신자가 메시지를 처리해줄 것이라는 믿음을 가지고 오직 메시지만을 본다.

수신자의 입장에서 메시지

수신자는 메시지를 처리하기 위해 메서드를 직접 선택하지만, 메서드를 외부에 노출하지 않는다.

✔️수신자와 송신자는 메시지라는 얇은 끈으로만 이어져 있다.

유연하고 확장 가능하고 재사용성이 높은 협력을 가능하게 하는 객체 지향의 다형성이라는 것은 송신자와 수신자 사이의 결합도를 낮춘 메시지(얇은 끈)가 있기 때문에 실현가능한 것이다.

0개의 댓글