Menu
Coddy logo textTech

상태 패턴

Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 110개 중 98번째.

상태 패턴(State pattern)은 객체의 내부 상태가 변경될 때 객체가 행동을 변경할 수 있도록 허용하여, 마치 객체의 클래스가 바뀐 것처럼 보이게 합니다. 여러 상태를 처리하기 위해 복잡한 조건문을 사용하는 대신, 각 상태를 별도의 클래스로 캡슐화하고 현재 상태 객체에 행동을 위임합니다.

이 패턴은 현재 상태에 대한 참조를 유지하는 Context와 가능한 각 상태에 대한 동작을 정의하는 State 클래스들로 구성됩니다. 컨텍스트의 상태가 변경되면 그 동작도 자동으로 변경됩니다:

abstract class DocumentState {
  void publish(Document doc);
  String getStatus();
}

class DraftState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Moving to review...');
    doc.setState(ReviewState());
  }

  @override
  String getStatus() => 'Draft';
}

class ReviewState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Document published!');
    doc.setState(PublishedState());
  }

  @override
  String getStatus() => 'Under Review';
}

class PublishedState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Already published.');
  }

  @override
  String getStatus() => 'Published';
}

class Document {
  DocumentState _state = DraftState();

  void setState(DocumentState state) => _state = state;
  void publish() => _state.publish(this);
  String getStatus() => _state.getStatus();
}

void main() {
  var doc = Document();
  print(doc.getStatus());  // 초안
  doc.publish();           // 검토 중으로 이동...
  print(doc.getStatus());  // 검토 중
  doc.publish();           // 문서가 게시되었습니다!
  print(doc.getStatus());  // 게시됨
}

각 상태 클래스는 publish() 동작을 다르게 처리하며 문서를 다음 상태로 전환할 수 있습니다. Document 클래스는 현재 상태를 확인하기 위한 조건문이 필요하지 않습니다. 단순히 현재 활성화된 상태 객체에 위임할 뿐입니다. 이 패턴은 주문 처리, 미디어 플레이어 또는 워크플로우 시스템과 같이 뚜렷한 행동 모드를 가진 객체에 이상적입니다.

challenge icon

챌린지

쉬움

상태(State) 패턴을 사용하여 신호등 시스템을 만들어 봅시다! 각 상태가 신호등의 색상을 결정하고 다음 상태로 전환되는 방식을 정의하는, 여러 상태를 순환하는 신호등을 만들게 됩니다.

코드는 다음 두 개의 파일로 구성됩니다:

  • traffic_light.dart: 이 파일에는 상태 클래스들과 신호등 컨텍스트(context)가 포함됩니다. 두 개의 메서드를 가진 추상 클래스 TrafficLightState를 생성하세요: 현재 신호등 색상을 반환하는 String getColor()와 신호등을 다음 상태로 전환하는 void next(TrafficLight light)입니다. 세 개의 구체적인 상태 클래스를 구현하세요:
    • RedState - 색상으로 'RED'를 반환하고, next()가 호출될 때 'Stop! Light is red.'를 출력한 후 GreenState로 전환합니다.
    • GreenState - 색상으로 'GREEN'을 반환하고, next()가 호출될 때 'Go! Light is green.'를 출력한 후 YellowState로 전환합니다.
    • YellowState - 색상으로 'YELLOW'를 반환하고, next()가 호출될 때 'Caution! Light is yellow.'를 출력한 후 RedState로 전환합니다.
    그런 다음 RedState에서 시작하는 TrafficLight 클래스(컨텍스트)를 생성하세요. 이 클래스는 현재 상태를 변경하는 setState() 메서드, 현재 상태에 위임하는 getColor() 메서드, 그리고 현재 상태의 next()를 호출하는 change() 메서드를 가져야 합니다.
  • main.dart: 신호등 파일을 임포트하고 상태 패턴이 작동하는 모습을 보여주세요. TrafficLight를 생성하고 초기 색상을 출력합니다. 그런 다음 change()를 세 번 호출하고, 각 변경 후에 색상을 출력하세요. 이를 통해 신호등이 모든 상태를 순환하고 다시 처음으로 돌아오는 것을 확인할 수 있습니다.

TrafficLight 클래스가 동작을 결정하기 위해 어떠한 조건문도 필요로 하지 않는다는 점에 주목하세요. 각 상태는 자신의 색상과 다음에 올 상태를 스스로 알고 있습니다. 신호등은 단순히 현재 활성화된 상태에 동작을 위임할 뿐입니다!

예상 출력:

RED
Stop! Light is red.
GREEN
Go! Light is green.
YELLOW
Caution! Light is yellow.
RED

치트 시트

상태 패턴(State pattern)은 객체의 내부 상태가 변경될 때 객체의 동작을 변경할 수 있도록 합니다. 복잡한 조건문을 사용하는 대신, 각 상태를 자체 클래스로 캡슐화합니다.

이 패턴은 다음과 같이 구성됩니다:

  • Context: 현재 상태에 대한 참조를 유지합니다.
  • State classes: 가능한 각 상태에 대한 동작을 정의합니다.

기본 구조:

abstract class DocumentState {
  void publish(Document doc);
  String getStatus();
}

class DraftState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Moving to review...');
    doc.setState(ReviewState());
  }

  @override
  String getStatus() => 'Draft';
}

class Document {
  DocumentState _state = DraftState();

  void setState(DocumentState state) => _state = state;
  void publish() => _state.publish(this);
  String getStatus() => _state.getStatus();
}

컨텍스트는 동작을 현재 상태 객체에 위임합니다. 각 상태 클래스는 동작을 다르게 처리하며 다음 상태로 전환할 수 있습니다. 이를 통해 현재 상태를 확인하기 위한 조건문이 필요하지 않게 됩니다.

주문 처리, 미디어 플레이어 또는 워크플로 시스템과 같이 뚜렷한 동작 모드가 있는 객체에 이상적입니다.

직접 해보기

import 'traffic_light.dart';

void main() {
  // TODO: TrafficLight 인스턴스 생성
  
  // TODO: 초기 색상 출력
  
  // TODO: change()를 호출하고 색상을 출력 (모든 상태를 순환하기 위해 3번 반복)
  // 첫 번째 변경: RED -> GREEN
  
  // 두 번째 변경: GREEN -> YELLOW
  
  // 세 번째 변경: YELLOW -> RED
}
quiz icon실력 점검

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

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