[C#]커맨드 패턴

Arthur·2023년 7월 9일
0
post-thumbnail

커맨드 패턴이란?


요청을 객체의 형태로 캡슐화하여 사용자가 보낸 요청을 나중에 이용할 수 있도록 메서드 이름, 매개 변수 등 요청에 필요한 정보를 저장 또는 로깅, 취소할 수 있게 하는 패턴이다.

  • 다양한 요청들이 있는 메서드들을 인수화 할 수 있다.
  • 요청의 실행을 지연 또는 대기열에 넣을 수 있도록 한다.
  • 실행 취소할 수 있는 작업을 지원할 수 있다.

디자인 패턴은 개념만 보면 이해하기 쉽지만, 실제로 사용할려면 잘 안되는 경우가 많습니다.
그래서 사용하는 이유와 예시, 예제 코드를 보면 좀 더 실용적인 개념이 될 것이라 생각했습니다.



커맨드 패턴을 사용하는 이유


가장 큰 이유는 관심사 분리의 원칙(SoC, Separation of Concerns)을 지킬 수 있게 합니다.


아래의 사진은 레스토랑에서 손님이 주문을 하는 상황입니다.

상황 1)
첫 번째 레스토랑은 주방에 있는 직원이 요리도 하고 직접 주문을 받습니다.


상황 2)
두 번째 상황은 키오스크 주문을 통해 주문서를 한번에 관리하고 있습니다.

개선된 점

  • 주방 직원은 이제 온전히 요리와 부엌 관리에만 집중할 수 있습니다.
    • 비즈니스 로직은 비즈니스 로직에만 집중할 수 있습니다.
  • 주문에 대한 관리를 주문서 객체에게 위임 할 수 있습니다.
    ex) 주문 취소를 주문서 객체에서 실행한다.
  • 주문 관련 변경 사항이 생길 경우 주문(커맨드) 부분만 수정하면 된다.
    • 주문에 대한 변경 발생 시 손님, 주방에 영향을 주지 않는다.


커맨드 패턴 예제코드



    abstract class Command
    {
        protected Kiosk _kiosk;

        public void setKiosk (Kiosk kiosk)
        {
            this._kiosk = kiosk;
        }

        public abstract void execute();
    }

    class OrderPushCommand : Command
    {
        private Menu menu;

        public OrderPushCommand(Menu menu)
        {
            this.menu = menu;
        }

        public override void execute()
        {
            _kiosk.OrderPush(menu);
        }
    }

    class OrderPopCommand : Command
    {
        public override void execute()
        {
            _kiosk.OrderPop();
        }
    }

    // 키오스크를 활용해 주문 Queue에 push 및 pop을 합니다.
    class Kiosk
    {
        Queue<Menu> _orderQueue = new Queue<Menu>();
        Cooker cooker;

        public Kiosk(Cooker cooker)
        {
            this.cooker = cooker;
        }

        public void OrderPush(Menu menu)
        {
            _orderQueue.Enqueue(menu);
        }

        // 주문 Queue에서 menu를 pop 합니다.
        public void OrderPop()
        {
            if (_orderQueue.Count == 0)
            {
                Console.WriteLine("요리할 메뉴가 없습니다.");
                return;
            }

            Menu menu = _orderQueue.Dequeue();
            cooker.Cooking(menu);
        }
    }

    // 주방장(요리사)이 요리를 합니다.
    class Cooker
    {

        // 주방장(요리사)이 메뉴에 맞게 요리를 합니다.
        public void Cooking(Menu menu)
        {
            Console.WriteLine("------------------------------------");
            Console.WriteLine("요리사가 요리를 시작합니다.");

            foreach (string menuName in menu._menuList)
                Console.WriteLine(menuName);

            Console.WriteLine("요리가 완료되었습니다.");
            Console.WriteLine("------------------------------------");
        }
    }

    // 메뉴를 List에 저장합니다.
    class Menu
    {
        public List<string> _menuList = new List<string>();

        public void addMenu(string menuName)
        {
            _menuList.Add(menuName);
        }
    }

    class baekTest
    {
        static void Main(string[] args)
        {
        	// 키오스크(Kiosk)와 Cooker(주방장) 객체를 생성합니다.
            Cooker cooker = new Cooker();
            Kiosk kiosk = new Kiosk(cooker);

			// 메뉴를 선택합니다.
            Menu menu = new Menu();
            menu.addMenu("파스타");
            menu.addMenu("콜라");

			// 커맨드 객체를 생성합니다.
            // OrderPushCommand 생성 시 menu를 전달합니다.
            Command orderPushCommand = new OrderPushCommand(menu);
            Command orderPopCommand = new OrderPopCommand();

			// 커맨드를 실행 할 키오스를 set 합니다.
            orderPushCommand.setKiosk(kiosk);
            orderPopCommand.setKiosk(kiosk);
            
            // 커맨드를 실행합니다.
            orderPushCommand.execute();
            orderPopCommand.execute();
        }
    }

예제 코드를 실행 시 위와 같은 결과가 나오게 됩니다.

  • 키오스크(Kiosk) 객체의 메서드를 직접 실행하는게 아니라 커맨드를 사용해서 메서드 실행합니다.
  • 커맨드를 통해 키오스크의 메서드들이 추상화 되어 다른 객체에 노출이 되지 않습니다.
  • 주문 큐를 키오스크에서 관리합니다.
    => 키오스크 기계에 저장되어야 한다고 생각해서 이렇게 구현했습니다.

구현하면서 키오스크 객체에서 메서드를 직접 실행하는 방식보다 좀 더 간결하고,
커맨드를 List 형식으로 저장해서 한번에 실행도 가능할 것 같다고 생각했습니다.

디자인 패턴을 단순히 예제 코드를 따라 치는게 아니라,
다른 상황과 연결 시켜서 직접 구현보았습니다.



참고 자료


  • [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버 => 링크
  • Refactoring guru - 커맨드 패턴 => 링크
  • 위키백과 - 커맨드 패턴 ⇒ 링크
  • Tecoble - 전략패턴과 커맨드패턴 => 링크
  • 유튜브 <코드 없는 프로그래밍> - 디자인 패턴, Command Pattern.. => 링크
  • 얄코(yalco) - 객체지향 디자인 패턴 1 => 링크
profile
기술에 대한 고민과 배운 것을 회고하는 게임 서버 개발자의 블로그입니다.

0개의 댓글