오트젝트 02 객체지향 프로그래밍
[오브젝트: 코드로 이해하는 객체지향 설계] 를 읽고 정리한 내용입니다.
객체지향 프로그래밍
영화 예매 시스템
이번 장에서는 온라인 영화 예매 시스템을 구현해본다. 먼저 영화라는 도메인에 대해서 용어에 대한 의미를 정한다.
영화
- 제목, 상영 시간, 가격 정보 등 기본적인 정보
상영
- 상영 일자, 시간, 순번 등
다음, 요금 할인에 대한 부분을 정한다.
- 할인 조건
- 순서 조건
- 특정 순번에 상영되는 영화는 할인한다.
- 기간 조건
- 특정 기간에 상영 시작되는 영화는 할인한다.
- 순서 조건
- 할인 정책
- 금액 할인 정책
- 일정금액을 할인한다.
- 비율 할인 정책
- 일정금액의 비율을 할인한다.
- 금액 할인 정책
클래스를 작성할 때 하는 실수
대부분의 사람들은 클래스를 먼저 결정한 후에 어떤 속성과 메서드가 필요한지 고민한다. 하지만 이는 객체가 무엇을 하는지에는 초점이 맞춰지 있지 않기 때문에 좋지 않은 습관이다.
좋은 객체지향을 위해 집중해야하는 두가지
- 어떤 클래스가 필요한지보다 어떤 객체들이 필요한지 고민하라
- 객체를 독립적인 존재가아닌 협력하는 공동체의 일원으로 봐야한다. 이는 설계를 유연하고 확장 가능하게 만든다.
도메인
- 뜻
- 문제를 해결하기 위해 사용자가 프로그램을 사용하는 분야
- 예시
- 영화 예매를 쉽고 빠르게 위해 영화 예매 시스템을 사용한다.
클래스 구현
좋은 클래스를 설계할 때 중요한 핵심은 어떤 부분을 공개(public
)하고 어떤 부분을 감출지(private
) 결정하는 것이다. 그 경계가 객체의 자율성을 보장하기 때문이다.
자율적인 객체
객체의 내부 외부를 분리하지 않으면 자율성이 떨어지고 이는 설계와 유지보수를 어렵게만든다.
캡슐화
객체는 상태와 행동을 함께가지는 존재이고 스스로 판단하고 행동하는 자율적인 존재이다. 객체지향은 객체라는 단위안에 데이터와 기능을 묶어 문제를 해결하는 아이디어를 표현한다. 이처럼 데이터와 기능을 객체 내부로 함께 묶는 것을 캡슐화라고한다.
외부에서 접근 가능한 객체의 외부를 public interface 라고 부르며, 외부에서 접근할 수 없는 내부를 implementation(구현) 이라고 부른다. 이 둘의 분리는 객체지향 프로그램의 핵심 원리이다.
클래스 작성자는 클래스를 사용하는 클라이언트 프로그래머가 쉽게 내부에 접근할 수 없도록 구현부를 외부에 노출하지 않는다. 이는 추후 수정이 있을 때 클라이언트 프로그래머에 가는 영향을 걱정하지 않고 수정할 수 있게 해준다. 이를 implementation hiding(구현 은닉)이라고 부른다.
협력하는 공동체
의미를 좀 더 명시적이고 분명하게 표현할 수 있으면, 객체를 사용해서 해당 개념을 구현하자. 간단한 변수일지라도 명시적으로 표현된 부분들은 설계의 명확성과 유연성을 높여준다.
객체는 다른 객체와 공개된 인터페이스를 통해 소통한다. 이때 다른 객체에 공개된 행동을 수행하라고 하는 부분을 요청이라고하고, 요청 당한 객체가 그에 대한 답을 보내주는것을 응답이라고한다. 프론트엔드와 백엔드와 비슷하다. 서로 주고받는 내용을 메시지라고 하며, 수신된 메시지를 처리하기 위한 각 객체들의 방법을 메서드라고 부른다.
설계가 유연해질수록 코드는 이해하기 어렵고 디버깅하기 어려지게된다. 훌륭한 객체지향을 하기 위해서는 유연성과 가독성 사이에서 고민해야한다.
다형성
- 자식 클래스가 부모 클래스를 대신하는 것을 업캐스팅이라고 부른다.
DiscountPoilcy
와AmountDisCountPolicy
,PercentDisCountPolicy
들의 관계 Movie
클래스는 동일한 메시지를 전송하지만, 전달받은 메시지(Policy)에 따라 내부 로직(메서드)이 돌아간다. 이를 다형성이라고 부른다.- 다형성을 구현하기 위해서는 실행되는 메서드가 결정되는 시점이 컴파일 시점이 아닌 실행 시점이여야한다. 이를 동적바인딩이라고 한다.
트레이드오프
다형성을 통해 클래스를 설계하는 경우, 코드의 일관성을 유지할 수 있다는 장점이 있지만 가독성이 떨어질 수 있다는 단점이 있다. 모든것에는 정답이 없고 트레이드 오프가 있을 뿐이다. 고민하고 트레이드 오프해야한다.
합성
상속은 객체지향에서 코드를 재활용하기 위해 널리 사용된다. 하지만 설계 관점에서는 캡슐화를 위반하고 설계를 유연하지 못하게 만든 다는 단점이 있다. 자식이 부모를 지나치게 많이 알아야하기 때문이다. 또한 부모 클래스와 자식 클래스 사이의 관계를 컴파일 시점에 결정한다. 합성은 인터페이스에 정의된 메시지를 통해서만 코드를 재사용하는 방법이다. 부모 클래스로써 확장하여 사용하지 않고 멤버변수로 두어 사용한다.