본문 바로가기
STUDY/디자인패턴

Command 커맨드 패턴 ★★★

by 램플릿 2024. 7. 16.

커스텀 툴을 만들 때 커맨드패턴으로 Undo, Redo(execute)를 만들어 사용하기때문에 정말 많이 사용하게되는 패턴이다.

 

스택에 ICommand를 쌓아서 사용.

 

 


Command pattern을 활용하여 Redo 구현 시, History stack에서 Command를 Pop 해서 어려움을 겪는 이슈
1.베이스 자료구조를 Linked list 로 구현하는 방법
2.Redo 용 Temp stack을 하나 더 메모리에 들고 가는 방법

1번 케이스의 경우 Pop을 하지 않아도 Undo 시점으로 되돌아갈 수 있고, Redo 용 Excute가 메모리에 nextNode 형태로 남아 있으니 직관적으로 이해가 가는 방법입니다.

2번 케이스의 경우 Undo 할때마다 Pop한 Comand를 Redo용 스택에 Push 해서 지니고 있다가, Undo와 Redo를 하지 않고 새로운 Comand 를 Push 할 때 Redo용 stack을 클리어하는 형태로 구현하는 방식입니다. 아마 조금 더 직관적으로 이해가 가지 않을까 싶습니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface ICommand
{
    void SetOwner(GameObject go);
    void Excute();
    void Undo();
}

public abstract class Command : ICommand
{
    protected GameObject Owner;

    public void SetOwner(GameObject go)
    {
        Owner = go;
    }
    public abstract void Excute();
    public abstract void Undo();
}

public class MoveCommand : Command
{
    private Vector3 movePosition = new Vector3(10, 0, 0);
    
    public override void Excute()
    {
        Owner.transform.position += movePosition;
    }

    public override void Undo()
    {
        Owner.transform.position += -movePosition;
    }
}

public class CommandManager
{
    public GameObject Owner;
    
    private Stack<ICommand> History = new();

    public void Excute(ICommand command)
    {
        command.SetOwner(Owner);
        command.Excute();
        History.Push(command);
    }

    public void Undo()
    {
        if (History.Count > 0)
        {
            History.Pop().Undo();
        }
    }
}

public class CommandPattern : MonoBehaviour
{
    private CommandManager _commandManager = new();
    
    // Start is called before the first frame update
    void Start()
    {
        _commandManager.Owner = this.gameObject;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.E))
        {
            _commandManager.Excute(new MoveCommand());
        }
        
        if (Input.GetKeyDown(KeyCode.U))
        {
            _commandManager.Undo();
        }
    }
}

'STUDY > 디자인패턴' 카테고리의 다른 글

Observer 옵저버 패턴 ★★★  (0) 2024.07.19
FSM(Finite-State-Machine) ★★★  (0) 2024.07.17
chain of responsibility 책임연쇄 패턴  (0) 2024.07.16
Proxy 프록시 패턴  (0) 2024.07.15
Flyweight 플라이웨이트 패턴  (0) 2024.07.15