상태 패턴
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 인터페이스를 구현하는 새로운 클래스를 만들기만 하면 됩니다.
챌린지
쉬움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() 호출
// - 각 동작 후 현재 상태 출력
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
4상속
상속의 기초 (extends)super 키워드메서드 오버라이딩 (@Override)생성자 체이닝Object 클래스단일 및 다중 레벨 상속다중 클래스 상속이 불가능한 이유요약 - 직원 계층 구조직접 연습해 보세요: 온라인 Java 컴파일러