[Unity] 상태(State) 패턴에 대해

조재훈·2024년 4월 2일

상태 패턴

상태 패턴이란?

상태 패턴은 게임 개발에서 유용하게 사용되는 디자인 패턴이다

어떤 객체가 상태에 따라 행위를 다르게 할 때, 상태를 if문 같은 조건문으로 직접 체크해 상태에 따른 행동을 호출하는 것이 아니라 상태를 객체화해서 필요에 따라 다르게 행동하도록 위임하는 패턴이다

객체의 특정 상태를 클래스로 선언하고 클래스에서 해당 상태에서 할 수 있는 행동을 메서드로 정의한다

상태 패턴을 사용하는 경우

  • 상태 전이를 위한 로직이 복잡한 경우
  • 현재 상태에 따라 다르게 행동하는 객체가 있는 경우
  • 상태들의 수가 많고, 상태별로 코드가 자주 변경되는 경우

상태 패턴의 장점

  • 객체 내부 상태의 변경에 따라 객체의 행동을 특정 상태에 특화된 행동들로 분리할 수 있고, 새로운 행동을 추가해도 다른 행동에 영향을 주지 않는다
  • 상태에 따른 동작을 개별 클래스로 옮겨 관리할 수 있다
  • 상태와 관련된 모든 동작을 각각의 상태 클래스에 분산시킴으로써, 코드 복잡도를 줄일 수 있다
  • 특정 상태와 관련된 코드를 별도의 클래스로 구성하여 단일 책임 원칙을 준수할 수 있다
  • 기존 상태 클래스나 컨텍스트를 변경하지 않고 새로운 상태를 도입할 수 있어, 개방-폐쇄 원칙을 준수할 수 있다
  • 하나의 상태 객체만 사용해 상태 변경을 하므로 일관성 없는 상태 주입을 방지하는데 도움이 된다

상태 패턴의 단점

  • 상태 별로 클래스를 생성하므로 관리해야 할 클래스의 수가 증가함
  • 상태 클래스의 개수가 많고, 규칙이 자주 변경된다면, 컨텍스트의 상태 변경 코드가 복잡해질 수 있다
  • 객체에 적용할 상태가 별로 없거나 상태 변경이 자주 일어나지 않는다면 패턴을 적용하는 것이 오히려 안좋을 수 있다

구조

  • State Interface
    • 상태를 추상화한 모듈
  • Concrete State
    • 구체적인 각각의 상태를 클래스로 표현함
    • State Interface를 상속 받아 인터페이스를 구현
    • 다음 상태가 결정되면 Context에 상태 변경을 요청하는 역할 수행
  • Context
    • State를 이용하는 시스템(객체)
    • 시스템 상태를 나타내는 State 객체를 Composition함
    • 클라이언트로부터 요청받으면 State 객체에 행위 실행을 위임

유니티 예제

namespace StatePattern
{
    public interface IState
    {
        void Study();
    }
}

public class Sleep : IState
{
    public void Study()
    {
        Debug.Log("졸려서 공부가 안됩니다");
    }
}

public class Fine : IState
{
    public void Study()
    {
        Debug.Log("멀쩡하게 공부합니다");
    }
}

상태의 인터페이스를 선언하고 이를 상속받는 상태(Fine, Sleep)를 생성한다

학생 클래스를 만들어 상태 정보를 저장하게 하자

public class Student
{
    /// <summary>
    /// 학생의 현재 상태
    /// </summary>
    private IState state;

    public int health = 100;

    public Student() 
    {
        SetState();
    }

    public void SetState()
    {
        if (health < 30)
            state = new Sleep();
        else
            state = new Fine();
    }

    public void Study()
    {
        SetState();
        state.Study();
    }
}

학생의 체력을 뜻하는 health 값에 따라 SetState에서 상태 값을 결정한다.

학생의 Study 함수를 실행하면 먼저 현재 체력에 따라 어떤 상태인지 결정한 후 state의 Study를 실행해 멀쩡하면 Fine의 Study가, 졸리면 Sleep의 Study가 실행된다

이 학생을 관리하는 클래스인 School을 보자

public class School : MonoBehaviour
{
    
    private void Start()
    {
        Student student = new Student();
        student.Study();

        student.health = 20;
        student.Study();
    }
}

학생 클래스를 만들어 학생이 공부를 하게 한 다음 임의로 학생의 체력을 깎고 공부를 시켜보자

게임을 실행하면 로그가 다음과 같이 뜬다

효율적으로 쓰려면 Student에서 체력에 맞게 알아서 상태가 변경되면 좋을 것 같음

이렇게 간단하게 상태 패턴을 알아보았다

profile
나태지옥

0개의 댓글