반응형
오브젝트 14 - 일관성 있는 협력
14.1 핸드폰 과금 시스템 변경하기
14.1.1 기본 정책 확장
- 핸드폰 과금 시스템을 4가지 방식으로 확장해보자
- 새롭게 구현할 클래스 구조는 아래와 같다.
14.1.2 고정요금 방식 구현하기
- 고정 요금 방식은 기존의 일반요금제와 동일하므로 기존 RegularPolicy 클래스 이름을 FixedFeePolicy로 수정하면 된다.
14.1.3 시간대별 방식 구현하기
- 날짜별로 요금을 분리 후, 시간대별로 요금을 구해야한다.
- 시간대별 방식을 구현하는데 핵심은 규칙에 따라 통화 시간을 분할하는 방법을 결정하는 것이다.
- 이를 위해 DateTimeInterval 클래스를 추가하자
public class DateTimelnterval {
private LocalDateTime from;
private LocalDateTime to;
public static DateTimelnterval of(LocalDateTime from, LocalDateTime to) {
return new DateTimelnterval(from, to);
}
}
- 요금 계산 로직은 아래와 같이 두 단계로 나뉘어 구현될 것이다.
- 통화 기간을 일자별로 분리한다.
- 일자별로 분리된 기간을 다시 시간대별 규칙에 따라 분리한 후 각 기간에 대해 요금을 계산한다.
- 시간대별 방식을 담당한 개발자는 이 문제를 4개의 서로 다른 List를 가지는 것으로 해결했다.
public class TimeOfDayDiscountPolicy extends BasicRatePolicy {
private List<LocalTime> starts = new Arraylist<>();
private List<LocalTime> ends = new ArrayList<>();
private List<Duration> durations = new ArrayList<>();
private List<Money> amounts = new ArrayList<>();
}
14.1.4 요일별 방식 구현하기
- 요일별 방식은 요일별로 요금 규칙을 다르게 설정할 수 있다.
- 각 규칙은 요일의 목록, 단위 시간, 단위 요금이라는 세가지 요소로 구성된다.
- 시간대별 방식을 개발한 프로그래머는 4개의 List를 이용했지만, 요일별 방식을 개발하는 프로그래머는 규칙을 DayOfWeekDiscountRule 이라는 하나의 클래스로 구현하는 것이 더 나은 설계라고 판단했다.
public class DayOfWeekDiscountRule {
private List<DayOfWeek> dayOfWeeks = new Arraylist<>();
private Duration duration = Duration.ZERO;
private Money amount = Money.ZERO;
.
.
.
}
- 요일별 방식 역시 통화 기간을 날짜별로 분리하고, 각 통화 기간을 요일별로 설정된 요금 정책에 따라 계산해야한다.
14.1.5 구간별 방식 구현하기
- 지금까지 구현한 세 클래스는 로직을 정확하게 구현하고 있고, 응집도와 결합도 측면에서 문제가 없어보인다.
- 그러나 현재 구현의 가장 큰 문제점은 이 클래스들이 유사한 문제를 해결하고 있음에도 불구하고 설계에 일관성이 없다는 것이다.
- 비일관성은 두가지 상황에서 발목을 잡는다.
- 새고운 구현을 추가해야하는 상황
- 기존의 구현을 이해해야 하는 상황
- 대부분의 사람들은 유사한 요구사항을 구현하는 코드는 유사한 방식으로 구현될 것이라고 예상한다.
- 그러나 유사한 요구사항이 서로 다른 방식으로 구현돼 있다면 요구사항이 유사하다는 사실 자체도 의심할 것이다.
- 그러므로 유사항 기능은 유사한 방식으로 구현해야 한다.
14.2 설계에 일관성 부여하기
- 일관성 있는 설계를 만드는데 가장 좋은 방법은 다양한 설계 경험을 익히는 것이다.
- 디자인 패턴을 학습하면 빠른 시간 안에 전문가의 경험을 흡수할 수 있다.
- 디자인 패턴이란 : 특정한 변경에 대해 일관성 있는 설계를 만들수 있는 경험 법칙을 모아놓은 일종의 템플릿
- 협력을 일관성 있게 만들기 위해 다음과 같은 기본 지침을 따르면 도움이 된다.
- 변하는 개념을 변하지 않는 개념으로부터 분리하라.
- 변하는 개념을 캡슐화하라.
14.2.1 조건 로직 대 객체 탐색
- 정책을 조건 로직으로 구현할 경우 새로운 정책을 추가하기 위해서는 기존 코드를 수정해야해 오류의 발생 확률이 높다.
- 반면 객체지향에서 변경을 다루는 전통적인 방법은 조건 로직을 객체 사이의 이동으로 바꾸는 것익다.
- 단순히 현재의 할인 정책을 나타내는 객체에 필요한 메시지를 전달할 뿐이다.
- 클라이언트는 단지 객체가 자신의 요청을 잘 처리해줄것이라고 믿고 메시지를 전송한다.
- Movie는 현재의 할인 정책이 어떤 종류인지 판단하지 않는다.
- 단지 DiscountPolicy로 향하는 참조를 통해 메시지를 전달할 뿐이다.
- 할인 정책의 구체적인 종류는 메시지를 수신한 객체의 타입에 따라 달라지며 실행할 메서드를 결정하는 것은 메시지를 수신한 객체의 책임이다.
- 조건 로직을 객체 사이의 이동으로 대체하기 위해서는 커다란 클래스를 더 작은 클래스들로 분리해야 한다.
- 클래스를 분리하는데 가장 중요한 기준은 변경의 이유와 주기이다.
- 협력을 일관성 있게 만들기 위해서 따라야 하는 지침들은 아래와 같다.
- 변하는 개념을 변하지 않는 개념으로부터 분리하라.
- 변하는 개념을 캡슐화하라.
14.2.2 캡슐화 다시 살펴보기
- 데이터 은닉이란 오직 외부에 공개된 메서드를 통해서만 객체의 내부에 접근할 수 있게 제한함으로써 객체의 내부 상태 구현을 숨기는 기법이다.
- 많은 사람들은 캡슐화에 대한 이야기를 들으면 데이터 은닉을 떠올리지만, 캡슐화는 데이터 은닉 이상이다.
- 캡슐화란 단순히 데이터를 감추는것이 아니라 소프트웨어 안에서 변할 수 있는 모든 개념을 감추는 것이다.
- 일반적으로 데이터 캡슐화와 메서드 캡슐화는 개별 객체에 대한 변경을 관리하기 위해 사용한다.
- 객체 캡슐화와 서브타입 캡슐화는 협력에 참여하는 객체들의 관계에 대한 변경을 관리하기 위해 사용한다.
728x90
반응형
'스터디 > 오브젝트' 카테고리의 다른 글
오브젝트 15 - 디자인 패턴과 프레임워크 (0) | 2024.04.16 |
---|---|
오브젝트 13 - 서브클래싱과 서브타이핑 (0) | 2024.04.09 |
오브젝트 12 - 다형성 (0) | 2024.04.02 |
오브젝트 11 - 합성과 유연한 설계 (0) | 2024.03.26 |
오브젝트 10 - 상속과 코드 재사용 (0) | 2024.03.26 |
댓글