ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,74 @@
+package christmas.controller;
+
+import christmas.constant.Menu;
+import christmas.domain.BenefitStorage;
+import christmas.dto.BenefitResult;
+import christmas.domain.Customer;
+import christmas.domain.EventPlanner;
+import christmas.dto.OrderMenu;
+import christmas.exception.ExceptionHandler;
+import christmas.view.InputView;
+import christmas.view.OutputView;
+import java.util.Map;
+
+public class ChristmasController {
+
+    private final ExceptionHandler handler;
+    private Customer customer;
+    private EventPlanner eventPlanner;
+
+
+    public ChristmasController(ExceptionHandler handler){
+        this.handler = handler;
+    }
+
+    public void service(){
+        order();
+        searchPromotion(customer);
+    }
+
+    public void order(){
+        int date = getDate();
+        Map<Menu, Integer> menu = getMenu();
+        customer = new Customer(date, menu);
+
+        displayOrder(date, menu);
+    }
+
+    private int getDate(){
+        return handler.getResult(InputView::readVisitDate);
+    }
+
+    private Map<Menu, Integer> getMenu(){
+        return handler.getResult(InputView::readMenu);
+    }
+
+    private void searchPromotion(Customer customer){
+        eventPlanner = new EventPlanner();
+        eventPlanner.findPromotion(customer);
+
+        BenefitStorage benefitStorage = storeBenefits();
+        previewEventBenefits(benefitStorage);
+    }
+
+    private BenefitStorage storeBenefits(){
+        if(eventPlanner.hasGiftMenu()){
+            return new BenefitStorage(customer.getTotalOrderAmount(), true, eventPlanner.getPromotionResult());
+        }
+        return new BenefitStorage(customer.getTotalOrderAmount(), false, eventPlanner.getPromotionResult());
+    }
+
+    private void displayOrder(int date, Map<Menu, Integer> menu){
+        OrderMenu orderMenu = new OrderMenu(date, menu);
+        OutputView.printOrder(orderMenu);
+    }
+
+
+    private void previewEventBenefits(BenefitStorage benefitStorage){
+        BenefitResult benefitResult = new BenefitResult(benefitStorage.getBeforeDiscountAmount(),
+                benefitStorage.isGiftMenu(), benefitStorage.getPromotionResult(), benefitStorage.totalBenefitAmount(),
+                benefitStorage.afterDiscountAmount(), benefitStorage.determineBadge());
+        OutputView.printPreview(benefitResult);
+    }
+
+}

리뷰: 사소하지만 네이밍을 `OrderedMenu` 로 하면 어떨까요?
@@ -0,0 +1,74 @@
+package christmas.controller;
+
+import christmas.constant.Menu;
+import christmas.domain.BenefitStorage;
+import christmas.dto.BenefitResult;
+import christmas.domain.Customer;
+import christmas.domain.EventPlanner;
+import christmas.dto.OrderMenu;
+import christmas.exception.ExceptionHandler;
+import christmas.view.InputView;
+import christmas.view.OutputView;
+import java.util.Map;
+
+public class ChristmasController {
+
+    private final ExceptionHandler handler;
+    private Customer customer;
+    private EventPlanner eventPlanner;
+
+
+    public ChristmasController(ExceptionHandler handler){
+        this.handler = handler;
+    }
+
+    public void service(){
+        order();
+        searchPromotion(customer);
+    }
+
+    public void order(){
+        int date = getDate();
+        Map<Menu, Integer> menu = getMenu();
+        customer = new Customer(date, menu);
+
+        displayOrder(date, menu);
+    }
+
+    private int getDate(){
+        return handler.getResult(InputView::readVisitDate);
+    }
+
+    private Map<Menu, Integer> getMenu(){
+        return handler.getResult(InputView::readMenu);
+    }
+
+    private void searchPromotion(Customer customer){
+        eventPlanner = new EventPlanner();
+        eventPlanner.findPromotion(customer);
+
+        BenefitStorage benefitStorage = storeBenefits();
+        previewEventBenefits(benefitStorage);
+    }
+
+    private BenefitStorage storeBenefits(){
+        if(eventPlanner.hasGiftMenu()){
+            return new BenefitStorage(customer.getTotalOrderAmount(), true, eventPlanner.getPromotionResult());
+        }
+        return new BenefitStorage(customer.getTotalOrderAmount(), false, eventPlanner.getPromotionResult());
+    }
+
+    private void displayOrder(int date, Map<Menu, Integer> menu){
+        OrderMenu orderMenu = new OrderMenu(date, menu);
+        OutputView.printOrder(orderMenu);
+    }
+
+
+    private void previewEventBenefits(BenefitStorage benefitStorage){
+        BenefitResult benefitResult = new BenefitResult(benefitStorage.getBeforeDiscountAmount(),
+                benefitStorage.isGiftMenu(), benefitStorage.getPromotionResult(), benefitStorage.totalBenefitAmount(),
+                benefitStorage.afterDiscountAmount(), benefitStorage.determineBadge());
+        OutputView.printPreview(benefitResult);
+    }
+
+}

