정리
메시지
객체가 독립적으로 수행할 수 있는 것보다 더 큰 책임을 수행하기 위해서는 다른 객체와 협력해야 한다는 것이고, 이를 가능케하는 매개체가 바로 메시지이다.
메시지 전송(메시지 패싱)
한 객체가 다른 객체에게 도움을 요청하는 것.
메시지 = 오퍼레이션명 + 인자
메시지 전송 = 오퍼레이션명 + 인자 + 메시지 수신자
메시지 수신자는 누가 메시지를 전송하는지 알 필요가 없다. 단지 메시지가 도착했다는 사실만 알면 된다. 이로써 메시지 전송자와 메시지 수신자가 느슨하게 결합될 수 있게 한다.
또한, 메시지 수신자는 메시지를 처리하기 위해 필요한 메서드를 스스로 결졍할 수 있는 자율권을 누린다.
객체는 메시지와 메서드라는 두 가지 서로 다른 개념을 실행 시점에 연결해야 하기 때문에 컴파일 시점과 실행 시점의 의미가 달라질 수 있다.
퍼블릭 인터페이스
객체가 의사소통을 위해 외부에 공개하는 메시지의 집합
프로그래밍 언어의 관점에서 퍼블릭 인터페이스에 포함된 메시지를 오퍼레이션이라고 부른다.
UML 용어로 말하자면 인터페이스의 각 요소는 오퍼레이션이다. 오퍼레이션은 구현이 아닌 추상화다. 반면 UML의 메서드는 오퍼레이션을 구현한 것이다. 메서드는 오퍼레이션과 연관된 알고리즘 또는 절차를 명시한다[Larman04].
그에 반해, 메시지를 수신했을 때 실제로 실행되는 코드는 메서드라고 부른다.
시그니처
오퍼레이션(또는 메서드)의 이름과 파라미터 목록을 합쳐 시그니처라고 부른다.
오퍼레이션 = 실행 코드 없이 시그니처만을 정의한 것
메서드 = 시그니처 + 구현
퍼블릭 인터페이스의 품질에 영향을 미치는 4원칙 및 기법
- 디미터 법칙
- 묻지 말고 시켜라
- 의도를 드러내는 인터페이스
- 명령-쿼리 분리
디미터 법칙
협력하는 객체의 내부 구조에 대한 결합으로 인해 발생하는 설계 문제를 해결하기 위해 제안된 원칙.
캡슐화를 하기 위해 따라야 하는 구체적인 지침을 제공한다.
객체의 내부 구조에 강하게 결합되지 않도록 협력 경로를 제한하라는 것.
낯선 자에게 말하지 말라[Larman04]
오직 인접한 이웃하고만 말하라[Metz12]
자바나 C#처럼 ‘도트(.)’를 이용해 메시지 전송을 표현하는 언어에서는
오직 하나의 도트만 사용하라[Metz12]라는 말로 요약되기도 한다.
클래스 내부의 메서드가 아래 조건을 만족하는 인스턴스에만 메시지를 전송하도록 프로그래밍 해야 한다[Larman 2004].
- this 객체
- 메서드의 매개변수
- this의 속성
- this의 속성인 컬렉션의 요소
- 메서드 내에서 생성된 지역 객체
screening.getMovie().getDisccountConditions();
메시지 전송자가 수신자의 내부 구조에 대해 물어보고 반환받은 요소에 대해 연쇄적으로 메시지를 전송하는 이와 같은 코드를 기차 충돌이라고 한다.
디미터 법칙을 따르는 코드를 보면
screening.cacluateFee(audienceCount);
와 같이 단 하나의 도트만 사용하는 것을 볼 수 있다.
묻지 말고 시켜라
상태를 묻는 오퍼레이션을 행동을 요청하는 오퍼레이션으로 대체함으로써 인터페이스를 향상시켜라.
의도를 드러내는 인터페이스
구현과 관련된 모든 정보를 캡슐화하고 객체의 퍼블릭 인터페이스에는 협력과 관련된 의도만을 표현해야 한다.
메서드를 명명하는 두 가지 방법
- 메서드가 작업을 어떻게 수행하는지를 나타내도록 이름 짓는 것.
- 어떻게가 아니라 무엇을 하는지를 드러내는 것. (의도를 드러내는 선택자)
어떻게 수행하는지 드러내는 이름 → 내부 구현을 설명하는 이름
무엇을 하는지 드러내는 이름 → 협력하는 클라이언트의 의도에 부합하도록 메서드의 이름을 짓게 됨
정보 은닉 말고도 “묻지 말고 시켜라” 스타일에는 좀 더 미묘한 이점이 있다. 이 스타일은 객체 간의 상호작용을 getter의 체인 속에 암시적으로 두지 않고 좀 더 명시적으로 만들고 이름을 가지도록 강요한다.
법칙에는 예외가 없지만 원칙에는 예외가 넘쳐난다.
디미터 법칙은 하나의 도트(.)를 강제하는 규칙이 아니라 객체의 내부 구조가 외부로 노출되는 경우로 한정된다.
소프트웨어 설계에 법칙이란 존재하지 않는다.
소프트웨어 설계에 존재하는 몇 안 되는 법칙 중 하나는 “경우에 따라 다르다”라는 사실을 명심하라.
명령-쿼리 분리 원칙
루틴: 어떤 절차를 묶어 호출 가능하도록 이름을 부여한 기능 모듈
루틴은 다시 프로시저와 함수로 구분할 수 있다.
- 프로시저는 부수효과(상태변경)를 발생시킬 수 있지만 값을 반환할 수 없다.
- 함수는 값을 반환할 수 있지만 부수효과를 발생시킬 수 없다.
명령과 쿼리는 객체의 인터페이스 측면에서 프로시저와 함수를 부르는 또 다른 이름이다.
명령 = 프로시저
쿼리 = 함수
즉, 명령은 상태를 변경할 수 있지만 상태를 반환해선 안 되고,
쿼리는 객체의 상태를 반환할 수 있지만 상태를 변경해서는 안 된다.
명령과 쿼리를 뒤섞으면 실행 결과를 예측하기가 어렵고, 버그를 양산할 수 있다.
따라서 명령과 쿼리를 분리시켜야 한다!
참조 투명성
어떤 표현식 e가 있을 때 모든 e를 e의 값으로 바꾸더라도 결과가 달라지지 않는 특성.
값이 변하지 않는 성질 → 불변성
불변한다 → 부수효과가 발생하지 않는다.
위 특성으로 인한 참조 투명성 장점
- 식을 쉽게 계산할 수 있다.
- 식의 순서를 변경하더라도 결과는 같다.
명령형 프로그래밍과 함수형 프로그래밍
명령형 프로그래밍은 부수효과를 기반으로 하는 프로그래밍 방식
함수형 프로그래밍은 부수효과가 존재하지 않는 수학적인 함수에 기반한다.
계약에 의한 설계
협력을 위해 클라이언트와 서버가 준수해야 하는 제약을 코드 상에 명시적으로 표현하고 강제할 수 있는 방법이다.
읽고 난 후
저번 장을 읽고 리팩토링을 하려고 했지만 막상 하려고 하니 이론을 적용하기 어려웠다. 이번 장에서 4가지 원칙 및 기법을 통해 구체적인 지침을 얻었기 때문에 이를 바탕으로 다시 리팩토링을 해봐야겠다.
'독서 > 오브젝트(조영호 저)' 카테고리의 다른 글
8장 의존성 관리하기 (0) | 2023.06.02 |
---|---|
7장 객체 분해 (0) | 2023.06.02 |
5장 책임 할당하기 (0) | 2023.06.02 |
4장 설계 품질과 트레이드오프 (0) | 2023.06.02 |
3장 역할, 책임, 협력 (0) | 2023.06.02 |