본문으로 건너뛰기
객체지향 설계 · 디자인 패턴LESSON 10

State 패턴: 상태가 늘어나는 흐름 다루기

난이도중급 → 심화
예상 시간65분
선수지식이전 강의

10강. State 패턴: 상태가 늘어나는 흐름 다루기

1. 이번 강의에서 해결할 문제​

상태별 if가 모든 메서드에 흩어지면 새 상태 하나가 여러 switch를 수정하게 합니다.

2. 학습 목표​

3. 핵심 개념​

State는 현재 상태가 행동과 다음 전이를 결정하게 합니다. Strategy와 구조는 비슷하지만 State는 시간에 따른 전이 책임, Strategy는 교체 가능한 정책이 목적입니다. 상태가 적고 닫혀 있으면 enum switch가 더 단순합니다.

상태 전이는 단순 값 변경이 아니라 “현재 상태에서 이 행동을 허용하는가”라는 규칙입니다. Todo → InProgress → Completed는 허용하지만 Todo → Completed는 거부할 수 있습니다. 이 규칙이 여러 메서드의 switch에 반복될 때 State 객체가 각 상태의 허용 행동과 다음 상태를 맡습니다.

4. 가장 작은 예제로 시작하기​

main.cpp
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string_view>

class TaskState {
public:
virtual ~TaskState() = default;
virtual std::unique_ptr<TaskState> start() const = 0;
virtual std::unique_ptr<TaskState> complete() const = 0;
virtual std::string_view name() const noexcept = 0;
};

class InProgressState;
class CompletedState;

class TodoState final : public TaskState {
public:
std::unique_ptr<TaskState> start() const override;
std::unique_ptr<TaskState> complete() const override {
throw std::logic_error("Todo는 바로 완료할 수 없습니다.");
}
std::string_view name() const noexcept override { return "Todo"; }
};

class InProgressState final : public TaskState {
public:
std::unique_ptr<TaskState> start() const override {
throw std::logic_error("이미 진행 중입니다.");
}
std::unique_ptr<TaskState> complete() const override;
std::string_view name() const noexcept override { return "InProgress"; }
};

class CompletedState final : public TaskState {
public:
std::unique_ptr<TaskState> start() const override {
throw std::logic_error("완료 작업은 다시 시작할 수 없습니다.");
}
std::unique_ptr<TaskState> complete() const override {
throw std::logic_error("이미 완료됐습니다.");
}
std::string_view name() const noexcept override { return "Completed"; }
};

std::unique_ptr<TaskState> TodoState::start() const {
return std::make_unique<InProgressState>();
}

std::unique_ptr<TaskState> InProgressState::complete() const {
return std::make_unique<CompletedState>();
}

class Task {
std::unique_ptr<TaskState> state_ = std::make_unique<TodoState>();
public:
void start() { state_ = state_->start(); }
void complete() { state_ = state_->complete(); }
std::string_view status() const noexcept { return state_->name(); }
};

int main() {
Task task;
std::cout << task.status() << '\n';
task.start();
std::cout << task.status() << '\n';
task.complete();
std::cout << task.status() << '\n';
}

예상 출력: Todo, InProgress, Completed가 차례로 한 줄씩 출력됩니다.

5. 코드가 동작하는 이유​

Task는 현재 상태를 unique_ptr로 하나만 소유합니다. start()의 오른쪽 전이 함수가 성공해 새 객체를 반환한 뒤에만 state_가 교체됩니다. 예외가 나면 대입이 실행되지 않아 기존 상태가 유지됩니다.

변경 전에는 start, complete, cancel마다 상태 switch가 반복됩니다. 변경 후 Todo의 규칙은 TodoState, 진행 중 규칙은 InProgressState에서 찾습니다. 단, 상태가 두 개이고 전이가 고정된 작은 모델에서는 enum과 한 switch가 더 읽기 쉬울 수 있습니다.

6. 자주 하는 실수와 해결법​

7. 직접 실습​

8. 이해 점검 질문 3개​

9. 핵심 요약​

10. 다음 강의 연결​

시간에 따라 바뀌는 전이 규칙을 State로 분리했습니다. 다음 강의에서는 상태 흐름과 무관하게 교체되는 계산 정책을 Strategy로 설계합니다.

MINI QUIZ

State 패턴: 상태가 늘어나는 흐름 다루기 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“State 패턴: 상태가 늘어나는 흐름 다루기” 내용을 실제 작업에 적용한 설명으로 가장 알맞은 것은 무엇인가요?
  2. 문제 2“State 패턴: 상태가 늘어나는 흐름 다루기”에서 ‘예외 뒤에도 상태를 먼저 바꿈’ 문제가 생겼습니다. 가장 알맞은 진단 또는 대응은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

10강. State 패턴: 상태가 늘어나는 흐름 다루기 미완료 상태