리뷰: `customer = new Customer(getDate(), getMenu());`
로 한번에 해도 좋을 거 같아요.
`getDate()` 나 `getMenu()` 둘 다 메서드 이름으로 뭐를 하는지 정확히 알 수 있어보입니다.
@@ -0,0 +1,55 @@
+package christmas.domain;
+
+import christmas.constant.Badge;
+import christmas.constant.Menu;
+import christmas.domain.promotion.ChristmasPromotion;
+import java.util.Arrays;
+import java.util.HashMap;
+
+public class BenefitStorage {
+
+    private final long beforeDiscountAmount;
+    private final boolean giftMenu;
+    private final HashMap<ChristmasPromotion, Long> promotionResult;
+
+    public BenefitStorage(long beforeDiscountAmount, boolean giftMenu, HashMap<ChristmasPromotion, Long> promotionResult){
+        this.beforeDiscountAmount = beforeDiscountAmount;
+        this.giftMenu = giftMenu;
+        this.promotionResult = promotionResult;
+    }
+
+    public long totalBenefitAmount() {
+        return promotionResult.values().stream().mapToLong(Long::longValue).sum();
+    }
+
+    public long afterDiscountAmount() {
+        long totalBenefit = totalBenefitAmount();
+
+        if (giftMenu) {
+            totalBenefit -= Menu.CHAMPAGNE.getPrice();
+        }
+
+        return beforeDiscountAmount - totalBenefit;
+    }
+
+    public Badge determineBadge() {
+        long totalBenefit = totalBenefitAmount();
+
+        return Arrays.stream(Badge.values())
+                .filter(badge -> totalBenefit >= badge.getPrize())
+                .reduce((first, second) -> second)
+                .orElse(Badge.NONE);
+    }
+
+    public long getBeforeDiscountAmount() {
+        return beforeDiscountAmount;
+    }
+
+    public boolean isGiftMenu() {
+        return giftMenu;
+    }
+
+    public HashMap<ChristmasPromotion, Long> getPromotionResult() {
+        return promotionResult;
+    }
+}

