디자인패턴

[디자인 패턴] 상태 패턴 (State Pattern)

haleylog 2025. 3. 4. 16:56

1. 상태 패턴 (State Pattern) 이란?

상태에 따라 다른 행위를 할 때 상태객체화 하여 각각 다른 행동을 처리할 수 있게 하는 패턴

 

 

2. 특징

 

 

기능을 캡슐화 한 Interface와 각 상태 또는 상황 별 Class 로 이루어져 있고

상태 별로 기능을 구현하여 사용한다.

 

728x90

 

3. 사용 예시

문 열기, 문 닫기, 문 잠그기, 문 잠금해제하기 4가지의 기능이 있는 기계가 있을 때

현재 문의 상태에 따라서 기능이 달라 질 수 있다.

 

기능

  • open(): 문을 여는 행동
  • close(): 문을 닫는 행동
  • lock(): 문을 잠그는 행동
  • unlock(): 문을 잠금 해제하는 행동

기능을 정의한 DoorState Interface 를 생성한다.

interface DoorState {
    void open(Door door);
    void close(Door door);
    void lock(Door door);
    void unlock(Door door);
}

 

문의 상태를 관리하고 행동을 실행할 Door Class 를 생성한다.

class Door {
    private DoorState state;

    public Door() {
        this.state = new ClosedState(); // 초기 상태는 닫힌 상태
    }

    public void setState(DoorState state) {
        this.state = state;
    }

    public void open() {
        state.open(this);
    }

    public void close() {
        state.close(this);
    }

    public void lock() {
        state.lock(this);
    }

    public void unlock() {
        state.unlock(this);
    }
}

 

 

상태

  • ClosedState: 문이 닫혀있는 상태
  • OpenedState: 문이 열린 상태
  • LockedState: 문이 잠긴 상태

문이 닫힌 상태 Class 를 생성하고 닫힌 상태에서 기능 별 동작을 구현한다.

open() -> 현재 상태 문 열림으로 변경

close() -> 상태 변화X (이미 닫혀 있음)

lock() -> 현재 상태 문 잠김으로 변경

unlock() -> 상태 변화X (잠겨 있지 않음)

class ClosedState implements DoorState {
    @Override
    public void open(Door door) {
        System.out.println("문을 엽니다.");
        door.setState(new OpenedState());
    }

    @Override
    public void close(Door door) {
        System.out.println("문은 이미 닫혀 있습니다.");
    }

    @Override
    public void lock(Door door) {
        System.out.println("문을 잠급니다.");
        door.setState(new LockedState());
    }

    @Override
    public void unlock(Door door) {
        System.out.println("문은 잠겨 있지 않습니다.");
    }
}

 

 

문이 열린 상태 Class 를 생성하고 닫힌 상태에서 기능 별 동작을 구현한다.

open() -> 상태 변화X (이미 열려 있음)

close() -> 현재 상태 문 닫힘으로 변경

lock() -> 상태 변화X (문 열려 있어 잠글 수 없음)

unlock() -> 상태 변화X (잠겨 있지 않음)

class OpenedState implements DoorState {
    @Override
    public void open(Door door) {
        System.out.println("문은 이미 열려 있습니다.");
    }

    @Override
    public void close(Door door) {
        System.out.println("문을 닫습니다.");
        door.setState(new ClosedState());
    }

    @Override
    public void lock(Door door) {
        System.out.println("문은 열려 있어 잠글 수 없습니다.");
    }

    @Override
    public void unlock(Door door) {
        System.out.println("문은 잠겨 있지 않습니다.");
    }
}

 

 

문이 잠긴 상태 Class 를 생성하고 닫힌 상태에서 기능 별 동작을 구현한다.

open() -> 상태 변화X (잠겨 있어 열 수 없음)

close() -> 상태 변화X (이미 닫혀 있음)

lock() -> 상태 변화X (이미 잠겨 있음)

unlock() -> 현재 상태 문 닫힘으로 변경

class LockedState implements DoorState {
    @Override
    public void open(Door door) {
        System.out.println("문이 잠겨 있어 열 수 없습니다.");
    }

    @Override
    public void close(Door door) {
        System.out.println("문은 이미 닫혀 있습니다.");
    }

    @Override
    public void lock(Door door) {
        System.out.println("문은 이미 잠겨 있습니다.");
    }

    @Override
    public void unlock(Door door) {
        System.out.println("문을 잠금 해제합니다.");
        door.setState(new ClosedState());
    }
}

 

 

사용 예시

public class Main {
    public static void main(String[] args) {
        Door door = new Door();

        // 문 열기
        door.open(); // console: 문을 엽니다.

        // 문 닫기
        door.close(); // console: 문을 닫습니다.

        // 문 잠그기
        door.lock(); // console: 문을 잠급니다.

        // 문 열기 시도 (잠금 상태)
        door.open(); // console: 문이 잠겨 있어 열 수 없습니다.

        // 문 잠금 해제
        door.unlock(); // console: 문을 잠금 해제합니다.

        // 다시 문 열기
        door.open(); // console: 문을 엽니다.
    }
}

 

 

4. 장단점

장점

  1. 상태 별 행동을 명확히 분리할 수 있음
  2. 상태가 변경될 때마다 자동으로 상태에 맞는 동작이 실행되므로 일관성 있음

단점

  1. 상태가 많아지면 상태 클래스가 많아져 코드가 과도하게 복잡해 질 수 있음

 

 

5. 결론

상태 패턴은 상태 전환이 빈번하고 각 상태에 따른 행동이 달라야 하는 시스템에서 유용하게 사용 할 수 있음.

상태별로 동작을 캡슐화하고 관리할 수 있어 유지보수가 편리해지고 확장성이 높다는 장점이 있으나

상태 전환이 단순하거나 상태가 적은 경우에는 오히려 이 패턴을 적용하는 것이 과도할 수 있음

728x90
반응형