ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -1,29 +1,40 @@
 package lotto;
 
-import lotto.domain.*;
+import lotto.domain.LottoGame;
+import lotto.domain.LottoPrize;
+import lotto.domain.LottoTicket;
+import lotto.domain.WinningLotto;
 import lotto.view.LottoInputView;
 import lotto.view.LottoResultView;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class LottoGameApplication {
 
     public static void main(String[] args) {
-        int moneyForTicket = LottoInputView.getMoneyForTicket();
-        List<LottoTicket> tickets = LottoGame.buy(moneyForTicket);
-
-        LottoResultView.printTickets(tickets);
-
-        if (tickets.isEmpty()) {
-            return;
+        try {
+            List<List<Integer>> numbersForManualTicket = new ArrayList<>();
+            int moneyForTicket = LottoInputView.getMoneyForTicket();
+            int numberOfManualTickets = LottoInputView.getNumberOfManualTicket();
+            if (numberOfManualTickets > 0) {
+                numbersForManualTicket = LottoInputView.getLottoTicketNumbers(numberOfManualTickets);
+            }
+            List<LottoTicket> tickets = LottoGame.buy(moneyForTicket, numbersForManualTicket);
+
+            LottoResultView.printTickets(tickets, numberOfManualTickets);
+
+            if (tickets.isEmpty()) {
+                return;
+            }
+
+            WinningLotto lastWeekWinningLotto = new WinningLotto(LottoInputView.getLastWeekWinnerNumber(), LottoInputView.getLastWeekBonusNumber());
+            List<LottoPrize> prizes = lastWeekWinningLotto.prizes(tickets);
+
+            LottoResultView.printResult(prizes, tickets.size());
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
         }
 
-        LottoTicket lastWeekWinnerTicket = LottoTicket.createFromIntegerList(LottoInputView.getLastWeekWinnerNumber());
-        LottoNumber lastWeekBonusNumber = new LottoNumber(LottoInputView.getLastWeekBonusNumber());
-        WinningLotto lastWeekWinningLotto = new WinningLotto(lastWeekWinnerTicket, lastWeekBonusNumber);
-
-        List<LottoPrize> prizes = lastWeekWinningLotto.prizes(tickets);
-
-        LottoResultView.printResult(prizes, tickets.size());
     }
 }

리뷰: <img width="295" alt="스크린샷 2022-11-16 오전 1 54 53" src="https://user-images.githubusercontent.com/18049492/201979676-12c7da76-8473-4db8-a2c6-5050921f04f1.png">

수익률 계산 로직도 점검해 볼까요?
@@ -1,29 +1,40 @@
 package lotto;
 
-import lotto.domain.*;
+import lotto.domain.LottoGame;
+import lotto.domain.LottoPrize;
+import lotto.domain.LottoTicket;
+import lotto.domain.WinningLotto;
 import lotto.view.LottoInputView;
 import lotto.view.LottoResultView;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class LottoGameApplication {
 
     public static void main(String[] args) {
-        int moneyForTicket = LottoInputView.getMoneyForTicket();
-        List<LottoTicket> tickets = LottoGame.buy(moneyForTicket);
-
-        LottoResultView.printTickets(tickets);
-
-        if (tickets.isEmpty()) {
-            return;
+        try {
+            List<List<Integer>> numbersForManualTicket = new ArrayList<>();
+            int moneyForTicket = LottoInputView.getMoneyForTicket();
+            int numberOfManualTickets = LottoInputView.getNumberOfManualTicket();
+            if (numberOfManualTickets > 0) {
+                numbersForManualTicket = LottoInputView.getLottoTicketNumbers(numberOfManualTickets);
+            }
+            List<LottoTicket> tickets = LottoGame.buy(moneyForTicket, numbersForManualTicket);
+
+            LottoResultView.printTickets(tickets, numberOfManualTickets);
+
+            if (tickets.isEmpty()) {
+                return;
+            }
+
+            WinningLotto lastWeekWinningLotto = new WinningLotto(LottoInputView.getLastWeekWinnerNumber(), LottoInputView.getLastWeekBonusNumber());
+            List<LottoPrize> prizes = lastWeekWinningLotto.prizes(tickets);
+
+            LottoResultView.printResult(prizes, tickets.size());
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
         }
 
-        LottoTicket lastWeekWinnerTicket = LottoTicket.createFromIntegerList(LottoInputView.getLastWeekWinnerNumber());
-        LottoNumber lastWeekBonusNumber = new LottoNumber(LottoInputView.getLastWeekBonusNumber());
-        WinningLotto lastWeekWinningLotto = new WinningLotto(lastWeekWinnerTicket, lastWeekBonusNumber);
-
-        List<LottoPrize> prizes = lastWeekWinningLotto.prizes(tickets);
-
-        LottoResultView.printResult(prizes, tickets.size());
     }
 }

리뷰: 그러고 보니 2등 출력 시 금액이 "보너스 볼 일치" 텍스트 뒤로 와야 할 것 같아요~
@@ -15,8 +15,9 @@ public class LottoResultView {
     public static final String RESULT_OUTPUT_COMMENT = "당첨 통계\n---------";
     public static final String BONUS_MATCH_COMMENT = ", 보너스 볼 일치";
 
-    public static void printTickets(List<LottoTicket> ticketList) {
-        System.out.println(ticketList.size() + "개를 구매했습니다.");
+    public static void printTickets(List<LottoTicket> ticketList, int numberOfManualTickets) {
+        int numberOfAutoTickets = ticketList.size() - numberOfManualTickets;
+        System.out.println(String.format("수동으로 %d장, 자동으로 %d개를 구매했습니다.", numberOfManualTickets, numberOfAutoTickets));
         ticketList.stream()
                 .map(LottoTicket::getNumbers)
                 .map(numbers -> numbers.stream().map(Object::toString).collect(Collectors.joining(", ", "[", "]")))

리뷰: `\n`은 항상 개행을 보장하지 않아요. 관련하여 학습해 보고 수정해 주시면 좋을 것 같아요~
@@ -0,0 +1,80 @@
+package christmas.controller;
+
+import christmas.domain.BenefitCalculationFactory;
+import christmas.domain.Benefits;
+import christmas.domain.EventPlanner;
+import christmas.domain.Order;
+import christmas.dtos.OrderLineDto;
+import christmas.util.OrderLineMapper;
+import christmas.view.ErrorMessage;
+import christmas.view.InputView;
+import christmas.view.OutputView;
+import java.time.LocalDate;
+import java.util.List;
+
+public class ChristmasController {
+
+    public static void run() {
+        OutputView.printWelcomeMessage();
+        int day = getExpectedVisitDate();
+
+        Order order = getOrder();
+
+        LocalDate orderDate = LocalDate.of(2023, 12, day);
+
+        Benefits benefits = BenefitCalculationFactory.calculateBenefits(order, orderDate);
+
+        OutputView.printBenefitPreviewMessage(orderDate);
+
+        EventPlanner.printPreview(order, benefits);
+    }
+
+    public static Order getOrder() {
+        try {
+            OutputView.printOrderMenuMessage();
+            List<OrderLineDto> dtos = InputView.readMenus();
+            validateDuplicateMenus(dtos);
+
+            Order order = new Order(OrderLineMapper.orderLineDtosToOrderLines(dtos));
+
+            return order;
+        } catch (IllegalArgumentException e) {
+            OutputView.printExceptionMessage(e);
+            return getOrder();
+        }
+    }
+
+
+    public static int getExpectedVisitDate() {
+        try {
+            OutputView.printExpectedVisitDateMessage();
+            int day = InputView.readInteger();
+            validateExpectedVisitDate(day);
+            return day;
+        } catch (IllegalArgumentException e) {
+
+            System.out.println(e.getMessage());
+            System.out.println(e.getClass());
+            OutputView.printExceptionMessage(e);
+            return getExpectedVisitDate();
+        }
+    }
+
+    private static void validateExpectedVisitDate(int day) {
+        if (day < 1 || day > 31) {
+            throw new IllegalArgumentException(ErrorMessage.INVALID_DATE_INPUT.getMessage());
+        }
+    }
+
+    private static void validateDuplicateMenus(List<OrderLineDto> dtos) {
+        int originalSize = dtos.size();
+        int distinctSize = (int) dtos.stream()
+            .map(OrderLineDto::getMenuDetail)
+            .distinct()
+            .count();
+
+        if (originalSize != distinctSize) {
+            throw new IllegalArgumentException(ErrorMessage.DUPLICATE_MENU_INPUT.getMessage());
+        }
+    }
+}

리뷰: try ~ catch 문이 계속 반복되고 있고 비즈니스 로직과 섞여 있어 비즈니스 로직과 분리를 하면 좋을 듯 합니다. 알고 계실지도 모르겠으나 AOP에 대해 한번 찾아 보시는 것을 추천 드립니다. 

추가적으로 try ~ catch 문을 분리하는 방법에는 프록시 패턴, 펑셔널 인터페이스 활용 등 여러 방법이 있으니 한번 찾아보시는 것을 추천드립니다.
@@ -0,0 +1,47 @@
+package christmas.domain;
+
+import static christmas.domain.MenuDiscountType.WEEKDAYS;
+import static christmas.domain.MenuDiscountType.WEEKENDS;
+
+import java.time.LocalDate;
+
+public class MenuDiscount {
+
+    private static final int WEEKDAYS_DISCOUNT = 2023;
+    private static final int WEEKENDS_DISCOUNT = 2023;
+    private static final MenuDiscount NONE = new MenuDiscount(Money.ZERO, MenuDiscountType.NONE);
+    private Money money;
+    private MenuDiscountType type;
+
+    private MenuDiscount(Money money, MenuDiscountType type) {
+        this.money = money;
+        this.type = type;
+    }
+
+
+    public static MenuDiscount of(OrderLine orderLine, LocalDate localDate) {
+        MenuDiscountType type = MenuDiscountType.findByLocalDate(localDate);
+
+        if (type == WEEKDAYS && orderLine.isDessert()) {
+            return new MenuDiscount(
+                new Money(WEEKDAYS_DISCOUNT).multiply(orderLine.getQuantity()), WEEKDAYS);
+        }
+        if (type == WEEKENDS && orderLine.isMain()) {
+            return new MenuDiscount(
+                new Money(WEEKENDS_DISCOUNT).multiply(orderLine.getQuantity()), WEEKENDS);
+        }
+        return NONE;
+    }
+
+    public boolean isWeekdays() {
+        return type == WEEKDAYS;
+    }
+
+    public boolean isWeekends() {
+        return type == WEEKENDS;
+    }
+
+    public Money getMoney() {
+        return money;
+    }
+}

리뷰: 같은 값인데 두개의 변수로 나눈 이유가 있으실까요?
@@ -0,0 +1,26 @@
+package christmas.dtos;
+
+import christmas.domain.BenefitType;
+
+public class BenefitDto {
+
+    private BenefitType benefitType;
+    private int discountAmount;
+
+    BenefitDto(BenefitType benefitType, int discountAmount) {
+        this.benefitType = benefitType;
+        this.discountAmount = discountAmount;
+    }
+
+    public static BenefitDto toDto(BenefitType benefitType, int discountAmount) {
+        return new BenefitDto(benefitType, discountAmount);
+    }
+
+    public BenefitType getBenefitType() {
+        return benefitType;
+    }
+
+    public int getDiscountAmount() {
+        return discountAmount;
+    }
+}

리뷰: 사실 dto가 많지는 않아서 dto 내부에서 바로 도메인으로 변경해도 상관은 없겠으나 나중에는 dto <-> domain을 변환해주는 mapper 를 만드는 것도 좋을 듯 합니다.
@@ -0,0 +1,80 @@
+package christmas.controller;
+
+import christmas.domain.BenefitCalculationFactory;
+import christmas.domain.Benefits;
+import christmas.domain.EventPlanner;
+import christmas.domain.Order;
+import christmas.dtos.OrderLineDto;
+import christmas.util.OrderLineMapper;
+import christmas.view.ErrorMessage;
+import christmas.view.InputView;
+import christmas.view.OutputView;
+import java.time.LocalDate;
+import java.util.List;
+
+public class ChristmasController {
+
+    public static void run() {
+        OutputView.printWelcomeMessage();
+        int day = getExpectedVisitDate();
+
+        Order order = getOrder();
+
+        LocalDate orderDate = LocalDate.of(2023, 12, day);
+
+        Benefits benefits = BenefitCalculationFactory.calculateBenefits(order, orderDate);
+
+        OutputView.printBenefitPreviewMessage(orderDate);
+
+        EventPlanner.printPreview(order, benefits);
+    }
+
+    public static Order getOrder() {
+        try {
+            OutputView.printOrderMenuMessage();
+            List<OrderLineDto> dtos = InputView.readMenus();
+            validateDuplicateMenus(dtos);
+
+            Order order = new Order(OrderLineMapper.orderLineDtosToOrderLines(dtos));
+
+            return order;
+        } catch (IllegalArgumentException e) {
+            OutputView.printExceptionMessage(e);
+            return getOrder();
+        }
+    }
+
+
+    public static int getExpectedVisitDate() {
+        try {
+            OutputView.printExpectedVisitDateMessage();
+            int day = InputView.readInteger();
+            validateExpectedVisitDate(day);
+            return day;
+        } catch (IllegalArgumentException e) {
+
+            System.out.println(e.getMessage());
+            System.out.println(e.getClass());
+            OutputView.printExceptionMessage(e);
+            return getExpectedVisitDate();
+        }
+    }
+
+    private static void validateExpectedVisitDate(int day) {
+        if (day < 1 || day > 31) {
+            throw new IllegalArgumentException(ErrorMessage.INVALID_DATE_INPUT.getMessage());
+        }
+    }
+
+    private static void validateDuplicateMenus(List<OrderLineDto> dtos) {
+        int originalSize = dtos.size();
+        int distinctSize = (int) dtos.stream()
+            .map(OrderLineDto::getMenuDetail)
+            .distinct()
+            .count();
+
+        if (originalSize != distinctSize) {
+            throw new IllegalArgumentException(ErrorMessage.DUPLICATE_MENU_INPUT.getMessage());
+        }
+    }
+}

리뷰: 감사합니다. 저도 작성하면서 잘못 되었다는 것을 느꼈는데, 효율적인 방법에 대해 알지 못했습니다. 말씀하신 방법들을 적용해보도록 하겠습니다 !!
@@ -0,0 +1,47 @@
+package christmas.domain;
+
+import static christmas.domain.MenuDiscountType.WEEKDAYS;
+import static christmas.domain.MenuDiscountType.WEEKENDS;
+
+import java.time.LocalDate;
+
+public class MenuDiscount {
+
+    private static final int WEEKDAYS_DISCOUNT = 2023;
+    private static final int WEEKENDS_DISCOUNT = 2023;
+    private static final MenuDiscount NONE = new MenuDiscount(Money.ZERO, MenuDiscountType.NONE);
+    private Money money;
+    private MenuDiscountType type;
+
+    private MenuDiscount(Money money, MenuDiscountType type) {
+        this.money = money;
+        this.type = type;
+    }
+
+
+    public static MenuDiscount of(OrderLine orderLine, LocalDate localDate) {
+        MenuDiscountType type = MenuDiscountType.findByLocalDate(localDate);
+
+        if (type == WEEKDAYS && orderLine.isDessert()) {
+            return new MenuDiscount(
+                new Money(WEEKDAYS_DISCOUNT).multiply(orderLine.getQuantity()), WEEKDAYS);
+        }
+        if (type == WEEKENDS && orderLine.isMain()) {
+            return new MenuDiscount(
+                new Money(WEEKENDS_DISCOUNT).multiply(orderLine.getQuantity()), WEEKENDS);
+        }
+        return NONE;
+    }
+
+    public boolean isWeekdays() {
+        return type == WEEKDAYS;
+    }
+
+    public boolean isWeekends() {
+        return type == WEEKENDS;
+    }
+
+    public Money getMoney() {
+        return money;
+    }
+}

리뷰: 현재 요구사항에서는 값이 동일하지만 그 의미는 다르므로 분리하는 것이 옳다고 생각했습니다. 추후 주말 할인과 평일 할인에 차이가 생기도록 변경사항이 생긴다면 더 편하게 변경할 수 있을 것이라 기대하고 분리했습니다.
@@ -0,0 +1,26 @@
+package christmas.dtos;
+
+import christmas.domain.BenefitType;
+
+public class BenefitDto {
+
+    private BenefitType benefitType;
+    private int discountAmount;
+
+    BenefitDto(BenefitType benefitType, int discountAmount) {
+        this.benefitType = benefitType;
+        this.discountAmount = discountAmount;
+    }
+
+    public static BenefitDto toDto(BenefitType benefitType, int discountAmount) {
+        return new BenefitDto(benefitType, discountAmount);
+    }
+
+    public BenefitType getBenefitType() {
+        return benefitType;
+    }
+
+    public int getDiscountAmount() {
+        return discountAmount;
+    }
+}

리뷰: 감사합니다! 꼭 적용해보도록 하겠습니다.
@@ -0,0 +1,80 @@
+package christmas.controller;
+
+import christmas.domain.BenefitCalculationFactory;
+import christmas.domain.Benefits;
+import christmas.domain.EventPlanner;
+import christmas.domain.Order;
+import christmas.dtos.OrderLineDto;
+import christmas.util.OrderLineMapper;
+import christmas.view.ErrorMessage;
+import christmas.view.InputView;
+import christmas.view.OutputView;
+import java.time.LocalDate;
+import java.util.List;
+
+public class ChristmasController {
+
+    public static void run() {
+        OutputView.printWelcomeMessage();
+        int day = getExpectedVisitDate();
+
+        Order order = getOrder();
+
+        LocalDate orderDate = LocalDate.of(2023, 12, day);
+
+        Benefits benefits = BenefitCalculationFactory.calculateBenefits(order, orderDate);
+
+        OutputView.printBenefitPreviewMessage(orderDate);
+
+        EventPlanner.printPreview(order, benefits);
+    }
+
+    public static Order getOrder() {
+        try {
+            OutputView.printOrderMenuMessage();
+            List<OrderLineDto> dtos = InputView.readMenus();
+            validateDuplicateMenus(dtos);
+
+            Order order = new Order(OrderLineMapper.orderLineDtosToOrderLines(dtos));
+
+            return order;
+        } catch (IllegalArgumentException e) {
+            OutputView.printExceptionMessage(e);
+            return getOrder();
+        }
+    }
+
+
+    public static int getExpectedVisitDate() {
+        try {
+            OutputView.printExpectedVisitDateMessage();
+            int day = InputView.readInteger();
+            validateExpectedVisitDate(day);
+            return day;
+        } catch (IllegalArgumentException e) {
+
+            System.out.println(e.getMessage());
+            System.out.println(e.getClass());
+            OutputView.printExceptionMessage(e);
+            return getExpectedVisitDate();
+        }
+    }
+
+    private static void validateExpectedVisitDate(int day) {
+        if (day < 1 || day > 31) {
+            throw new IllegalArgumentException(ErrorMessage.INVALID_DATE_INPUT.getMessage());
+        }
+    }
+
+    private static void validateDuplicateMenus(List<OrderLineDto> dtos) {
+        int originalSize = dtos.size();
+        int distinctSize = (int) dtos.stream()
+            .map(OrderLineDto::getMenuDetail)
+            .distinct()
+            .count();
+
+        if (originalSize != distinctSize) {
+            throw new IllegalArgumentException(ErrorMessage.DUPLICATE_MENU_INPUT.getMessage());
+        }
+    }
+}

리뷰: 2023, 12을 상수로 하는건 어떨까요?
다른 부분에서도 똑같이 사용하고 있고, 만약 다른 이벤트로 추가되면 수정할 부분을 다 찾아야 할 것 같아요
@@ -0,0 +1,58 @@
+package christmas.domain;
+
+import java.util.Collections;
+import java.util.List;
+
+public class Order {
+
+    private static final int MAX_QUANTITY = 20;
+    private static final String INSUFFICIENT_ORDERLINE_ERROR_MESSAGE = "[ERROR] 주문 항목이 비어 있습니다.";
+    private static final String TOO_MANY_ORDERLINE_QUANTITY_ERROR_MESSAGE = "[ERROR] 메뉴는 한 번에 최대 20개까지만 주문할 수 있습니다.";
+    private static final String ONLY_DRINKS_ERROR_MESSAGE = "[ERROR] 음료만 주문할 수 없습니다.";
+
+    private List<OrderLine> orderLines;
+
+    public Order(List<OrderLine> orderLines) {
+        validateAtLeastOneOrderLine(orderLines);
+        validateTotalQuantity(orderLines);
+        validateOnlyDrinks(orderLines);
+        this.orderLines = orderLines;
+    }
+
+    public Money getTotalAmounts() {
+        return orderLines.stream()
+            .map(OrderLine::getAmounts)
+            .reduce(Money::plus)
+            .get();
+    }
+
+    private void validateAtLeastOneOrderLine(List<OrderLine> orderLines) {
+        if (orderLines == null || orderLines.isEmpty()) {
+            throw new IllegalArgumentException(INSUFFICIENT_ORDERLINE_ERROR_MESSAGE);
+        }
+    }
+
+    private void validateTotalQuantity(List<OrderLine> orderLines) {
+        int totalQuantity = orderLines.stream()
+            .mapToInt(OrderLine::getQuantity)
+            .sum();
+
+        if (totalQuantity > MAX_QUANTITY) {
+            throw new IllegalArgumentException(TOO_MANY_ORDERLINE_QUANTITY_ERROR_MESSAGE);
+        }
+    }
+
+    private void validateOnlyDrinks(List<OrderLine> orderLines) {
+        if (orderLines.stream().allMatch(OrderLine::isDrink)) {
+            throw new IllegalArgumentException(ONLY_DRINKS_ERROR_MESSAGE);
+        }
+    }
+
+    public List<OrderLine> getOrderLines() {
+        return Collections.unmodifiableList(orderLines);
+    }
+
+    public Money getAmountToPay(Money discountAmounts) {
+        return getTotalAmounts().minus(discountAmounts);
+    }
+}

리뷰: ```suggestion
        if (isOnlyDrink())
```
메서드로 분리해서 가독성을 높이는건 어떨까요?
@@ -0,0 +1,80 @@
+package christmas.controller;
+
+import christmas.domain.BenefitCalculationFactory;
+import christmas.domain.Benefits;
+import christmas.domain.EventPlanner;
+import christmas.domain.Order;
+import christmas.dtos.OrderLineDto;
+import christmas.util.OrderLineMapper;
+import christmas.view.ErrorMessage;
+import christmas.view.InputView;
+import christmas.view.OutputView;
+import java.time.LocalDate;
+import java.util.List;
+
+public class ChristmasController {
+
+    public static void run() {
+        OutputView.printWelcomeMessage();
+        int day = getExpectedVisitDate();
+
+        Order order = getOrder();
+
+        LocalDate orderDate = LocalDate.of(2023, 12, day);
+
+        Benefits benefits = BenefitCalculationFactory.calculateBenefits(order, orderDate);
+
+        OutputView.printBenefitPreviewMessage(orderDate);
+
+        EventPlanner.printPreview(order, benefits);
+    }
+
+    public static Order getOrder() {
+        try {
+            OutputView.printOrderMenuMessage();
+            List<OrderLineDto> dtos = InputView.readMenus();
+            validateDuplicateMenus(dtos);
+
+            Order order = new Order(OrderLineMapper.orderLineDtosToOrderLines(dtos));
+
+            return order;
+        } catch (IllegalArgumentException e) {
+            OutputView.printExceptionMessage(e);
+            return getOrder();
+        }
+    }
+
+
+    public static int getExpectedVisitDate() {
+        try {
+            OutputView.printExpectedVisitDateMessage();
+            int day = InputView.readInteger();
+            validateExpectedVisitDate(day);
+            return day;
+        } catch (IllegalArgumentException e) {
+
+            System.out.println(e.getMessage());
+            System.out.println(e.getClass());
+            OutputView.printExceptionMessage(e);
+            return getExpectedVisitDate();
+        }
+    }
+
+    private static void validateExpectedVisitDate(int day) {
+        if (day < 1 || day > 31) {
+            throw new IllegalArgumentException(ErrorMessage.INVALID_DATE_INPUT.getMessage());
+        }
+    }
+
+    private static void validateDuplicateMenus(List<OrderLineDto> dtos) {
+        int originalSize = dtos.size();
+        int distinctSize = (int) dtos.stream()
+            .map(OrderLineDto::getMenuDetail)
+            .distinct()
+            .count();
+
+        if (originalSize != distinctSize) {
+            throw new IllegalArgumentException(ErrorMessage.DUPLICATE_MENU_INPUT.getMessage());
+        }
+    }
+}

리뷰: 클래스로 분리를 너무 잘하신 것 같은데 domain에 너무 많은 클래스들이 뭉쳐 있는게 아닌가 싶습니다.
- domain.benefit
- domain.menu
등으로 분류를 해보는건 어떨까요?