본문 바로가기

JAVA/디자인 패턴

[Design Pattern] State(상태) 패턴이란?

반응형
행위 패턴(Behavioral Pattern)


상태 패턴(State Pattern)은 객체지향 디자인 패턴 중 하나로, 객체가 내부 상태에 따라 행동을 변경할 수 있도록 하는 패턴입니다. 이 패턴은 객체가 다양한 상태를 가질 수 있고, 각 상태에 따라 객체가 다르게 동작해야 할 때 유용합니다.

상태 패턴은 크게 세 가지 구성요소로 이루어집니다.

 

  1. 상태(State): 객체가 가질 수 있는 상태를 나타내는 인터페이스입니다. 이 인터페이스에는 해당 상태에서 수행되어야 하는 모든 메서드가 정의됩니다.

  2. 구체적인 상태(Concrete State): 상태 인터페이스를 구현한 클래스입니다. 이 클래스는 객체가 실제로 가질 수 있는 상태 중 하나를 나타내며, 해당 상태에서 수행되어야 하는 모든 메서드를 구현합니다.

  3. 컨텍스트(Context): 상태 객체를 포함하고 있는 클래스입니다. 컨텍스트는 상태 객체를 사용하여 동작을 수행합니다. 상태 객체는 컨텍스트에서 필요할 때마다 변경됩니다.

이 패턴은 컨텍스트와 상태 객체가 상호작용하는 방식을 표현하기 위해 상태 전이도를 사용할 수 있습니다. 상태 전이도는 객체가 다른 상태로 전이될 때 어떤 메서드가 호출되는지를 나타내는 그림입니다.

예를 들어, 게임에서 캐릭터의 상태를 나타내는 예제를 생각해보겠습니다. 캐릭터는 걷는 상태, 뛰는 상태, 점프하는 상태 등 다양한 상태를 가질 수 있습니다. 이 때 캐릭터 객체는 컨텍스트 역할을 하며, 각 상태는 상태 객체로 구현됩니다. 예를 들어, 걷는 상태를 나타내는 WalkingState 클래스는 상태 인터페이스를 구현하고, 걷는 동작을 수행하는 walk() 메서드를 정의합니다. 이와 같은 방식으로 캐릭터의 모든 상태를 클래스로 구현하고, 컨텍스트에서 필요할 때마다 상태 객체를 변경하여 동작을 수행할 수 있습니다.

상태 패턴을 사용하면 상태 전이를 관리하기가 쉬워지며, 새로운 상태를 추가하기도 용이해집니다. 또한 코드의 가독성과 유지보수성이 좋아지는 장점이 있습니다.

 

 

State 패턴 예제

예제에서는 미디어 플레이어(MediaPlayer) 객체가 다양한 상태를 가질 수 있고, 각 상태에 따라 다르게 동작하는 것을 구현합니다.

Diagrams


먼저, 상태 인터페이스(State)를 정의합니다. 이 인터페이스에는 미디어 플레이어가 가질 수 있는 모든 상태에서 수행되어야 하는 메서드가 정의됩니다.

public interface State {
    void pressPlay(MediaPlayer mediaPlayer);
}



다음으로, 구체적인 상태 객체를 정의합니다. 여기서는 미디어 플레이어가 재생 중인 상태와 정지 상태를 구현합니다. 각 상태 객체는 State 인터페이스를 구현하고, 해당 상태에서 수행되어야 하는 메서드를 구현합니다.

public class PlayingState implements State {
    @Override
    public void pressPlay(MediaPlayer mediaPlayer) {
        System.out.println("Already playing.");
    }
}

public class StoppedState implements State {
    @Override
    public void pressPlay(MediaPlayer mediaPlayer) {
        mediaPlayer.setState(new PlayingState());
        System.out.println("Playing...");
    }
}



마지막으로, 컨텍스트 객체인 미디어 플레이어(MediaPlayer)를 구현합니다. 미디어 플레이어는 현재 상태를 유지하고, 상태 전이를 처리합니다.

public class MediaPlayer {
    private State state;

    public MediaPlayer() {
        state = new StoppedState();
    }

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

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



이제, 위에서 정의한 클래스들을 사용하여 미디어 플레이어를 테스트해보겠습니다.

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

        // 정지 상태에서 재생 버튼을 누르면, 재생 중인 상태로 전이됩니다.
        mediaPlayer.pressPlay();

        // 이미 재생 중인 상태에서 재생 버튼을 누르면, 이미 재생 중이라는 메시지가 출력됩니다.
        mediaPlayer.pressPlay();
    }
}



위의 예제에서는 미디어 플레이어 객체가 생성될 때, 상태를 정지 상태(StoppedState)로 초기화합니다. 이후, pressPlay() 메서드가 호출될 때마다 현재 상태에 따라 동작이 달라집니다.

실행 결과는 다음과 같습니다.

Playing...
Already playing.



첫 번째 pressPlay() 메서드 호출 시, 미디어 플레이어 객체가 정지 상태에서 재생 중인 상태로 전이되어, "Playing..."이 출력되며, 두 번째 pressPlay() 메서드 호출 시, 이미 재생 중인 상태이므로 "Already playing."이 출력됩니다.

상태 패턴은 객체의 상태에 따라 다르게 동작해야 하는 경우에 유용합니다. 또한, 객체의 상태 전이를 캡슐화함으로써, 객체 간의 결합도를 낮출 수 있습니다. 이를 통해 유지보수성을 향상시킬 수 있습니다.

반응형