리뷰: Map 타입으로 인스턴스 변수를 가지면 추후
세부 구현 자료구조가 바뀔 때 능동적으로 대처할 수 있을거 같아요!
@@ -0,0 +1,55 @@
+package christmas.domain;
+
+import christmas.constant.Badge;
+import christmas.constant.Menu;
+import christmas.domain.promotion.ChristmasPromotion;
+import java.util.Arrays;
+import java.util.HashMap;
+
+public class BenefitStorage {
+
+    private final long beforeDiscountAmount;
+    private final boolean giftMenu;
+    private final HashMap<ChristmasPromotion, Long> promotionResult;
+
+    public BenefitStorage(long beforeDiscountAmount, boolean giftMenu, HashMap<ChristmasPromotion, Long> promotionResult){
+        this.beforeDiscountAmount = beforeDiscountAmount;
+        this.giftMenu = giftMenu;
+        this.promotionResult = promotionResult;
+    }
+
+    public long totalBenefitAmount() {
+        return promotionResult.values().stream().mapToLong(Long::longValue).sum();
+    }
+
+    public long afterDiscountAmount() {
+        long totalBenefit = totalBenefitAmount();
+
+        if (giftMenu) {
+            totalBenefit -= Menu.CHAMPAGNE.getPrice();
+        }
+
+        return beforeDiscountAmount - totalBenefit;
+    }
+
+    public Badge determineBadge() {
+        long totalBenefit = totalBenefitAmount();
+
+        return Arrays.stream(Badge.values())
+                .filter(badge -> totalBenefit >= badge.getPrize())
+                .reduce((first, second) -> second)
+                .orElse(Badge.NONE);
+    }
+
+    public long getBeforeDiscountAmount() {
+        return beforeDiscountAmount;
+    }
+
+    public boolean isGiftMenu() {
+        return giftMenu;
+    }
+
+    public HashMap<ChristmasPromotion, Long> getPromotionResult() {
+        return promotionResult;
+    }
+}

리뷰: 어찌보면 Dto에 가까운 성격을 가지는 클래스인데
도메인 로직을 다 넣어둔 느낌을 받았습니다.
결국 출력때 필요한 자료들을 다 가지고 있어서
도메인을 다른 방식으로 분리해보는 것을 고려해보면 어떨까요?
@@ -0,0 +1,71 @@
+package christmas.domain;
+
+import christmas.constant.MenuType;
+import christmas.constant.PromotionType;
+import christmas.domain.promotion.ChristmasPromotion;
+import christmas.domain.promotion.DdayPromotion;
+import christmas.domain.promotion.GiftPromotion;
+import christmas.domain.promotion.SpecialPromotion;
+import christmas.domain.promotion.WeekDayPromotion;
+import christmas.domain.promotion.WeekendPromotion;
+import java.util.HashMap;
+import java.util.Map;
+
+public class EventPlanner {
+    private final HashMap<ChristmasPromotion, Long> promotionResult;
+
+    public EventPlanner(){
+        promotionResult = new HashMap<>();
+        promotionResult.put(new DdayPromotion(), 0L);
+        promotionResult.put(new GiftPromotion(), 0L);
+        promotionResult.put(new SpecialPromotion(), 0L);
+        promotionResult.put(new WeekDayPromotion(), 0L);
+        promotionResult.put(new WeekendPromotion(), 0L);
+    }
+
+    public void findPromotion(Customer customer){
+        for(ChristmasPromotion promotion : promotionResult.keySet()){
+            checkPromotionConditions(promotion, customer);
+        }
+    }
+
+    public boolean hasGiftMenu(){
+        return promotionResult.entrySet()
+                .stream()
+                .filter(entry -> entry.getKey() instanceof GiftPromotion)
+                .mapToLong(Map.Entry::getValue)
+                .sum() > 0;
+    }
+
+    public HashMap<ChristmasPromotion, Long> getPromotionResult(){
+        return promotionResult;
+    }
+
+    private void checkPromotionConditions(ChristmasPromotion promotion, Customer customer){
+        long discount = customer.applicablePromotion(promotion);
+
+        if (isContainWeekOrWeekend(promotion)) {
+            discount *= checkMenuCount(customer, promotion.getPromotionType());
+        }
+        promotionResult.put(promotion, promotionResult.get(promotion) + discount);
+    }
+
+    private int checkMenuCount(Customer customer, PromotionType promotionType) {
+        Map<PromotionType, MenuType> promotionTypeMenuTypeMap = Map.of(
+                PromotionType.WEEKDAY, MenuType.DESSERT,
+                PromotionType.WEEKEND, MenuType.MAIN
+        );
+
+        MenuType menuType = promotionTypeMenuTypeMap.getOrDefault(promotionType, MenuType.NONE);
+        return customer.countMenuType(menuType);
+    }
+
+    private boolean isContainWeekOrWeekend(ChristmasPromotion promotion){
+        if(promotion.getPromotionType() == PromotionType.WEEKDAY
+                || promotion.getPromotionType() == PromotionType.WEEKEND)
+            return true;
+
+        return false;
+    }
+
+}

