Eternity's Chit-Chat

aeternum.egloos.com



유연한 설계를 위한 패턴과 원리 - 4.잃어버린 시간을 찾아서 5부 Supple Design

이제 구현이다!
DayOfYear를 TimePoint로 변환하는 asTimePoint()부터 시작하자. asTimePoint() 메소드는 표준 시간대를 표현하는 TimeZone을 파라미터를 사용해 GMT에서의 TimePoint 값으로 변환한다.

DayOfYear.java
public
TimePoint asTimePoint(TimeZone zone) {
  return TimePoint.atMidnight(year, month, day, zone);
}

TimePoint를 DayOfYear로 변환하는 것은 간단하다. Java.util.Calendar의 기능을 사용해서 해당 표준 시간대의 연, 월, 일 정보를 구하고 이를 DayOfYear의 CREATION METHOD에 파라미터로 전달하면 된다.

TimePoint.java
public
DayOfYear asDayOfYear(TimeZone timeZone) {
  Calendar calendar = asCalendar(timeZone);
  return DayOfYear.at(calendar.get(Calendar.YEAR), 
   
calendar.get(Calendar.MONTH)+1, 
   
calendar.get(Calendar.DAY_OF_MONTH));

}

public
Calendar asCalendar(TimeZone timeZone) {
  Calendar calendar = Calendar.getInstance(timeZone);
  calendar.setTimeInMillis(miliseconds);
  return calendar;
}

MomentOfYear는 DayOfYear와 TimeOfDay 모두를 포함하는 클래스로 특정 일자의 특정 시간을 표현한다. MomentOfYear는 정수형 연, 월, 일, 시, 분을 파라미터로 받는 메소드와 DayOfYear와 TimeOfDay를 파라미터로 받는 메소드를 제공한다.

MomentOfYear.java
private
final DayOfYear dayOfYear;
private final TimeOfDay timeOfDay;

public
static MomentOfYear at(int year, int month, int day,
int hour, int minute) {
  return at(DayOfYear.at(year, month, day), TimeOfDay.at(hour, minute));
}

public
static MomentOfYear at(DayOfYear dayOfYear,
TimeOfDay timeOfDay) {
  return new MomentOfYear(dayOfYear, timeOfDay);
}

private
MomentOfYear(DayOfYear dayOfYear,
TimeOfDay timeOfDay) {
  this.dayOfYear = dayOfYear;
  this.timeOfDay = timeOfDay;
}

public
DayOfYear dayOfYear() {
  return dayOfYear;
}

public
TimeOfDay timeOfDay() {
  return timeOfDay;
}

DayOfYear와 TimeOfDay처럼 MomentOfYear 역시 각 인스턴스 간의 시간적인 선후 관계를 가진다. 앞에서 살펴본 패턴과 동일하게 Comparable을 실체화하도록 클래스 정의를 수정하고 isBefore(), isAfter(), equals(), hashCode(), compareTo() 메소드를 구현한다. 이 메소드들을 구현하기 위해 DayOfYear와 TimeOfHour에 구현되어 있는 기존 메소드들을 사용하여 짧은 양의 코드만으로도 원하는 기능을 구현했음에 주목하자.

MomentOfYear.java
public
class MomentOfYear
implements Comparable<MomentOfYear> {
  ......
  public boolean isBefore(MomentOfYear other) {
    if (dayOfYear.isBefore(other.dayOfYear)) {
      return true;
    }

    if (dayOfYear.isAfter(other.dayOfYear)) {
      return false;
    }

    if
(timeOfDay.isBefore(other.timeOfDay())) {
      return true;
    }

    return
false;
  }

  public
boolean isAfter(MomentOfYear other) {
    return !isBefore(other) && !equals(other);
  }

  public
int compareTo(MomentOfYear other) {
    if (isBefore(other)) {
      return -1;
    }

    if
(isAfter(other)) {
      return 1;
    }

    return 0;
  }
}


MomentOfYear를 생성할 수 있으므로 TimeOfDay를 파라미터로 받는 CREATION METHOD를DayOfYear에 추가할 수 있다. DayOfYear의 CREATION METHOD는 앞에서 추가한 MomentOfYear의 CREATION METHOD를 사용하여 간단하게 구현할 수 있다.
 
DayOfYear.java
public
MomentOfYear at(TimeOfDay timeOfDay) {
  return MomentOfYear.at(this, timeOfDay);
}

TimeOfDay 역시 동일한 방법으로 DayOfYear를 인자로 받아 MomentOfYear를 생성하는 메소드를 추가할 수 있다.

TimeOfDay.java
public
MomentOfYear on(DayOfYear dayOfYear) {
  return MomentOfYear.at(dayOfYear, this);
}

이제 TimePoint를 원하는 표준 시간대의 MomentOfYear로 변환하는 작업만 남아 있다. TimeZone을 파라미터로 받는 asTimeOfDay() CONVERSTION METHOD를 추가하고 asMomentOfYear() 메소드에서 asDayOfYear()와 asTimeOfDay()를 사용해서 MomentOfYear를 생성한 후 반환한다.

TimePoint.java
public
MomentOfYear asMomentOfYear(TimeZone timeZone) {

  return MomentOfYear.at(asDayOfYear(timeZone), asTimeOfDay(timeZone));

}

 

public TimeOfDay asTimeOfDay(TimeZone timeZone) {

  Calendar calendar = asCalendar(timeZone);

  return TimeOfDay.at(calendar.get(Calendar.HOUR_OF_DAY),

    calendar.get(Calendar.MINUTE),

    calendar.get(Calendar.SECOND),

    calendar.get(Calendar.MILLISECOND));

}

 

MomentOfYear를 TimePoint로 변환하는 것도 간단하다.

MomentOfyear.java
public
TimePoint asTimePoint(TimeZone zone) {

  return TimePoint.at(dayOfYear, timeOfDay, zone);

}

 

DayOfYear와 TimeOfDay대신 MomentOfYear를 사용해서 TimePoint를 생성할 수도 있다. 구현은 간단하게 MomentOfYear에서 DayOfYear와 TimeOfDay를 추출해서 다른 at() 메소드로 위임하면 된다.

 

TimePoint.java
public
static TimePoint at(MomentOfYear momentOfYear, TimeZone zone) {

  return at(momentOfYear.dayOfYear(), momentOfYear.timeOfDay(), zone);

}

 

모든 표현식 구현이 끝났다. TimePoint, MomentOfYear, DayOfYear, TimeOfDay 간의 관계를 명시적인 메소드로 구현함으로써 코드의 추상화 레벨을 한 단계 높일 수 있게 되었으며 결과적으로 더 읽기 쉽고 이해하기 쉬운 코드를 만들게 되었다.