Menu
Coddy logo textTech

상태 패턴

Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 87개 중 74번째.

State Pattern은 객체의 내부 상태가 변경될 때 객체가 동작을 변경할 수 있도록 하는 행동 디자인 패턴입니다. 객체의 클래스가 변경되는 것처럼 보이지만, 실제로는 동작을 서로 다른 상태 객체에 위임합니다. 자판기를 생각해 보세요. 버튼을 눌렀을 때의 반응은 자판기가 유휴 상태인지, 돈이 투입되었는지, 또는 제품을 배출 중인지에 따라 달라집니다.

서로 다른 상태를 처리하기 위해 복잡한 조건문을 사용하는 대신, 각 상태를 자체 클래스에 캡슐화합니다. 이 패턴에는 current 상태에 대한 참조를 유지하는 Context와 각 상태에 대한 동작을 정의하는 상태 클래스가 포함됩니다:

interface State {
    void handle(Context context);
}

class Context {
    private State state;
    
    public void setState(State state) {
        this.state = state;
    }
    
    public void request() {
        state.handle(this);
    }
}

각 concrete state는 동작을 구현하며 다른 state로의 전환을 트리거할 수 있습니다:

class IdleState implements State {
    public void handle(Context context) {
        System.out.println("Idle: Insert coin to start");
        context.setState(new ActiveState());
    }
}

class ActiveState implements State {
    public void handle(Context context) {
        System.out.println("Active: Processing...");
        context.setState(new IdleState());
    }
}

context는 요청을 current state에 delegates하고, state가 changes함에 따라 동작이 자동으로 changes합니다:

Context context = new Context();
context.setState(new IdleState());

context.request();  // Idle: 시작하려면 동전을 넣으세요
context.request();  // Active: 처리 중...

상태 패턴은 객체의 동작이 상태에 크게 의존하고 런타임에 변경되어야 할 때 이상적입니다. 이 패턴은 큰 조건문 블록을 없애고 새로운 상태를 간단하게 추가할 수 있도록 합니다. State 인터페이스를 구현하는 새로운 클래스를 만들기만 하면 됩니다.

challenge icon

챌린지

쉬움

State Pattern을 사용하여 문서 workflow 시스템을 만들어 봅시다! 문서가 Draft, Review, Published라는 여러 단계를 거치는 방식을 모델링하는 시스템을 만들게 됩니다. 각 state는 어떤 action을 사용할 수 있는지와 문서를 edit하거나 approve하려고 할 때 문서가 어떻게 동작하는지를 결정합니다.

코드를 네 개의 파일로 구성합니다:

  • DocumentState.java: 모든 state가 구현할 DocumentState 인터페이스를 Define합니다. 두 개의 메서드를 Declare해야 합니다. 문서의 edit을 시도하는 edit(Document doc)과 문서를 다음 단계로 approve하거나 진행하려는 approve(Document doc)입니다.
  • States.java: DocumentState를 구현하는 세 개의 concrete state 클래스를 Create합니다:

    DraftState - edit가 call되면 Editing draft...를 출력합니다. approve가 call되면 Draft approved. Moving to review.를 출력하고 문서를 ReviewState로 전환합니다.

    ReviewState - edit가 call되면 Cannot edit during review.를 출력합니다(state change 없음). approve가 call되면 Review complete. Publishing document.를 출력하고 PublishedState로 전환합니다.

    PublishedState - edit가 call되면 Cannot edit published document.를 출력합니다. approve가 call되면 Document already published.를 출력합니다. 어느 action도 state를 변경하지 않습니다.

  • Document.java: current state를 유지하는 context 클래스를 Create합니다. Document에는 다음이 있어야 합니다:

    current DocumentState를 보유하는 private field. Constructor에서 DraftState로 초기화됩니다.

    current state를 변경하는 setState(DocumentState state) 메서드.

    current state의 edit 메서드에 delegates하는 edit() 메서드.

    current state의 approve 메서드에 delegates하는 approve() 메서드.

    current state의 simple class name을 반환하는 getStatus() 메서드(getClass().getSimpleName() 사용).

  • Main.java: state 시스템을 Demonstrate합니다! 하나의 input을 받습니다. 각 action이 edit 또는 approve 중 하나인 comma-separated 문자열 형태의 action sequence입니다(예: edit,approve,edit,approve).

    Document를 Create하고 Status: [state] 형식으로 initial status를 출력합니다. 그런 다음 각 action을 순서대로 처리하며, document에서 적절한 메서드를 call합니다. 각 action 후에 current status를 출력합니다.

하나의 input을 받습니다. comma-separated action 문자열입니다.

예를 들어 input이 edit,approve,approve인 경우 output은 다음과 같습니다:

Status: DraftState
Editing draft...
Status: DraftState
Draft approved. Moving to review.
Status: ReviewState
Review complete. Publishing document.
Status: PublishedState

동일한 approve() call이 document의 current state에 따라 서로 다른 결과를 생성하는 것을 확인하세요. 이것이 State Pattern의 핵심입니다! document는 state를 확인하기 위해 conditional을 사용하지 않습니다. 대신 current state object에 behavior를 delegate하고, 해당 object가 action을 적절히 처리하며 필요한 경우 transition을 trigger합니다.

직접 해보기

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: 새로운 Document 생성
        
        // TODO: "Status: [state]" 형식으로 초기 상태 출력
        
        // TODO: 쉼표로 입력을 분할하여 개별 동작 가져오기
        
        // TODO: 각 동작에 대해 반복문 실행
        // - 동작이 "edit"이면 document에서 edit() 호출
        // - 동작이 "approve"이면 document에서 approve() 호출
        // - 각 동작 후 현재 상태 출력
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Java 컴파일러