리뷰: 변수 명에 Map 을 사용하는 것보다는 `PromotionsAppliedToEachMenu` 와 같이 사용하는 것은 어떨까요?
@@ -0,0 +1,43 @@
+package christmas.domain.promotion;
+
+import christmas.constant.PromotionItem;
+import christmas.constant.PromotionType;
+import java.util.Arrays;
+
+public class DdayPromotion extends ChristmasPromotion{
+
+    private static final int START_DATE = 1;
+    private static final int END_DATE = 25;
+    private static final int INIT_DISCOUNT_AMOUNT = 1000;
+    private static final int MIN_ORDER_AMOUNT = 10000;
+
+
+    public DdayPromotion(){
+        this.period = Arrays.asList(START_DATE, END_DATE);
+        this.targetItems = PromotionItem.TOTAL_ORDER_AMOUNT;
+        this.discountAmount = INIT_DISCOUNT_AMOUNT;
+        this.promotionType = PromotionType.DDAY;
+    }
+
+    @Override
+    public long applyPromotion(int data, long orderAmount){
+        if(isApplicable(data) && isEligibleForPromotion(orderAmount)){
+            return getDiscountAmount(data);
+        }
+        return 0L;
+    }
+
+    @Override
+    protected boolean isApplicable(int date) {
+        return date >= period.get(0) && date <= period.get(1);
+    }
+
+    @Override
+    protected boolean isEligibleForPromotion(long orderAmount){
+        return orderAmount >= MIN_ORDER_AMOUNT;
+    }
+
+    public long getDiscountAmount(int date) {
+        return discountAmount + 100L * (date - 1);
+    }
+}

리뷰: 매직넘버를 상수로 두는건 어떨까요?
@@ -0,0 +1,39 @@
+package christmas.domain.promotion;
+
+import christmas.constant.PromotionItem;
+import christmas.constant.PromotionType;
+import java.util.Arrays;
+
+public class GiftPromotion extends ChristmasPromotion{
+
+    private static final long PRICETHRESHOLD = 120000;
+    private static final int START_DATE = 1;
+    private static final int END_DATE = 31;
+    private static final int INIT_DISCOUNT_AMOUNT = 25000;
+
+    public GiftPromotion(){
+        this.period = Arrays.asList(START_DATE, END_DATE);
+        this.targetItems = PromotionItem.GIFT_CHAMPAGNE;
+        this.discountAmount = INIT_DISCOUNT_AMOUNT;
+        this.promotionType = PromotionType.GIFT;
+    }
+
+    @Override
+    public long applyPromotion(int data, long orderAmount){
+        if(isApplicable(data) && isEligibleForPromotion(orderAmount)){
+            return getDiscountAmount();
+        }
+        return 0L;
+    }
+
+    @Override
+    protected boolean isApplicable(int date) {
+        return date >= period.get(0) && date <= period.get(1);
+    }
+
+    @Override
+    protected boolean isEligibleForPromotion(long orderAmount){
+        return orderAmount >= PRICETHRESHOLD;
+    }
+
+}

