개인 프로젝트 준비를 위해 당분간 TIL 작성은 간결하게 진행하겠다.
대신 이번 프로젝트도 마찬가지로 제작일지를 동시에 작성 예정.
기본적으로 코드로 복습 예정인데
예시 코드는 기존과 같이 비공개로 업로드 예정.
상태 패턴을 이해하고 활용해보자.
코드 위주의 내용이므로 간단히 정의만 정리하고
복습용 코드는 비공개로 게시.
상태 패턴이란?
객체의 내부 상태(State)가 바뀜에 따라 객체의 행위(Behavior)를 변경할 수 있게 해주는 디자인 패턴
복잡한 조건문을 사용하여 상태별 행위를 구현하는 대신
각 상태를 독립된 클래스로 분리하여 관리함으로써
코드의 유지보수성과 확장성을 높일 수 있다.
복잡한 상태 전환 로직을 캡슐화하고 분리하는 걸 중점으로 둠.
기존의 상태전환 로직의 예시로는
if(currentState == StateA)
{
Do A
}
위와 같이 하나의 객체 내부에 수많은 조건문을 사용하여
상태를 체크하고, 그에 맞는 로직을 실행하는 방식이였음.
이 상태별 행동(Behavior) 을 상태를 나타낼 객체에게 위임하는 방식.
주로 3가지 구성요소를 지님.
게임에서의 행동 유닛의 상태에 적용할 수 있다.
Player의 상태?
Idle, Walk, Run, Jump 등등
이 예시를 간단히 코드로 구현해보겠다.
인터페이스 방식 채용
인터페이스로 모든 상태에서 필요한 메서드를 강제
// 모든 상태가 구현해야 할 공통 인터페이스
public interface IPlayerState
{
void EnterState(Player player);
void HandleInput(Player player);
void Update(Player player);
}
ConcreteState(IdleState, WalkState 등)
해당 상태만의 로직을 구현.
public class IdleState : IPlayerState
{
public void Update(Player player))
{
if (벡터값이 있으면?))
{
//상태 전환
player.ChangeState(new WalkState());
}
}
다른 메서드 구현
}
현재 상태 객체의 참조 유지, 모든 상태별 요청을 이 객체에 위임.
public class Player
{
//1. 현재 상태 객체 참조
private IPlayerState _currentState;
public Player()
{
// 초기 상태 설정
_currentState = new IdleState();
_currentState.EnterState(this);
}
// 2. 상태 변경용 메서드
public void ChangeState(IPlayerState newState)
{
// 상태 변경
_currentState = newState;
// 새로운 상태의 시작 로직 호출
_currentState.EnterState(this);
}
// 3. Context의 동작을 현재 상태 객체에 위임
public void Update()
{
_currentState.Update(this);
}
}
이러면 기본적인 Player 움직임 상태패턴 구현 완료.
상태 분리:
상태별 행위 로직이 하나의 Context 클래스에 집중되지 않고
각 ConcreteState 클래스로 분리
유지보수 용이
새로운 상태를 추가할 때, 기존 Context 클래스의 코드를 수정(조건문 추가)할 필요 없이
새로운 상태 클래스만 추가
다형성 활용
객체 지향의 다형성(Polymorphism)을 활용하여 상태별 행위를 실행
이런 이점을 갖고 있기에 필요 시에 활용하면 좋다.
오늘은 상태 패턴이라는 디자인 패턴을 알아보았다.
내일은 이와 흡사한 Behavior Tree(BT) 구조를 알아보고
Unity 6부터 제공하는 BT 그래프 기능 (Behavior Graph) 또한 알아보겠다.