내일배움캠프 54일차 TIL : 커맨드 패턴 구현

김정환·2024년 11월 29일
0

키워드

  • 커맨드 패턴

프로젝트를 진행하면서 커맨드 패턴을 적용해보자는 기능이 있었다.

캠프 중에 특강을 통해서 이론적으로는 커맨드 패턴을 알고 있지만
실제로 구현해서 프로젝트에 적용하는 것은 이번이 처음이므로 공부를 해보고 작업을 하려고 한다.

커맨드(명령) 패턴

  • 행위를 캡슐화해서 하나의 객체로 만드는 방법이다.
  • 용도는 실행한 명령을 로그로 남기거나 Undo 기능 구현하기 위해 적용할 수 있다.
  • 이번에 커맨드 패턴을 쓰려는 이유가 바로는 아니더라도 후반부에 Undo 기능을 개발해야할 수도 있어서이다.
  • 후반부에 대부분의 기능이 완성된 상태에서 커맨드 패턴을 적용하기에는
    안정성이 매우 떨어질 것이 우려되기 때문에 초반인 지금 기반을 잡아두고 개발하는 것이 Undo 기능을 만들 때 도움이 될 것이라고 생각했다.

구성 요소

커맨드 인터페이스 ICommand

public interface ICommand
{
    void Execute();
    void Undo();
}
  • 다양한 커맨드 클래스들에 대해 통일된 사용을 위한 인터페이스를 만들어준다.
  • 이번에는 Undo 기능도 고려하고 있으므로 같이 추가해준다.

커맨드 구현 클래스 Command

  • 연습용으로 쓸 MoveCommand, AttackCommand를 작성했다.
using UnityEngine;

public class MoveCommand : ICommand
{
    public CommandReceiver subject;
    public Vector3 movement;
    
    // 구체적인 명령들
    public MoveCommand(CommandReceiver s, Vector3 move)
    {
        subject = s;
        movement = move;
    }
    
    public void Execute()
    {
        Debug.Log("이동 명령 수행");
        subject.Move(movement);
    }

    public void Undo()
    {
        Debug.Log("이동 명령 되돌리기");
        subject.Move(-movement);
    }
}

public class AttackCommand : ICommand
{
    public CommandReceiver subject;
    public GameObject target;
    public float damage;
    
    // 구체적인 명령들
    public AttackCommand(CommandReceiver s, GameObject t, float d)
    {
        subject = s;
        target = t;
        damage = d;
    }
    
    public void Execute()
    {
        Debug.Log("공격 명령 수행");
        subject.Attack(target, damage);
    }

    public void Undo()
    {
        Debug.Log("공격 명령 되돌리기");
    }
}
  • 커맨드 클래스에서 구체적인 작업을 수행하는게 아니라 작업을 수행하는 객체의 로직을 호출해주어야한다. 참고 링크

커맨드 Invoker

using System.Collections.Generic;
using UnityEngine;

public class CommandInvoker : MonoBehaviour
{
    // 명령 발송자, 히스토리 보관소
    public Stack<ICommand> history = new Stack<ICommand>();

    public void ExecuteCommand(ICommand command)
    {
        command.Execute();
        history.Push(command);
    }

    public void UndoCommand()
    {
        if(history.Count > 0)
            history.Pop().Undo();
    }
}
  • Command 객체를 보관하고 실행하는 역할을 수행한다.
  • 들어온 것의 역순으로 호출해야하므로 Stack을 이용해서 구현한다.
  • 엄격하게 Invoker라는 이름으로 있는 것은 아니다.

커맨드 Receiver

using UnityEngine;

public class CommandReceiver : MonoBehaviour
{
    // 명령을 수행할 클래스들
    // 게임 캐릭터들
    public void Move(Vector3 movement)
    {
        Debug.Log($"Move called {movement}");
    }

    public void Attack(GameObject go, float damage)
    {
        Debug.Log($"{gameObject.name}이/가 {go.name}에게 {damage}만큼 피해를 주었다.");
    }
}
  • 커맨드를 수행할 객체이다.
  • 마찬가지로 여기서는 Receiver라고 했는데 실제로는 게임 캐릭터와 같은 주체들에 적용될 것이다.
  • 커맨드를 통해서 수행할 로직인 Move, Attack을 구현해둔다.

작동 확인

  • 대략적인 구성 요소들에 대한 파악이 끝났으니 본 프로젝트에 적용해봐야겠다.

#내일배움캠프 #스파르타내일배움캠프 #스파르타내일배움캠프TIL

profile
사파 개발자

0개의 댓글

관련 채용 정보