리뷰: `PRICE_THRESHOLD` 와 같이 나눠주면 가독성이 더 좋아질 것 같습니다!
@@ -0,0 +1,38 @@
+package christmas.domain.promotion;
+
+import christmas.constant.PromotionItem;
+import christmas.constant.PromotionType;
+import java.util.Arrays;
+
+public class SpecialPromotion extends ChristmasPromotion{
+
+    private static final int INIT_DISCOUNT_AMOUNT = 1000;
+    private static final int MIN_ORDER_AMOUNT = 10000;
+
+    public SpecialPromotion(){
+        this.period = Arrays.asList(3, 10, 17, 24, 25, 31);
+        this.targetItems = PromotionItem.TOTAL_ORDER_AMOUNT;
+        this.discountAmount = INIT_DISCOUNT_AMOUNT;
+        this.promotionType = PromotionType.SPECIAL;
+    }
+
+    @Override
+    public long applyPromotion(int data, long orderAmount){
+        if(isApplicable(data) && isEligibleForPromotion(orderAmount)){
+            return getDiscountAmount();
+        }
+        return 0L;
+    }
+
+    @Override
+    protected boolean isApplicable(int date) {
+        return period.contains(date);
+    }
+
+    @Override
+    protected boolean isEligibleForPromotion(long orderAmount){
+        return orderAmount >= MIN_ORDER_AMOUNT;
+    }
+
+
+}

리뷰: 요것도 매직넘버!
혹은 1~31 값 중 7로 나누었을 때 나머지가 3인 날짜로 초기화해줘도 좋을 거 같아요
@@ -0,0 +1,38 @@
+package christmas.domain.promotion;
+
+import christmas.constant.PromotionItem;
+import christmas.constant.PromotionType;
+import java.util.Arrays;
+
+public class SpecialPromotion extends ChristmasPromotion{
+
+    private static final int INIT_DISCOUNT_AMOUNT = 1000;
+    private static final int MIN_ORDER_AMOUNT = 10000;
+
+    public SpecialPromotion(){
+        this.period = Arrays.asList(3, 10, 17, 24, 25, 31);
+        this.targetItems = PromotionItem.TOTAL_ORDER_AMOUNT;
+        this.discountAmount = INIT_DISCOUNT_AMOUNT;
+        this.promotionType = PromotionType.SPECIAL;
+    }
+
+    @Override
+    public long applyPromotion(int data, long orderAmount){
+        if(isApplicable(data) && isEligibleForPromotion(orderAmount)){
+            return getDiscountAmount();
+        }
+        return 0L;
+    }
+
+    @Override
+    protected boolean isApplicable(int date) {
+        return period.contains(date);
+    }
+
+    @Override
+    protected boolean isEligibleForPromotion(long orderAmount){
+        return orderAmount >= MIN_ORDER_AMOUNT;
+    }
+
+
+}

리뷰: 공백도 코딩컨벤션이라, 다른 클래스 파일과 맞춰주는게 어떨까요?
@@ -0,0 +1,47 @@
+package christmas.domain.promotion;
+
+import christmas.constant.PromotionItem;
+import christmas.constant.PromotionType;
+import java.time.LocalDate;
+import java.time.DayOfWeek;
+import java.util.Arrays;
+
+public class WeekDayPromotion extends ChristmasPromotion{
+
+    private static final int START_DATE = 1;
+    private static final int END_DATE = 31;
+    private static final int INIT_DISCOUNT_AMOUNT = 2023;
+    private static final int MIN_ORDER_AMOUNT = 10000;
+
+    public WeekDayPromotion(){
+        this.period = Arrays.asList(START_DATE, END_DATE);
+        this.targetItems = PromotionItem.DESSERT_MENU;
+        this.discountAmount = INIT_DISCOUNT_AMOUNT;
+        this.promotionType = PromotionType.WEEKDAY;
+    }
+
+    @Override
+    public long applyPromotion(int data, long orderAmount){
+        if(isApplicable(data) && isEligibleForPromotion(orderAmount)){
+            return getDiscountAmount();
+        }
+        return 0L;
+    }
+
+    @Override
+    protected boolean isApplicable(int date) {
+        LocalDate orderDate = LocalDate.of(2023, 12, date);
+
+        return isWeekday(orderDate);
+    }
+
+    @Override
+    protected boolean isEligibleForPromotion(long orderAmount){
+        return orderAmount >= MIN_ORDER_AMOUNT;
+    }
+
+    private boolean isWeekday(LocalDate date) {
+        DayOfWeek dayOfWeek = date.getDayOfWeek();
+        return dayOfWeek != DayOfWeek.FRIDAY && dayOfWeek != DayOfWeek.SATURDAY;
+    }
+}

