문제 발생

금나와라뚝딱(이하 금뚝)의 Event 엔티티는 Ready Running Closed 세가지의 상태를 가질 수 있다. 이벤트는 Ready 상태로 시작해서 이벤트 오픈시간이 되면 Running 상태로 바뀌고 선물 재고가 없거나 종료시간이 되면 Closed 상태로 변경된다. 하지만 분명 Closed된 Event 엔티티가 자꾸 Running 상태로 변경되는 문제가 발생했다.

원인은?

프로젝트 초기에 이벤트 상태 갱신 방법을 고민했는데, 결과적으로 배치를 이용하는것 대신 Event 엔티티 조회 API를 호출할때 상태를 갱신하도록 정했다. 그래서 renewStatus() 라는 메서드를 작성했다.

처음에 금뚝의 이벤트 종료 조건은 시간만 있었는데 요구사항이 변경되어서 선물 재고 조건도 추가되었다. 하지만 실수로 renewStatus()에 관련 로직 추가를 안해서 문제가 되었다.

그래서 renewStatus() 메서드에 종료 조건을 추가하고 상태 변경이 잘못되지 않도록 로직을 조정함으로써 문제를 해결했다.

초기의 renewStatus 메서드의 모습

public class Event {
		
		private EventProgressStatus eventProgressStatus;

		//...

		public void renewStatus() {
		    if (startAt.isAfter(LocalDateTime.now())) {
		        eventProgressStatus = EventProgressStatus.READY;
		        return;
		    }
		    if (startAt.isEqual(LocalDateTime.now()) || (startAt.isBefore(LocalDateTime.now()) && endAt.isAfter(
		        LocalDateTime.now()))) {
		        eventProgressStatus = EventProgressStatus.RUNNING;
		        return;
		    }
		    if (endAt.isEqual(LocalDateTime.now()) || endAt.isBefore(LocalDateTime.now())){
		        eventProgressStatus = EventProgressStatus.CLOSED;
		    }
		}
}

남아있는 문제점

문제는 임시방편으로 해결했지만 다음과 같은 문제가 남아있다.

  1. 이벤트 상태 변경 조건이 추가되면 renewStatus() 메서드를 다시 해석해서 로직을 추가하는 작업을 해야 한다. renewStatus() 메서드는 갈 수 록 복잡해질 것 이다.
  2. 로직 순서를 잘 못 설정하면 원하지 않는 상태 변경이 일어날 수 있다.

그래서 이를 해결하기 위해선 renewStatus()가 가지고 있는 **상태 변경 로직을 분리**하고 **구조적으로 상태간의 변경을 제어**할 수 있는 무언가가 필요했다.

상태패턴을 적용해보자!

상태패턴의 특징 [참고]

  1. 객체의 상태에 따라 기능의 동작을 변경시킨다.
    1. 전원 버튼을 눌렀을때 ON 상태면 전원을 끄고 OFF 상태면 전원을 킨다.
    2. 플레이 버튼을 눌렀을때 플레이중이라면 일시정지를 하고 일시정지 상태면 다시 플레이 한다.