Skip to content

일관성 있는 협력

Published: at 오전 05:42

Table of contents

Open Table of contents

개요

핸드폰 과금 시스템 변경하기

핸드폰 과금 시스템의 요금 정책을 확장한다.

유형형식
고정요금 방식A초당 B원10초당 18원
시간대별 방식A시부터 B시까지 C초당 D원 B시부터 C시까지 C초당 E원00시부터 19시까지 10초당 18원 19시부터 24시까지 10초당 15원
요일별 방식평일에는 A초당 B원 공휴일에는 A초당 C원평일에는 10초당 38원 공휴일에는 10초당 19원
구간별 방식초기 A분 동안 B초당 C원 A분 ~ D분까지 B초당 D원 D분 초과 시 B초당 E원초기 1분 동안 10초당 50원 초기 1분 이후 10초당 20원

img.png

고정요금 방식 구현하기

기존의 일반요금제와 동일하기 때문에 RegularPolicy 클래스의 이름을 FixedFeePolicy로 수정하기만 하면 된다.

시간대별 방식 구현하기

4개의 서로 다른 List를 가지는 방법으로 같은 규칙에 포함된 요소들은 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<>();
};

요일별 방식 구현하기

각 규칙은 요일의 목록, 단위 시간, 단위 요금이라는 세 가지 요소로 구성된다. 요일별 방식을 사용하면 월요일부터 금요일까지는 10초가 38원을, 토요일과 일요일에는 10초당 19원을 부과하는 식으로 요금 정책을 설정할 수 있다.

요일별 방식 역시 통화 기간이 여러 날에 걸쳐있을 수 있기 때문에 시간대별 방식과 동일하게 통화 기간을 날짜 경계로 분리하고 분리된 각 통화 기간을 요일별로 설정된 요금 정책에 따라 적절하게 계산해야 한다.

구간별 방식 구현하기

지금까지 구현한 방식 클래스를 천천히 살펴보자

구현한 세 클래스는 통화 요금을 정확하게 계산하고 있고 응집도와 결합도 측면에서도 특별히 문제는 없어 보인다.

하지만 이 클래스들을 함께 모아놓고 보면 그동안 보이지 않던 문제점이 보이기 시작한다.

현재 구현의 가장 큰 문제점은 유사한 문제를 해결하고 있음에도 불구하고 설계에 일관성이 없다는 것이다. 이 클래스들은 기본 정책을 구현한다는 공통의 목적을 공유한다. 하지만 정책을 구현하는 방식은 완전히 다르다. 개념적으로 연관돼 있지만 구현 방식에 있어서는 완전히 제각각이라는 것이다.

비일관성은 두 가지 상황에서 발목을 잡는다.

유사한 기능은 유사한 방식으로 구현해야 한다.

설계에 일관성 부여하기

협력을 일관성 있게 만들기 위한 기본 지침

애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분으로부터 분리시킨다. 바뀌는 부분을 따로 뽑아서 캡슐화한다. 그렇게 하면 바뀌지 않는 부분에는 영향을 미치지 않은 채로 그 부분만 고치거나 확장할 수 있다.

캡슐화 다시 살펴보기

많은 사람들은 객체의 캡슐화에 관한 이야기를 들으면 반사적으로 데이터 은닉 을 떠올린다.

그러나 캡슐화는 데이터 은닉 이상이다.

GOF의 조언에 따르면 캡슐화란 단순히 데이터를 감추는 것이 아니다. 소프트웨어 안에서 변할 수 있는 모든 개념을 감추는 것이다.

다음과 같은 다양한 종류의 캡슐화가 존재한다.

서브타입 캡슐화와 객체 캡슐화를 적용하는 방법은 다음과 같다.

일관성 있는 기본 정책 구현하기

변경 분리하기

일관성 있는 협력을 만들기 위한 첫 번째 단계는 변하는 개념과 변하지 않는 개념을 분리하는 것이다.

변경 캡슐화하기

-> 규칙을 구현 FeeRule, 적용조건을 구현 FeeCondition

협력 패턴 설계하기

협력은 BasicRatePolicycalculateFee 메시지를 수신했을 때 시작된다. BasicRatePolicycalculateFee 메서드는 인자로 전달받은 통화목록 (List〈Call〉 타입)의 전체 요금을 계산한다. BasicRatePolicy는 목록에 포함된 각 Call별로 FeeRulecalculateFee 메서드를 실행한다. 하나의 BasicRatePolicy는 하나 이상의 FeeRule로 구성되기 때문에 Call 하나당 FeeRule 에 다수의 calculateFee 메시지가 전송된다.

img.png