오브젝트 내용 요약
책 <오브젝트>의 내용을 요약한다.
오브젝트 내용 요약
3장
협력: 다른 객체들에게 무엇인가를 ‘요청’하는 것 (도와주세요)
- 협력에 필요함에 있어 다른 객체가 필요하다면 해당 객체를 사용한다. (
screening.reserve(movie)
)- 다른 객체를 파라미터로 받던지 등
책임: 협력에서(협력에 참여하기 위해) 객체가 하는 행동
- 책임은 아는 것과 하는 것으로 분류한다
- 책임을 능숙하게 할당하는 것에 따라 설계 품질이 달라진다.
- 해당 도메인의 전문가에게 책임을 할당하는 것이 바람직하다.
역할: 협력 안에서 객체가 수행하는 책임들의 집합
- 역할이 중요한 이유는 유연하고 재사용 가능한 협력을 얻을 수 있기 때문
- 여러 할인 정책에 따라 영화 금액이 달라진다면,
DiscountPolicy
라는 추상화된 역할에만 의존하는 것이다. - 협력에 참여하는 대상이 하나라면 객체, 여러 종류라면 역할로 설계를 하자.
객체에게 중요한 것은 행동이라는 사실을 기억하라. 역할이 중요한 이유는 동일한 협력을 수행하는 객체들을 추상화 할 수 있기 때문이다. 1
4장
객체지향 설계의 핵심은 역할, 책임, 협력이다. 2
역할, 책임, 협력 중에서 가장 중요한 것은 책임이다.
객체지향 설계란 올바른 객체에게 올바른 책임을 할당하면서 낮은 결합도와 높은 응집도를 가진 구조를 창조하는 활동이다. 3
결합도와 응집도를 합리적인 수준으로 유지하기 위해서는 객체의 상태가 아닌 행동에 초점을 두자.
변경될 가능성이 높은 부분을 구현이라고 부르고 상대적으로 안정적인 부분을 인터페이스라고 부른다는 사실을 기억하라. 4
캡슐화의 정도가 응집도와 결합도에 영향을 미친다. 5
데이터 중심의 설계는 캡슐화를 위반하고 객체의 내부 구현을 인터페이스의 일부로 만든다. 반면 책임 중심의 설계는 객체의 내부 구현을 안정적인 인터페이스를 뒤로 캡슐화한다. 6
캡슐화는 설계의 제1원리다. 객체는 스스로의 상태를 책임져야 하며 외부에서는 인터페이스에 정의된 메서드를 통해서만 상태에 접근할 수 있어야 한다. 7
객체는 단순한 데이터 제공자가 아니다. 객체 내부에 저장되는 데이터보다 객체가 협력에 참여하면서 수행할 책임을 정의하는 오퍼레이션이 더 중요하다. 8
데이터는 구현의 일부라는 사실을 명심하라. 데이터 주도 설계는 설계를 시작하는 처음부터 데이터에 관해 결정하돌고 강요하기 때문에 너무 이른 시기에 내부 구현에 초점을 맞추게 한다. 9
객체지향 애플리케이션을 구현한다는 것은 협력하는 객체들의 공동체를 구축한다는 것을 의미한다. 올바른 객체지향 설계의 무게 중심은 항상 객체의 내부가 아니라 외부에 맞춰져 있어야 한다. 10
한줄요약: 캡슐화를 잘 하자.
- 데이터 중심이 아니라, 객체에게 적절한 책임을 할당하고 객체가 하는 일을 캡슐화하여 응집도를 높이고 결합도를 낮추자.
5장
- 객체의 데이터가 아닌 책임, 메시지에 초점을 맞추자.
- 정보 전문가에게 책임을 할당하자. 자기 자신이 모든 것을 수행할 수 없다면 다른 객체에게 협력을 요청하자.
- 코드를 통해 변경의 이유를 파악할 수 있는 방법들이 있다. 11
- 인스턴스 변수가 초기화 되는 시점을 살펴보라.
- 메서드들이 인스턴스 변수를 사용하는 방식을 살펴보라.
- 속성 그룹과 해당 그룹에 접근하는 메서드 글부을 기준으로 코드를 분리하라.
데이터 중심 설계로 인해 발생하는 문제점을 해결할 수 있는 가장 기본적인 방법은 데이터가 아닌 책임에 초점을 맞추는 것이다. 12
데이터 중심의 세계에서는 "이 객체가 포함해야 하는 데이터가 무엇인가"를 결정한 후에 "데이터를 처리하는 데 필요한 오퍼레이션은 무엇인가"를 결정한다. 반면 책임 중심의 설계에서는 "이 객체가 수행해야 하는 책임은 무엇인가"를 결정한 후에 "이 책임을 수행하는 데 필요한 데이터는 무엇인가"를 결정한다. 13
중요한 것은 설계를 시작하는 것이지 도메인 개념들을 완벽하게 정리하는 것이 아니다. 도메인 개념을 정리하는 데 너무 많은 시간을 들이지 말고 빠르게 설계와 구현을 진행하라. 14
객체는 자신의 상태를 스스로 처리하는 자율적인 존재여야 한다. (…중략) 객체에게 책임을 할당하는 첫 번째 원칙을 책임을 수행할 정보를 알고 있는 객체에게 책임을 할당하는 것이다. GRASP에서는 이를 INFORMATION EXPERT 패턴이라고 부른다. 15
코드를 통해 변경의 이유를 파악할 수 있는 첫 번째 방법은 인스턴스 변수가 초기화되는 시점을 살펴보는 것이다. 응집도가 높은 클래스는 인스턴스를 생성할 때 모든 속성을 함께 초기화한다. 반면 응집도가 낮은 클래스는 객체의 속성 중 일부만 초기화하고 일부는 초기화되지 않은 상태로 남겨진다.
코드를 통해 변경의 이유를 파악할 수 있는 두 번째 방법은 메서드들이 인스턴스 변수를 사용하는 방식을 살펴보는 것이다. 16
다음은 타입을 분리하지 않았을 때의 예제를 간소화한 코드이다. 17
class Movie {
List<PerioidCondition> periodConditions;
List<SequenceCondition> sequenceConditions;
private boolean isDiscoutable(Screening screening) {
return this.periodConditions.stream()
.anyMatch(c -> c.isSatisfiedBy(screening)
|| this.sequenceConditions.stream()
.anyMatch(c -> c.isSatisfiedBy(screening)
}
}
사실 Movie 입장에서는 PerioidCondition과 SequenceCondition이 아무 차이가 없다.
새로운 Condition이 추가된다면? 새로운 List를 필드에 추가할 것인가?
할인 조건이 추가되었는데 Movie 클래스의 코드가 수정된다면 응집도가 낮은 설계라고 볼 수 있다.
PerioidCondition과 SequenceCondition을 하나의 Condition으로 추상화하자.
class Movie {
List<Condition> conditions;
private boolean isDiscoutable(Screening screening) {
return this.conditions.stream()
.anyMatch(c -> c.isSatisfiedBy(screening);
}
객체의 타입에 따라 변하는 로직이 있을 때 변하는 로직을 담당할 책임을 어떻게 할당해야 하는가? 타입을 명시적으로 정의하고 각 타입에 다형적으로 행동하는 책임을 할당하라. 18
책임 주도 설계 방법에 익숙하지 않다면 일단 데이터 중심으로 구현한 후 이를 리팩터링하더도 유사한 결과를 얻을 수 있다는 것이다. 처음부터 책임 주도 설계 방법을 따르는 것보다 동작하는 코드를 작성한 후에 리팩터링하는 것이 더 훌륭한 결과물을 낳을 수도 있다. 19
6장- 메시지와 인터페이스
- 메시지란 무엇인가
- 메시지와 인터페이스가 왜 중요한가
- 메시지와 인터페이스는 무슨 관계인가
메시지란 객체가 협력할 때 유일하게 주고 받을 수 있는 의사소통 수단을 의미한다.
객체는 인터페이스를 통해 메시지를 서로 주고받는다.
의도를 드러내는 인터페이스
메서드의 이름을 짓는 두 번째 방법은 '어떻게'가 아니라 '무엇'을 하는지를 드러내는 것이다. 20
원칙의 함정
잊지 말아야 하는 사실을 설계가 트레이드오프의 산물이라는 것이다. (…중략) 원칙이 현재 상황에 부적합하다고 판단된다면 과감하게 원칙을 무시하라. 원칙을 아는 것보다 더 중요한 것은 언제 원칙이 유용하고 언제 유용하지 않은지를 판단할 수 있는 능력을 기르는 것이다. 21
명령-쿼리 분리 원칙
- 프로시저와 함수는 각각 부수효과를 일으키는 것, 값을 연산해 반환하는 것.
- 명령을 프로시저, 쿼리를 함수로 표현
- 명령과 쿼리가 뒤섞으면 실행 결과를 예측하기 어려울 수 있다.