[Java] 상태 패턴 (State Pattern)

2025. 10. 24. 19:15Dev./Java

728x90
반응형

상태 패턴이란

  • 객체가 상태에 따라 다른 행동을 해야 할 때 사용하는 디자인 패턴
  • 상태를 객체로 캡슐화해서 상태 전환과 행동을 독립적으로 관리
  • 조건문 (if / switch)을 최소화할 수 있음
  • 객체가 여러 상태를 갖고있고 상태별로 행동이 다를때나, 상태가 자주바뀌고 상태별 로직이 길어서 조건문이 지저분할 때도 사용가능

구성 요소

구성 요소 역할
Context 상태를 가진 객체
State Interface 상태 인터페이스/추상 클래스
ConcreteState 각 상태 구현

장점

  • 조건문 최소화 → 코드가 깔끔
  • 상태별 행동 캡슐화 → 유지보수 용이
  • 새로운 상태 추가 용이

단점

  • 상태 클래스가 많아질 수 있음 → 관리 필요
  • 상태 전환 로직이 복잡하면 Context가 상태를 지나치게 알게 됨

적용

간단한 기능이라 기본적인 상태패턴 규칙처럼 클래스로 나누어 적용하지 않았다. 

public enum StateEnum{
    START(Kiosk::handleStartState),
    MAIN_MENU(Kiosk::handleMainMenuState),
    SUB_MENU(Kiosk::handleSubMenuState),
    EXIT(Kiosk::handleExitState);

    private final Consumer<Kiosk> handler;
    StateEnum(Consumer<Kiosk> handler) { this.handler = handler; }

    @Override
    public void run(Kiosk kiosk) { handler.accept(kiosk); }
}

// Context
public class Kiosk {
    private State currentState;
    private final List<Menu> menuList;

    public void start() {
        while(currentState != StateEnum.EXIT) {
            currentState.run(this);
        }
    }
}
  • enum State
    • START, MAIN_MENU, SUB_MENU, EXIT 총 4개의 상태 정의.
    • 각 상태는 Kiosk의 특정 메서드를 실행하도록 연결됨.
    • enum 안에서 상태별 동작을 직접 구현하지 않고 메서드 참조를 활용.
    • 예) currentState가 START 일때 Kiosk 객체가 있다면 Kiosk의 handleStartState메서드를 참조해
  • Consumer<Kiosk> handle
    • 함수형 인터페이스 Consumer :  단 하나의 입력 매개변수를 받아 소비하지만 아무 값도 반환하지 않는 역할
    • Consumer를 활용해 Kiosk 객체 → void 형태의 메서드를 참조.
    • 상태마다 어떤 동작을 할지 연결하는 역할.
  • run(Kiosk kiosk)
    • 현재 상태에서 Kiosk 객체를 받아, handle에 연결된 메서드를 실행.
    • 상태 전환 로직은 Kiosk 내부에서 currentState를 바꾸면서 진행.

 

기존 클래스의 이너클래스에서 enum을 활용해 상수로 상태를 전환하고 있다가 구현 메소드가 점점 커지면서 방향을 찾다가 상태패턴을 적용해 보았다. 처음에는 완전히 결합도를 낮춰서 클래스로 상태 패턴을 적용해보았는데 프로젝트 규모와도 맞지않았고 무엇보다도 깊은참조 문제와 인덱스 꼬임이 있어 오히려 지저분한 코드가 되었다고 판단해 라이트하게 적용시켜보았다.

상태별로 메소드 분리를 진행하며 확실히 가독성이 많이 좋아졌고 코드 의존성도 낮아졌다. 앞으로 장바구기 기능을 추가하더라도 구현 메서드 자체는 건들지 않고 새로운 상태메소드만 추가해 유지보수가 용이해졌다.

 

 

728x90
반응형