비트를 쪼개는 개발자

allen321@naver.com

C#

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

MozarTnT 2024. 10. 22. 13:35
728x90
반응형

 

 

 

 

 

상태 패턴이란?

 

  • 상태 패턴(State Pattern)은 객체의 상태에 따라 그 객체의 행동이 변경되도록 하는 디자인 패턴이다.
  • 상태 패턴은 객체의 상태가 변화할 때, 해당 상태에 따른 로직을 별도의 상태 클래스들로 분리하여 구현한다.
  • 객체의 상태와 관련된 코드가 분리되기 때문에 상태 전환을 쉽게 관리할 수 있게 된다.
  • 객체 지향 설계 원칙인 변화 부분을 "캡슐화" 할 수 있고 이를 통해 코드의 확장성이 용이해진다.

 

 

 

상태 패턴의 구성 요소는?

  • 상태 패턴은 크게 Context(시스템, 주체), State(상태, 인터페이스), ConcreteState(구체적 상태)로 구성된다. 

 

 

 

1. Context

 

  • 상태를 관리하는 객체로, 현재 상태에 따라 동작을 위임하는 역할을 수행한다
  • 상태 패턴의 사용자 측에서 사용할 주요 인터페이스를 제공하며 현재 상태(State) 객체를 보관하고, 필요에 따라 이를 변경한다
  • 게임에서 플레이어가 달리거나 점프하는 상황에서 Player 객체가 Context 역할을 수행한다

 

2. State

 

  • State는 상태 객체들이 구현해야 하는 공통 인터페이스를 정의한다
  • Context가 상태 객체에게 요청하는 메서드를 일관되게 사용할 수 있도록 한다.
  • 각 상태에 따라 구체적인 행동을 수행하는 메서드를 선언한다.
  • 인터페이스에는 Handle() 메서드를 선언하여 각 상태에서 수행할 행동을 정의한다.

 

3. ConcreteState

 

  • ConcreteState는 State 인터페이스를 구현하는 클래스들로, 각 상태에 해당하는 구체적인 행동을 정의한다
  • 상태마다 다르게 동작해야 하는 로직을 이 클래스들로 관리한다
  • 필요에 따라 Context의 상태를 다른 상태로 변경하는 로직을 수행한다
  • 게임에서는 Player의 상태를 StandState, RuuningState, JumpingState등의 클래스로 구현하여 사용할 수 있다

 

 

 

상태 패턴을 사용하는 경우?

 

  • 상태 패턴은 객체의 행동이 여러개 존재하고, 그 행동마다 행위가 달라지는 경우 사용하기 바람직하다.
  • 객채의 상태에 따른 행동을 호출하는 것이 아니라 해당 상태 자체를 객체화 하여서 필요에 따라 호출하는 방식이다.
  • 조건문을 사용해서 매번 상태를 검사하는 것이 아니라 상태의 행동 자체를 위임하게 된다.
  • 따라서 여러 상태가 존재하고, 상태마다 행동이 달라지는 경우에 상태 패턴을 사용하면 일관성 있는 코드를 작성할 수 있다.

 

 

예시 코드

 

internal class StatePattern
{
    public interface IState
    {
        void Handle(Player player);
    }

    public class StandingState : IState
    {
        public void Handle(Player player)
        {
            Console.WriteLine("Player is standing.");
            player.SetState(new RunningState());
        }
    }

    public class RunningState : IState
    {
        public void Handle(Player player)
        {
            Console.WriteLine("Player is running.");
            player.SetState(new JumpingState());
        }
    }

    public class JumpingState : IState
    {
        public void Handle(Player player)
        {
            Console.WriteLine("Player is jumping.");
            player.SetState(new StandingState());
        }
    }

    public class Player
    {
        private IState _state;

        public Player(IState state)
        {
            SetState(state);
        }

        public void SetState(IState state)
        {
            _state = state;
        }

        public void Action()
        {
            _state.Handle(this);
        }
    }
}

 

 

  • 상태를 담당할 IState 인터페이스를 만들어 주고, IState 인터페이스를 통해 상태별 행동을 정의한다.

 

  • Player 객체는 StandingState, RunningState, JumpingState와 같은 상태를 가지며, 상태가 변할 때마다 SetState 메서드를 통해 상태 객체를 변경하도록 설계했다.

 

  • 모든 State는 IState 인터페이스를 상속받아 구현하는데, 공통적으로 구현할 메서드를(Handle) 동일한 방식으로 호출하기 위해 상속시킨다. 

 

  • 상태가 변할 때마다 SetState 메서드를 통해 상태 객체를 변경하며, Player가 Action 메서드를 호출할 때마다 현재 상태에 따라 적절한 행동을 수행한다. (현재 코드에서는 Action 호출 시 상태 변경)

 

static void Main(string[] args)
{
    StatePattern statePattern = new StatePattern();

    StatePattern.Player player = new StatePattern.Player(new StatePattern.StandingState());
    player.Action();  
    player.Action();  
    player.Action(); 
}

 

 

  • Main문에서 Action을 호출하면 다음과 같이 상태가 변경된다.

 

 

 


 

 

정리

 

  • 상태 패턴(State Pattern)은 객체의 상태에 따라 행동이 변경되도록 설계하는 디자인 패턴이다.
  • 각각의 상태를 별도의 클래스로 캡슐화하여, 상태마다 동작을 정의한다.
  • 상태 패턴을 사용하면 검사용 조건문을 줄이고, 상태 전환을 명확하게 관리가 가능하다.
  • 새로운 상태를 추가할 때 기존 코드를 모두 수정하지 않고 클래스만 추가하면 된다. (확장성 있고 유지보수가 용이한 코드 구현)

 

 

 

 

 

 

사진 출처 :
https://refactoring.guru/design-patterns/state

https://fmoralesdev.com/2019/05/13/design-pattern-state/

728x90
반응형