리뷰: 내부 상수로 두는 것보다, 생성될 때 위의 상수 값으로 초기화 시키고
객체를 싱글톤으로 관리하는 것도 좋을 것 같아요
@@ -0,0 +1,7 @@
+package christmas.exception;
+
+import java.util.function.Supplier;
+
+public interface ExceptionHandler {
+    <T> T getResult(Supplier<T> supplier);
+}

리뷰: `Supplier` 라는 문법은 처음보네요! 함수형 프로그래밍? 인가 보네요 ㅎㅎ 배워갑니다.
@@ -0,0 +1,28 @@
+package christmas.exception;
+
+import christmas.view.OutputView;
+import java.util.function.Supplier;
+
+public class RetryExceptionHandler implements ExceptionHandler{
+
+    @Override
+    public <T> T getResult(Supplier<T> supplier) {
+        while (true) {
+            try {
+                return supplier.get();
+            } catch (IllegalArgumentException e) {
+                printException(e);
+            } finally {
+                afterHandlingException();
+            }
+        }
+    }
+
+    private void printException(IllegalArgumentException e) {
+        OutputView.printErrorMessage(e);
+    }
+
+    private void afterHandlingException() {
+        OutputView.printEmptyLine();
+    }
+}

리뷰: 이렇게 하면 try-catch문의 중복 로직을 뺄 수 있겠군요.!
@@ -0,0 +1,44 @@
+package christmas.view;
+
+import christmas.constant.Badge;
+import christmas.constant.OutputMessage;
+import christmas.domain.promotion.ChristmasPromotion;
+import java.util.HashMap;
+
+public class BenefitsView {
+
+    public static String giftMenuOutputStatement(boolean giftMenu){
+        if(giftMenu)
+            return OutputMessage.CHAMPAGNE.getMessage();
+
+        return OutputMessage.DOES_NOT_EXIST.getMessage();
+    }
+
+    public static String promotionResultOutputStatement(long totalBenefitAmount, HashMap<ChristmasPromotion, Long> promotionResult){
+        if(totalBenefitAmount == 0)
+            return OutputMessage.DOES_NOT_EXIST.getMessage();
+
+        return findPromotionDetail(promotionResult).toString();
+    }
+
+    public static String badgeOutputStatement(Badge badge){
+        if(badge == Badge.NONE)
+            return OutputMessage.DOES_NOT_EXIST.getMessage();
+        return badge.getBadgeName();
+    }
+
+    private static StringBuilder findPromotionDetail(HashMap<ChristmasPromotion, Long> promotionResult){
+        StringBuilder sb = new StringBuilder();
+        for(ChristmasPromotion promotion: promotionResult.keySet()){
+            long discount = promotionResult.get(promotion);
+            if(discount == 0) continue;
+
+            sb.append(String.format(OutputMessage.BENEFIT_DETAILS.getMessage(),
+                    promotion.getPromotionType().getMessage(), discount));
+        }
+
+        if(sb.isEmpty())
+            return sb.append(OutputMessage.DOES_NOT_EXIST.getMessage());
+        return sb;
+    }
+}

