유니티 상태 패턴(State Pattern)과 전략 패턴(Strategy Pattern) 차이에 대해서

디자인 패턴을 무턱대고 사용하지 맙시다! 

본인이 사용하고 있는 코드(디자인) 패턴이 무엇인지는 제대로 알고 사용하고, 디자인 패턴의 본연의 의미를 잃어버리지 맙시다!


State Pattern이란?

 

State Pattern은 객체의 상태를 캡슐화하여 해당 상태에 따라 객체의 행동을  내부에서 자동으로 변경하는 디자인 패턴입니다.

 

https://m.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS9413616994

 

 

유니티 설치과정을 예시로 말해보겠습니다. 우리가 유니티를 설치할 때 내부에서 어떻게 설치되는지 알아야 하는 이유가 있을까요? 저희는 그저 Next 버튼을 클릭하기만 하면 됩니다. Next 버튼을 누르면 내부에서 알아서 설치가 되고, 설치가 마무리되면 프로그램은 저희에게 또다시 Next 버튼을 누르라고 합니다. 그 과정이 끝나면 프로그램은 Finish 버튼을 누르라고 저희에게 알립니다.

 

저희는 이 과정에서 버튼을 딸-깍 했을 뿐, 내부에서 일어나는 과정을 몰라도 상관이 없습니다.

 

여기서 바뀐 State는 무엇일까요?? 

Next버튼을 누르면 A라는 프로세스가 진행되고, 한 번더 Next버튼을 누르면 B라는 프로세스가 진행되어 설치과정이 이뤄나고 있습니다. 저희는 버튼을 누름으로써 내부 프로세스의 설치과정, 즉 State(설치 진행)가 바뀌고 있습니다. 

 

수도 코드로 간단하게 나타내보면

interface IState()
{
	progress(StateContext context);
}

 

class StateContext
{
    IState currentState;
    
    class StateContext(Istate newState)
    {
    	currentstate = newState;
     }
     
     void Progress()
     {
     	currentState.Progress();
     }
}

 

StateContext는 현재 State의 상태를 보관하고 있다가 클라이언트의 요청에 따라 해당 State를 처리하는 역할을 담당합니다.

void ProgressA : IState
{
    void Progress(StateContext context)
    {
    	//설치.......
        if(설치가 다 되었다면)
        	context(new StateContext(ProgressB)) <- 자동으로 상태 변경
     }
}

 

ProgressA에서는 A 설치 프로세스를 처리합니다. 처리가 끝난다면 ContextState의 상태를 다음 Progess로 변경해 줍니다. 

void ProgressB : IState
{
    void Progress(StateContext context)
    {
    	//설치.......
        if(설치가 다 되었다면)
        	context(new StateContext(ProgressFinish)) <- 자동으로 상태 변경
     }
}

 

ProgressB도 마찬가지로 본인의 프로세스를 다 처리 했다면 다음 State를 ContextState에 변경해 줍니다.

 

class Client
{
    StateConext stateContext;
    
    void Click() //클릭 한 번만 한다고 가정
    {
    	stateContext.Progress(); //Progress A가 진행된다
        stateContext.Progress(); //Progress B가 진행된다
    }
}

 

이제 클라이언트는 Click(딸-깍)만 하면 알아서 설치가 된다. 클라이언트가 따로 행동을 지정할 필요 없이 StateContext를 실행하기만 하면 내부에서 알아서, 자동으로 상태가 변화하고 그거를 클라이언트가 누리기만 하면 됩니다.

 

State Pattern의 장점은, 만약 회원가입 과정에 Progress C와 Progress D가 생겼더라고 해도 Client 로직과 StateContext 로직은 수정될 필요 없이 내부 Progress 로직만 수정 변경을 하면 됩니다. 유지보수가 쉬워진다는 장점이 있습니다.

 


Strategy Pattern

 

Strategy Pattern은 알고리즘을 캡슐화하고, 실행 시점에 알고리즘을 교체할 수 있도록 하는 디자인 패턴입니다.

 

State Pattern에서는 내부 상태가 알아서 자동으로 바뀐다는 점과 다르게, Strategy Pattern은 클라이언트가 내부 상태를 결정해주어야 합니다. 

 

https://m.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS9413616994

 

예를 들어, 아까 State Pattern에서는 저희는 그저 딸-깍 버튼만 누르면 알아서 다 되었지만 위 사진처럼 저희가 어떤 행동을 결정할 때, 예를 들어 Visual Studio도 같이 설치할 것인지, SDK도 같이 설치할 것인지...등 클라이언트가 행동을 결정할 때 Strategy Pattern을 사용하면 된다고 생각하면 편할 것 같습니다.

 

수도 코드로 설명해 보자면

class StateContext
{
    IState currentState;
    
    public void Change(Istate newState)
    {
    	currentstate = newState;
     }
     
     void Progress()
     {
     	currentState.Progress();
     }
}
class Client
{
    StateConext stateContext;
    
    void Click() //클릭 한 번만 한다고 가정
    {
    	stateContext.Change(비쥬얼스튜디오 설치하기);
        stateContext.Progress();
        stateContext.Change(SDK 설치하기); 
        stateContext.Progress();
	//무엇을 설치할 지(=어떤 행동을 할 지) -> 전략 ㅋㅋ
    }
}

 

아까 State Pattern에서는 내부 State에서 자동으로 State를 처리한 반면에, Strategy Pattern에서는 Client가 직접 상태를 처리해주어야 합니다.

 

설치과정 말고 다른 예시로 한 번 더 설명을 해보겠습니다.

class Program
{
    void Main()
    {
        int[] array = { 5, 2, 7, 1, 9 };

        SortContext context = new SortContext();

        // 버블 정렬을 선택하여 사용
        context.SetSortStrategy(new BubbleSortStrategy());
        context.SortArray(array);

        // 퀵 정렬을 선택하여 사용
        context.SetSortStrategy(new QuickSortStrategy());
        context.SortArray(array);

        // 병합 정렬을 선택하여 사용
        context.SetSortStrategy(new MergeSortStrategy());
        context.SortArray(array);
    }
}

 

정렬하고자 하는 배열이 있다고 가정을 하겠습니다.

클라이언트는 어떤 정렬을 사용해서 정렬을 할 지 정렬 알고리즘을 선택하여 사용하면 됩니다.


정리

 

예시가 적절했는지 모르겠네요?ㅎㅎㅎ 이해가 최대한 쉽게 설명해 보려고... 미래의 제가 이해하기 쉽도록 해본 거고, 나름 적절하다고 생각하는데..여러분의 생각이 궁금합니다..!

 

State Pattern과 Strategy Pattern의 시스템적으로 로직의 차이는 크게 없지만, State를 클라이언트가 직접(혹은 특정 알고리즘에 의해) 결정해 주냐, 아니면 내부에 따라 자동으로 State가 결정되냐에 따라 패턴의 성격이 달라진다고 생각하시면 좋을 것 같습니다.

 

제 생각에 State Pattern이 사용될만한 부분은 게임 내 NPC AI를 개발 할 때 좋을 것 같고,

Strategy Pattern이 사용될 만한 부분은 FPS게임처럼 총을 들지, 권총을 들지, 칼을 들지 선택하는 상황이나, 데미지 입을 때 내부 로직?에 사용하면 좋을 것 같습니다.

 

틀린 부분이 있다면 지적해주세요! 또는 보완해줄 부분이 보인다면 피드백해주세요!!!