클라이언트가 우리의 불변식을 깨뜨리려 혈안이 되어 있다고 가정하고 방어적으로 프로그래밍을 해야 함

문제 상황1

public final class Period {
  private final Date start;
  private final Date end;

  /**
  * @param start 시작 시각
  * @param end 종료 시각. 시작 시각보다 뒤여야 한다.
  * @throws IllegalArgumentException 시작 시각이 종료 시각보다 늦을 때 발생한다.
  * @throws NullPointerException start나 end가 null이면 발생한다. 
  */
  public Period(Date start, Date end) { 
    if (start.compareTo(end) > 0)
      throw new IllegalArgumentException(
      start + " after " + end);
    this.start = start;
    this.end = end; 
  }

  public Date start() {
    return start; 
  }
  public Date end() {
    return end; 
  }
... // 나머지 코드 생략 
}

해결 방법

  1. 자바8 이상이라면 Date 대신 불변 Instant(혹은 LocalDateTime, ZonedDateTime)를 사용할 수 있음

    → 모두 불변으로 설계되어있음

  2. 방어적 복사

    public Period(Date start, Date end) {
      this.start = new Date(start.getTime());
      this.end = new Date(end.getTime());
    
      if (this.start.compareTo(this.end) > 0)
        throw new IllegalArgumentException(
        	this.start + " after " + this.end);
    }
    

문제상황2

Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
p.end().setYear(78); // p의 내부를 변경

해결방법

public Date start() {
  return new Date(start.getTime()); 
}
public Date end() {
  return new Date(end.getTime()); 
}

매개변수를 방어적으로 복사하는 목적