리뷰: if 문 을 {} 로 감싸주는게 코딩 컨벤션으로 알고 있습니다!
@@ -0,0 +1,74 @@
+package christmas.view;
+
+import christmas.constant.Badge;
+import christmas.constant.Menu;
+import christmas.constant.OutputMessage;
+import christmas.domain.promotion.ChristmasPromotion;
+import christmas.dto.BenefitResult;
+import christmas.dto.OrderMenu;
+import java.util.HashMap;
+import java.util.Map;
+
+public class OutputView {
+
+    public static void printErrorMessage(IllegalArgumentException e){
+        System.out.println(e.getMessage());
+    }
+
+    public static void printEmptyLine(){
+        System.out.println();
+    }
+
+    public static void printOrder(OrderMenu orderMenu){
+        printDate(orderMenu.date());
+        printEmptyLine();
+        printOrderedMenu(orderMenu.menu());
+    }
+
+    public static void printPreview(BenefitResult benefits){
+        printBeforeDiscountAmount(benefits.beforeDiscountAmount());
+        printHasGift(benefits.giftMenu());
+        printBenefitsDetail(benefits.beforeDiscountAmount(), benefits.promotionResult());
+        printTotalBenefits(benefits.totalBenefitAmount());
+        printAfterDiscountAmount(benefits.afterDiscountAmount());
+        printBadge(benefits.badge());
+    }
+
+    private static void printOrderedMenu(Map<Menu, Integer> orderMenu){
+        System.out.println(String.format(OutputMessage.ORDER_MENU_PREFIX.getMessage(),
+                OrderMenuView.orderMenuOutputStatement(orderMenu)));
+    }
+
+    private static void printDate(int date){
+        System.out.println(String.format(OutputMessage.RESERVATION_DATE.getMessage(), date));
+    }
+
+    private static void printBeforeDiscountAmount(long total){
+        System.out.println(String.format(OutputMessage.BEFORE_DISCOUNT_AMOUNT.getMessage(), total));
+    }
+
+    private static void printHasGift(boolean hasGift){
+        System.out.println(String.format(OutputMessage.GIVEAWAY_MENU.getMessage(),
+                BenefitsView.giftMenuOutputStatement(hasGift)));
+
+    }
+
+    private static void printBenefitsDetail(long price, HashMap<ChristmasPromotion, Long> result){
+        System.out.println(String.format(OutputMessage.BENEFIT_DETAILS_PREFIX.getMessage(),
+                BenefitsView.promotionResultOutputStatement(price, result)));
+    }
+
+    private static void printTotalBenefits(long price){
+        System.out.println(String.format(OutputMessage.TOTAL_BENEFIT_AMOUNT.getMessage(), -price));
+    }
+
+    private static void printAfterDiscountAmount(long price){
+        System.out.println(String.format(OutputMessage.AFTER_DISCOUNT_AMOUNT.getMessage(), price));
+    }
+
+    private static void printBadge(Badge badge){
+        System.out.println(String.format(OutputMessage.PROMOTION_BADGE.getMessage(),
+                BenefitsView.badgeOutputStatement(badge)));
+    }
+
+}

리뷰: 예외를 직접 받는 것보다
예외를 던지는 쪽에서 e.getMessage() 로 String 값을 던져주면
메서드가 좀 더 범용성이 있을 것 같습니다.
@@ -0,0 +1,27 @@
+package christmas.constant;
+
+public enum OutputMessage {
+
+    RESERVATION_DATE("12월 %d일에 우테코 식당에서 받을 이벤트 혜택 미리 보기!"),
+    ORDER_MENU_PREFIX("<주문 메뉴>%n%s"),
+    ORDER_MENU("%s %d개\n"),
+    BEFORE_DISCOUNT_AMOUNT("<할인 전 총주문 금액>%n%,d원\n"),
+    GIVEAWAY_MENU("<증정 메뉴>%n%s"),
+    DOES_NOT_EXIST("없음\n"),
+    CHAMPAGNE("샴페인 1개\n"),
+    BENEFIT_DETAILS_PREFIX("<혜택 내역>%n%s"),
+    BENEFIT_DETAILS("%s: %,d원\n"),
+    TOTAL_BENEFIT_AMOUNT("<총혜택 금액>%n%,d원\n"),
+    AFTER_DISCOUNT_AMOUNT("<할인 후 예상 결제 금액>%n%,d원\n"),
+    PROMOTION_BADGE("<12월 이벤트 배지>%n%s\n");
+
+    private final String message;
+
+    OutputMessage(String message) {
+        this.message = message;
+    }
+
+    public String getMessage(){
+        return this.message;
+    }
+}

리뷰: 개행문자를 System.lineseparator() 로 처리하는걸 추천드립니다! 운영체제 별로 개행문자 표현이 상이할 수 있거든요!