@@ -0,0 +1,112 @@
+package christmas.controller;
+
+import christmas.domain.Badge;
+import christmas.domain.Date;
+import christmas.domain.Menus;
+import christmas.domain.Order;
+import christmas.domain.event.Event;
+import christmas.dto.DiscountAmount;
+import christmas.dto.MenuCount;
+import christmas.exception.PromotionException;
+import christmas.view.InputView;
+import christmas.view.OutputView;
+import java.util.List;
+import java.util.Map;
+
+public class PromotionController {
+    private final InputView inputView = new InputView();
+    private final OutputView outputView = new OutputView();
+    private Order order;
+
+    public void run() {
+        this.order = createOrder();
+        showPlan();
+        showBadge();
+    }
+
+    private Order createOrder() {
+        Date date = askVisitDate();
+        while (true) {
+            try {
+                Menus menus = askMenus();
+                return new Order(date, menus);
+            } catch (PromotionException e) {
+                outputView.printErrorMessage(e);
+            }
+        }
+    }
+
+    private Date askVisitDate() {
+        while (true) {
+            try {
+                return new Date(inputView.readVisitDate());
+            } catch (PromotionException e) {
+                outputView.printErrorMessage(e);
+            }
+        }
+    }
+
+    private Menus askMenus() {
+        while (true) {
+            try {
+                List<String> input = inputView.readMenus();
+                Menus menus = new Menus();
+                input.stream()
+                        .map(menu -> Parser.parseMenu(menu, "-"))
+                        .forEach(menuCount -> menus.add(menuCount.menu(), menuCount.count()));
+                return menus;
+            } catch (PromotionException e) {
+                outputView.printErrorMessage(e);
+            }
+        }
+    }
+
+    private void showPlan() {
+        outputView.printPlanHeader(order.getDate());
+        showOrder();
+        showTotalAmount();
+        showGiveaway();
+        showBenefitDetails();
+        showTotalBenefit();
+        showFinalAmount();
+    }
+
+    private void showTotalAmount() {
+        outputView.printTotalAmount(order.totalAmount());
+    }
+
+    private void showOrder() {
+        List<MenuCount> menuCounts = order.getOrderMenu().entrySet()
+                .stream()
+                .map(MenuCount::apply)
+                .toList();
+        outputView.printOrder(menuCounts);
+    }
+
+    private void showGiveaway() {
+        outputView.printGiveaway(order.giveGiveaway());
+    }
+
+    private void showBenefitDetails() {
+        Map<Event, Integer> details = order.benefitDetails();
+
+        List<DiscountAmount> discountAmounts = details.entrySet().stream()
+                .map(DiscountAmount::apply)
+                .toList();
+        outputView.printBenefitDetails(discountAmounts);
+    }
+
+    private void showTotalBenefit() {
+        int totalBenefit = order.totalBenefit();
+        outputView.printTotalBenefit(totalBenefit);
+    }
+
+    private void showFinalAmount() {
+        outputView.printFinalAmount(order.finalAmount());
+    }
+
+    private void showBadge() {
+        Badge badge = Badge.fromBenefit(order.totalBenefit());
+        outputView.printBadge(badge.displayName());
+    }
+}

리뷰: Meun 생성시에 인자로 받는 것이 만들고 나서 add하는것 보다 저 좋다고 생각합니다.
Menu가 add되기 전까지는 빈 메뉴인 상태가 유지되니까요. 그리고 불변 객체 문제도 있겠네요.

- 참고 : [블로그 글](https://velog.io/@conatuseus/Java-Immutable-Object%EB%B6%88%EB%B3%80%EA%B0%9D%EC%B2%B4#immutable-object%EC%9D%98-%EC%9E%A5%EB%8B%A8%EC%A0%90)
  - 굳이 가변객체로 만들 이유는 없을 것 같습니다.