- 객체지향 설계의 세 가지 관점
- 개념 관점 (Conceptual Perspective)
- 도메인 안에 존재하는 개념과 개념들 사이의 관계를 표현한다.
- 실제 도메인의 규칙과 제약을 최대한 유사하게 반영하는 것이 핵심
- 명세 관점 (Specification Perspective)
- 객체의 인터페이스를 바라보게 된다.
- 객체가 협력을 위해 '무엇'을 할 수 있는가에 초점을 맞춘다.
- 구현 관점 (Implementation Perspective)
- 프로그래머가 가장 익숙한 관점
- 객체들이 책임을 수행하는 데 필요한 동작하는 코드를 작성하는 것
- 객체의 책임을 '어떻게' 수행할 것인가에 초점을 맞추며 인터페이스를 구현하는 데 필요한 속성과 메서드를 클래스에 추가한다.
- 개념 관점 (Conceptual Perspective)
@ 두 가지 목표
1. 도메인 모델에서 시작해서 최종 코드까지의 구현 과정을 간략하게 설명하는 것
2. 구현 클래스를 개념 관점, 명세 관점, 구현 관점에서 바라본다는 것이 무엇을 의미하는지 설명하는 것
- 커피 전문점은 아주 간단한 도메인
- 우리의 최종 목표는 손님이 커피를 주문하는 사건을 객체를 이용하여 컴퓨터 안에 재구성하는 것
- 도메인 : 커피 전문점
- 객체 : 메뉴판, 메뉴 항목, 손님, 바리스타, 커피
- 타입은 분류를 위해 사용. 상태와 무관하게, 동일하게 행동할 수 있는 객체들은 동일한 타입으로 분류
- 메뉴판 타입, 메뉴 항목 타입, 손님 타입, 바리스타 타입, 커피 타입
- 메뉴판 타입과 메뉴 항목 타입은 포함(containment) 관계 또는 합성(composition) 관계
- 메뉴판 타입과 손님 타입은 연관(association) 관계
- 도메인 모델
- 객체들을 타입과 관계를 이용해 추상화한 모델
- 객체들을 타입과 관계를 이용해 추상화한 모델
- 객체지향 설계의 첫 번째 목표는 훌륭한 협력을 설계하는 것
- 협력을 설계할 때는 객체가 메시지를 선택하는 것이 아니라 메시지가 객체를 선택하게 해야 한다.
- '커피를 주문하라(아메리카노)' 등의 메시지를 통하여 협력에 필요한 객체의 종류와 책임, 주고받아야 하는 메시지에 대한 정리
- 객체가 수신한 메시지는 객체의 인터페이스를 구성한다.
- 객체가 어떤 메시지를 수신할 수 있다는 것은 그 객체의 인터페이스 안에 메시지에 해당하는 오퍼레이션이 존재한다는 것을 의미한다.
- 객체들을 포괄하는 타입을 정의한 후 식별된 오퍼레이션을 타입의 인터페이스에 추가해야 한다.
- 객체의 타입을 구현하는 일반적인 방법은 클래스를 이용하는 것이다.
- 협력을 통해 식별된 타입의 오퍼레이션은 외부에서 접근 가능한 공용 인터페이스의 일부이다.
- 따라서 인터페이스에 포함된 오퍼레이션 역시 외부에서 접근 가능하도록 public으로 선언돼 있어야 한다.
class Customer {
pulblic void order(String menuName) {}
}
- 클래스의 인터페이스를 식별했으므로 오퍼레이션을 수행하는 방법을 메서드로 구현할 차례
- 객체가 다른 객체에게 메시지를 전송하기 위해서는 먼저 객체에 대한 참조를 얻어야 한다.
class Customer {
public void order(String menuName, Menu menu, Barista barista) {
MenuItem menuItem = menu.choose(menuName);
Coffee coffee = barista.makeCoffee(menuItem);
...
}
}
- MenuItem의 인터페이스를 구성하는 오퍼레이션들을 MenuItem을 구현하는 단계에 와서야 식별했다는 점
- 인터페이스를 통해 실제로 상호작용을 해보지 않은 채 인터페이스의 모습을 정확하게 예측하는 것은 불가능
- 개념 관점
- Customer, Menu, MenuItem, Barista, Coffee 클래스
- 명세 관점
- 클래스의 인스턴스를 바라본다. (클래스의 public 메서드)
- 객체의 인터페이스는 수정하기 어렵고, 변화에 안정적인 인터페이스를 만들기 위해서 인터페이스를 통해 구현과 관련된 세부 사항이 드러나지 않게 해야 한다.
- 구현 관점
- 클래스의 내부 구현을 바라본다.
- 메서드의 구현과 속성의 변경은 외부의 객체에게 영향을 미쳐서는 안 된다. (캡슐화 되어야 함)
- 메시지를 수신할 객체를 선택할 때, 도메인 개념 중에서 가장 적절한 것을 선택하라.
- 도메인 개념 안에서 적절한 객체를 선택하는 것은 도메인에 대한 지식을 기반으로 코드의 구조와 의미를 쉽게 유추할 수 있게 한다.
- 여러 개의 클래스로 기능을 분할하고 클래스 안에서 인터페이스와 구현을 분리하는 이유는 변경이 발생했을 때 코드를 좀 더 수원하게 수정하기 위해
- 명세 관점은 클래스의 안정적인 측면을 드러내야 한다.
- 구현 관점은 클래스의 불안정한 측면을 드러내야 한다.
- 클래스를 봤을 때 클래스를 명세 관점과 구현 관점으로 나눠볼 수 있어야 한다.