일관성 있는 협력 패턴을 적용하면 작성한 코드가 이해하기 쉽고 직관적이며 유연해진다.

기본 정책 확장

11장에서 구현한 핸드폰 과금 시스템의 요금 정책을 수정하자. 기본 정책에는 일반 요금제와 심야 할인 요금제 두가지 가 있었다.

기본정책 4가지 방식

  1. 고정요금 방식
    1. 일정 시간 단위로 동일한 요금을 부과하는 방식이다.
  2. 시간대별 방식
    1. 하루 24시간을 특정한 시간 구간으로 나눈후 각 구간별로 서로 다른 요금을 부과하는 방식
  3. 요일별 방식
    1. 요일별로 요금을 차등 부과하는 방식
  4. 구간별 방식
    1. 전체 통화 시간을 일정한 통화시간에 따라 나누고 각 구간별로 요금을 차등 부과하는 방식.

Untitled

고정 요금 방식 구현

public class FixedFeePolicy extends BasicRatePolicy {
	private Money amount;
	private Duration seconds;
	
	public FixedFeePolicy(Money amount, Duration seconds) {
		this.amount = amount;
		this.secound = seconds;
	}
	
	@Override
	protected Money calculateCallFee(Call call) {
		return amount.times(call.getDuration().getSeconds() / seconds.getSeconds());
	}
}

시간대별 방식 구현하기

시간대별 방식의 통화 요금을 계산하기 위해서는 통화의 시작 시간과 종료 시간 뿐만 아니라 시작 일자와 종료 일자도 함께 고려해야 한다.

public class DateTimeInterval {
	private LocalDateTime from;
	private LocalDateTime to;
	
	public static DateTimeInterver of (LocalDateTime from, LocalDateTime to) {
		return new DateTimeInterval(from, to);
	}
	
	public static DateTimeInterval toMidnight(LocalDateTime from) {
		return new DateTimeInterval(
			from ,
			LocalDateTime.of(to.toLocalDate(), LocalTime.of(23,59,59));
	}
	
	public static DateTimeInterval fromMidnight(LocalDateTime to) {
		return new DateTimeInterval(
			LocalDateTime.of(to.toLocalDate(), LocalTime.of(0,0)),
			to);
	}
	
	public static DateTimeInterval during(LocalDate date) {
		return new DateTimeInterval (
			LocalDateTime.of(to.toLocalDate(), LocalTime.of(0,0)),
			LocalDateTime.of(to.toLocalDate(), LocalTime.of(23,59,59));
		)
	}
	
	private DateTimeInterval(LocalDateTime from, LocalDateTime to) {
		this.from = from;
		this.to = to;
	}
	
	public Duration duration(){
		return Duration.between(from, to);
	}
	
	public LocalDateTime getFrom(){
		return from;
	}
	
	public LocalDateTime getTo(){
		return to;
	}
}
public class Call {
	private DateTimeInterval interval;
	
	public Call(LocalDateTime from, LocalDateTiem to) {
		this.interval = DateTimeInterval.of(from, to);
	}
	
	public Duration getDuration(){
		public interval.duration();
	}
	
	public LocalDateTime getFrom() {
		return interval.getFrom();
	}
	
	public LocalDateTime getTo() {
		return interval.getTo();
	}
	
	public DateTimeInterval getInterval(){
		return interval;
	}
}

요금 계산 로직은 크게 두 단계로 나뉜다.

  1. 통화 기간을 일자별로 분리한다.
  2. 일자별로 분리된 기간을 다시 시간대별 규칙에 따라 분리한 후 각 기간에 대해 요금을 계산한다.

기간을 처리하는 전문가는 DateTimeInterval이니 첫번째 로직은 DateTimeInterval에 위임한다.