박승규 / 오브젝트 1장 - 객체 설계 | 커리어리
커리어리
# 들어가기
- 훌륭한 객체지향 코드를 얻기 위해서는 클래스가 아니라 객체가 수행하는 책임에 초점을 맞춰야 한다.
- 책임은 객체가 수신할 수 있는 메시지의 기반이 된다.
- 객체가 수신하는 메시지들이 객체의 퍼블릭 인터페이스를 구성한다.
- 이번 장에서는 유연하고 재사용 가능한 퍼블릭 인터페이스를 만드는데 도움이 되는 설계 원칙과 기법을 살펴본다.
### 01 협력과 메시지
- 협력은 어떤 객체가 다른 객체에게 무언가를 요청할 때 시작된다.
- 두 객체사이의 협력관계를 위해 사용하는 전통적인 메타포는 클라이언트 - 서버 모델이다.
- 메시지(message)는 객체들이 협력 하기 위해 사용할 수 있는 유일한 소통 수단이다.
- 메시지는 오퍼레이션명과 인자로 구성되며, 메시지 전송은 여기에 수신자를 추가한 것이다.
- 메시지를 수신했을 때 실제로 수행되는 함수 또는 프로시저를 메서드라고 부른다.
- 런타임에는 객체의 타입이 달라질 수 있어서, 코드상으로는 동일한 이름의 변수에 동일한 메시지를 전송하더라도 실행되는 메서드가 달라질 수 있다.
- 객체가 외부에 공개하는 메시지의 집합을 퍼블릭 인터페이스라고 한다.
- 퍼블릭 인터페이스에 포함된 메시지를 오퍼레이션이라고 부른다.
- 오퍼레이션은 수행가능한 행동에 대한 추상화
- 인터페이스에 정의된 요소는 오퍼레이션이다.
- 오퍼레이션의 이름과 파라미터 목록을 합쳐 시그니처라고 부른다.
- 하나의 오퍼레이션에 다양한 메서드를 구현하면 다형성을 사용할 수 있다.
### 02 인터페이스와 설계 품질
- 좋은 인터페이스는 최소한의 인터페이스와 추상적인 인터페이스라는 조건을 만족해야한다.
- 최소한의 인터페이스 - 꼭 필요한 오퍼레이션을 인터페이스에 포함한다.
- 추상적인 인터페이스는 어떻게가 아닌 무엇을 하는지를 표현한다.
- 퍼블릭 인터페이스의 품질에 영향을 미치는 원칙과 기법
- 디미터 법칙
- 묻지말고 시켜라
- 의도를 드러내는 인터페이스
- 명령 - 쿼리 분리
디미터 법칙
- 객체의 내부 구조에 강하게 결합되지 않도록 협력 경로를 제한하라
- 낯선자에게 말하지 말라
- 인접한 이웃하고만 말하라
- Object-Oriented Programming: An Objective Sense of Style에서 처음소개. 해당 책의 저자들이 디미터라는 프로젝트를 진행중. 객체의 협력경로를 제한하면 결합도를 효과적으로 낮출 수 있다는 사실을 발견
- 특정한 조건을 만족하는 대상에게만 메시지를 전송하도록 프로그래밍
- 모든 클래스 C와 C에 구현된 모든 메서드 M에 대해서, M이 메시지를 전송할 수 있는 모든 객체는 다음과 같은 클래스의 인스턴스여야 한다.
- M의 인자로 전달된 클래스
- C의 인스턴스 변수의 클래스
- 위 설명이 어렵다면 다음의 조건으로 확인
- this 객체
- 메서드의 매개변수
- this의 속성
- this의 속성인 컬렉션의 요소
- 메서드 내에서 생성된 지역 객체
- 디미터 법칙을 따르면 부끄럼 타는 코드를 작성할 수 있다.
- 부끄럼 타는 코드 : 다른객체에게 불필요한 것을 보여주지 않음. 다른 객체에 의존하지 않음
- 기차 충돌(getter들이 기차처럼 연결된 코드)은 대표적인 디미터 법칙 위반이다. 다음과 같은 코드를 말함 `screening.getMovie().getDiscountCondition()`
- 무비판적으로 디미터 법칙을 수용하면 객체의 응집도가 낮아질 수 있다.
묻지 말고 시켜라 (Tell, Don't Ask)
- 절차적인 코드는 정보를 얻은 후에 결정한다. 객체지향 코드는 객체에게 그것을 하도록 시킨다.
- 객체의 정보를 이용하는 행동을 외부가 아닌 내부에 위치시켜서 정보와 행동을 동일한 클래스에 두게 됨.
- 내부의 상태를 이용해 어떤 결정을 내리는 로직이 외부에 존재한다면 해당객체가 책임져야하는 행동이 외부로 누수된 것이다.
- 단순하게 묻지 않고 시킨다고 해서 모든 문제가 해결되지는 않음. 인터페이스는 개체가 어떻게 하는지가 아닌 무엇을 하는지를 서술해야한다.
의도를 드러내는 인터페이스
- 메서드 이름을 짓는 두가지 방법
- 어떻게 하는지 명시
- 무엇을 하는지 명시
- 무엇을 하는지 드러내는 이름이 유연한 코드를 만들기 편하다.
- 무엇을 하느냐에 따라 메서드의 이름을 짓는 패턴을 `의도를 드러내는 선택자` 라고 부른다.
- 켄트백은 메서드에 의도를 드러낼 수 있는 이름을 붙이기 위해 다음과 같이 생각해볼 것을 조언
> 매우 다른 두번째 구현을 상상하라. 그리고 해당 메서드에 동일한 이름을 붙인다고 상상해보라. 그렇게 하면 아마도 그 순간에 여러분이 할 수 있는 한 가장 추상적인 이름을 메서드에 붙일 것이다.
- <도메인 주도 설계>에서는 `의도를 드러내는 인터페이스` 를 제시
- 수행 방법에 관해서는 언급하지 말고 결과와 목적만을 포함하도록 클래스와 오퍼레이션의 이름을 부여하라.
### 03 원칙의 함정
- 디미터 법칙과 묻지 말고 시켜라는 훌륭한 설계원칙이지만, 절대적인 원칙은 아니다.
- 소프트웨어 설계에 법칙이란 존재하지 않는다.
디미터 법칙은 하나의 닷(.)을 강제하는 규칙이 아니다.
- 자바의 IntStream을 사용한 코드는 기차 충돌을 야기하므로 디미터 법칙 위반이라고 하는 사람들이 있으나, 해당 코드는 다른 인스턴스를 참조하지 않으므로 결합도가 증가하지 않는다.
결합도와 응집도의 충돌
- 어떤 객체의 상태를 물어본 후 반환된 상태를 기반으로 결정을 내리고 그에따라 객체의 상태를 변경하는 코드는 묻지 말고 시켜라 스타일로 변경해야한다. (Theater의 enter메서드)
- 디미터 법칙의 위반 여부는 대상이 객체인지, 자료구조인지에 달려있다.
- 객체는 내부구조를 숨겨야하므로 디미터 법칙을 따르는 것이 좋지만, 자료구조라면 내부를 노출해야하므로 디미터 법칙을 따를 필요가 없다.
- 원칙을 맹신하지 말라.
### 04 명령-쿼리 분리 원칙
- 프로시저와 함수의 차이점
- 프로시저는 정해진 절차에 따라 내부의 상태를 변경하는 루틴의 종류이다.
- 함수는 어떠한 값을 계산해서 반환하는 루틴의 한 종류이다.
- 프로시저는 부수효과를 발생시키지만, 값을 반환 하지 않는다.
- 함수는 값을 반환하지만, 부수효과를 발생시키지 않는다.
- 명령(Command)과 쿼리(Query)는 객체의 인터페이스 측면에서 프로시저와 함수를 부르는 또 다른 이름이다.
- 객체의 상태를 변경하는 명령은 반환값을 가질 수 없다.
- 객체의 정보를 반환하는 쿼리는 상태를 변경할 수 없다.
- 기계로서의 메타포
- 동그란 버튼은 쿼리이고, 네모난 버튼은 명령이다. (empty와 search의 위치가 바뀐것 같다.)
- 명령과 쿼리를 섞어서 사용하면 실행결과를 예측하기가 어려워진다.
책임에 초점을 맞춰라
- 메시지를 먼저 선택하고 해당 메시지를 처리할 객체를 선택하라.
- 객체 구현 이전에 객체사이의 협력에 초점을 맞추고 협력방식을 단순하고 유연하게 만들자.
- 책임 주도 설계를 하자.
- 버트란드 마이어는 계약에 의한 설계 개념을 제안했다.
오브젝트 1장 https://careerly.co.kr/comments/92380
오브젝트 2장 https://careerly.co.kr/comments/92467
오브젝트 3장 https://careerly.co.kr/comments/92725
오브젝트 4장 https://careerly.co.kr/comments/93990
오브젝트 5장 https://careerly.co.kr/comments/96255
다음 내용이 궁금하다면?
이미 회원이신가요?
2024년 1월 29일 오전 9:23
하나부터 열까지 리더가 상세히 설명해 주기를 바라는 구성원이 있습니다. 반대로 큰 얼개만 듣고 나머지는 자율적으로 하고 싶어 하는 경우도 있죠. 회식에 참여하는 것을 너무나 힘겨워 하는 구성원이 있는 반면, 동료들과 함께 시간을 보내며 가까워지는 것을 원하는 구성원도 있습니다.
... 더 보기6
... 더 보기코
... 더 보기추
... 더 보기