[UNITY],[C#]/TIL : UNITY

[디자인패턴] 명령패턴

네,가능합니다 2024. 11. 1. 21:48

명령패턴이란?

행위를 캡슐화하여 큐에 저장하거나 로그로 기록하고, 다시 재실행할 수 있는 패턴이다.

이로 인해 행동을 되돌리거나 하는 등의 시스템이 가능해진다.

 

이게 어떻게 가능한지 이해가 잘 안 된다.. 예제를 보면서 코드의 흐름을 이해해 보자

 

아이템 거래시스템에 명령패턴을 적용한 예제를 살펴보자

 

 우선 거래명령이 구현해야 할 인터페이스를 정의해 주자.

public interface ICommand
{
    void Execute();
    void Undo();
}

 

그리고 거래명령받으면 실제로 아이템을 교환하는 플레이어를 만들자

public class Player : MonoBehaviour
{
    public string playerName;
    public List<string> inventory = new List<string>();
	//아이템추가
    public void AddItem(string item)
    {
        inventory.Add(item);
    }
    
    public void RemoveItem(string item)
    {
    	// 아이템이 있으면
        if (inventory.Contains(item))
        {	//아이템 제거
            inventory.Remove(item);
        }
        else
        {
        	// 아이템이 없을때
        }
    }
}

 

그리고 명령 객체를 구현하자

public class TradeCommand : ICommand
{
    private Player _sender;
    private Player _receiver;
    private string _item;

    public TradeCommand(Player sender, Player receiver, string item)
    {
        _sender = sender;
        _receiver = receiver;
        _item = item;
    }

    public void Execute()
    {	// 보내는쪽이 아이템을 들고있으면
        if (_sender.inventory.Contains(_item))
        {	// 지우고
            _sender.RemoveItem(_item);
            // 받는사람한테 추가하기
            _receiver.AddItem(_item);
        }
        else
        {
            // 없으면 거래취소
        }
    }
	// 되돌리기
    public void Undo()
    {	// 받은사람이 아이템 있는지 확인하고
        if (_receiver.inventory.Contains(_item))
        {	// 받은사람 아이템 지우고
            _receiver.RemoveItem(_item);
            // 준사람에게 아이템 추가하기
            _sender.AddItem(_item);
        }
        else
        {
            // 원하는 대응
        }
    }
}

 

자 그러면 이렇게 캡슐화를 한 이유는 아래의 예제코드를 보면 알 수 있다.

public class TradeManager : MonoBehaviour
{
	// 스택 자료구조로 저장하기에 후입선출방식
    private Stack<ICommand> _tradeHistory = new Stack<ICommand>();
	// 거래하라는 명령이 내려지면 거래를 시키고 기록함
    public void ExecuteTrade(ICommand command)
    {
        command.Execute();
        _tradeHistory.Push(command);
    }
	// 되돌리라는 명령이 내려지면 가장 마지막 기록을 가져와서 되돌림
    public void UndoTrade()
    {
        if (_tradeHistory.Count > 0)
        {
            ICommand command = _tradeHistory.Pop();
            command.Undo();
        }
        else
        {
            // 기록이 없습니다.
        }
    }
}

 

그리고 찐막으로 트레이드 매니저를 관리하면 끝

public class GameManager : MonoBehaviour
{
    public Player player1;
    public Player player2;
    private TradeManager tradeManager;

    private void Start()
    {
        tradeManager = new TradeManager();
        player1.playerName = "geun";
        player2.playerName = "hyun";

        player1.AddItem("VeryGoodItem");
    }

    private void Update()
    {
        if (거래허락)
        {
            // 거래시도 (주는사람, 받는사람, 아이템)
            var tradeCommand = new TradeCommand(player1, player2, "VeryGoodItem");
            // 거래시키기
            tradeManager.ExecuteTrade(tradeCommand);
        }

        if (거래 되돌리기)
        {
            // 마지막 거래를 되돌리기
            tradeManager.UndoTrade();
        }
    }
}

 

이런 방법으로 행위를 캡슐화하여, 로그를 기록하고 언제든 되돌릴 수 있는 것이 명령패턴인 것 같다.

 

이런 방식으로 필요한 곳에 적절하게 사용하면 로그를 기록하거나 하는 방법도 쉽게 만들 수 있을 것 같다.

 

매번 디자인 패턴을 배울 때마다 드는 생각이지만

 

단일책임원칙만 잘 지키며 코딩해도 언제든 필요한 디자인패턴을 쉽게 적용할 수 있을 것 같다