From 615bf4ff7951b5143a9a3f18f65671da11c37c9f Mon Sep 17 00:00:00 2001 From: 023-dev <0_2_3@naver.com> Date: Wed, 27 Nov 2024 18:16:58 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=ED=81=AC=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=EB=A7=88=EC=8A=A4=20=EB=AF=B8=EC=85=98=20=EC=A0=9C=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/christmas/Application.java | 7 +- src/main/java/christmas/config/AppConfig.java | 18 +++ .../java/christmas/config/MenuConfig.java | 21 +++ .../christmas/controller/EventController.java | 115 +++++++++++++++++ .../java/christmas/model/domain/Badge.java | 28 ++++ .../java/christmas/model/domain/Menu.java | 25 ++++ .../java/christmas/model/domain/Order.java | 22 ++++ .../christmas/repository/MenuRepository.java | 17 +++ .../christmas/service/DiscountCalculator.java | 53 ++++++++ src/main/java/christmas/view/InputView.java | 98 ++++++++++++++ src/main/java/christmas/view/OutputView.java | 121 ++++++++++++++++++ 11 files changed, 523 insertions(+), 2 deletions(-) create mode 100644 src/main/java/christmas/config/AppConfig.java create mode 100644 src/main/java/christmas/config/MenuConfig.java create mode 100644 src/main/java/christmas/controller/EventController.java create mode 100644 src/main/java/christmas/model/domain/Badge.java create mode 100644 src/main/java/christmas/model/domain/Menu.java create mode 100644 src/main/java/christmas/model/domain/Order.java create mode 100644 src/main/java/christmas/repository/MenuRepository.java create mode 100644 src/main/java/christmas/service/DiscountCalculator.java create mode 100644 src/main/java/christmas/view/InputView.java create mode 100644 src/main/java/christmas/view/OutputView.java diff --git a/src/main/java/christmas/Application.java b/src/main/java/christmas/Application.java index b9ba6a2..5b9d4f3 100644 --- a/src/main/java/christmas/Application.java +++ b/src/main/java/christmas/Application.java @@ -1,7 +1,10 @@ package christmas; +import christmas.config.AppConfig; + public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + AppConfig app = new AppConfig(); + app.run(); } -} +} \ No newline at end of file diff --git a/src/main/java/christmas/config/AppConfig.java b/src/main/java/christmas/config/AppConfig.java new file mode 100644 index 0000000..5b7d22f --- /dev/null +++ b/src/main/java/christmas/config/AppConfig.java @@ -0,0 +1,18 @@ +package christmas.config; + +import christmas.controller.EventController; +import christmas.view.InputView; +import christmas.view.OutputView; + +public class AppConfig { + private final EventController eventController; + + public AppConfig() { + this.eventController = new EventController(new InputView(), new OutputView()); + } + + public void run() { + eventController.init(); + eventController.run(); + } +} diff --git a/src/main/java/christmas/config/MenuConfig.java b/src/main/java/christmas/config/MenuConfig.java new file mode 100644 index 0000000..c85ef34 --- /dev/null +++ b/src/main/java/christmas/config/MenuConfig.java @@ -0,0 +1,21 @@ +package christmas.config; + +import christmas.model.domain.Menu; +import christmas.repository.MenuRepository; + +public class MenuConfig { + public static void initMenus() { + MenuRepository.addMenu(new Menu("양송이수프", 6_000, "애피타이저")); + MenuRepository.addMenu(new Menu("타파스", 5_500, "애피타이저")); + MenuRepository.addMenu(new Menu("시저샐러드", 8_000, "애피타이저")); + MenuRepository.addMenu(new Menu("티본스테이크", 55_000, "메인")); + MenuRepository.addMenu(new Menu("바비큐립", 54_000, "메인")); + MenuRepository.addMenu(new Menu("해산물파스타", 35_000, "메인")); + MenuRepository.addMenu(new Menu("크리스마스파스타", 25_000, "메인")); + MenuRepository.addMenu(new Menu("초코케이크", 15_000, "디저트")); + MenuRepository.addMenu(new Menu("아이스크림", 5_000, "디저트")); + MenuRepository.addMenu(new Menu("제로콜라", 3_000, "음료")); + MenuRepository.addMenu(new Menu("레드와인", 60_000, "음료")); + MenuRepository.addMenu(new Menu("샴페인", 25_000, "음료")); + } +} diff --git a/src/main/java/christmas/controller/EventController.java b/src/main/java/christmas/controller/EventController.java new file mode 100644 index 0000000..4cb7170 --- /dev/null +++ b/src/main/java/christmas/controller/EventController.java @@ -0,0 +1,115 @@ +package christmas.controller; + +import christmas.config.MenuConfig; +import christmas.model.domain.*; +import christmas.repository.MenuRepository; +import christmas.service.DiscountCalculator; +import christmas.view.InputView; +import christmas.view.OutputView; + +import java.time.DayOfWeek; +import java.time.LocalDate; + +public class EventController { + + private static final String GIFT_CHAMPAGNE = "샴페인 1개"; // 증정 메뉴 상수 + private static final String NO_GIFT = "없음"; // 증정 메뉴가 없을 때 + private static final String ORDER_DELIMITER = ","; // 주문 항목 구분자 + private static final String DETAIL_DELIMITER = "-"; // 메뉴명-개수 구분자 + + private final InputView inputView; + private final OutputView outputView; + private final DiscountCalculator discountCalculator; + + public EventController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + this.discountCalculator = new DiscountCalculator(); + } + + public void init() { + MenuConfig.initMenus(); + } + + public void run() { + try { + int visitDay = readValidVisitDate(); + LocalDate visitDate = LocalDate.of(2023, 12, visitDay); + + Order order = createOrderFromInput(); + processOrder(order, visitDay, visitDate); // LocalDate 전달 + } catch (IllegalArgumentException e) { + outputView.printError(e.getMessage()); + } + } + + private int readValidVisitDate() { + while (true) { + try { + return inputView.readVisitDate(); + } catch (IllegalArgumentException e) { + outputView.printError(e.getMessage()); + } + } + } + + private Order createOrderFromInput() { + Order order = new Order(); + String[] orderDetails = readValidOrderDetails(); + for (String detail : orderDetails) { + String[] parts = detail.split(DETAIL_DELIMITER); + Menu menu = MenuRepository.findByName(parts[0].trim()); + int quantity = Integer.parseInt(parts[1].trim()); + order.addMenu(menu, quantity); + } + return order; + } + + private String[] readValidOrderDetails() { + while (true) { + try { + return inputView.readOrderDetails().split(ORDER_DELIMITER); + } catch (IllegalArgumentException e) { + outputView.printError(e.getMessage()); + } + } + } + + private void processOrder(Order order, int visitDay, LocalDate visitDate) { + int totalPrice = order.calculateTotalPrice(); + + int dailyDiscount = discountCalculator.calculateDailyDiscount(visitDay); + int categoryDiscount = discountCalculator.calculateCategoryDiscount(order, visitDate); // LocalDate 사용 + int specialDayDiscount = discountCalculator.calculateSpecialDayDiscount(visitDate); + + boolean eligibleForGift = discountCalculator.isEligibleForGift(totalPrice); + String gift = getGiftBasedOnEligibility(eligibleForGift); + + int totalDiscount = calculateTotalDiscount(dailyDiscount, categoryDiscount, specialDayDiscount, eligibleForGift); + int discountPrice = calculateDiscount(dailyDiscount, categoryDiscount, specialDayDiscount); + int finalPrice = totalPrice - discountPrice; + + String badge = Badge.getBadgeByBenefit(totalDiscount).getName(); + + outputView.printOrderSummary(order, totalPrice, totalDiscount, finalPrice, gift, dailyDiscount, categoryDiscount, specialDayDiscount, badge); + } + + private String getGiftBasedOnEligibility(boolean eligibleForGift) { + if (eligibleForGift) { + return GIFT_CHAMPAGNE; + } + return NO_GIFT; + } + + private int calculateDiscount(int dailyDiscount, int categoryDiscount, int specialDayDiscount) { + return dailyDiscount + categoryDiscount + specialDayDiscount; + } + + private int calculateTotalDiscount(int dailyDiscount, int categoryDiscount, int specialDayDiscount, boolean eligibleForGift) { + int giftDiscount = 0; + if (eligibleForGift) { + giftDiscount = 25000; + } + return dailyDiscount + categoryDiscount + specialDayDiscount + giftDiscount; + } +} \ No newline at end of file diff --git a/src/main/java/christmas/model/domain/Badge.java b/src/main/java/christmas/model/domain/Badge.java new file mode 100644 index 0000000..cda2c6c --- /dev/null +++ b/src/main/java/christmas/model/domain/Badge.java @@ -0,0 +1,28 @@ +package christmas.model.domain; +import java.util.Arrays; + +public enum Badge { + SANTA("산타", 20000), + TREE("트리", 10000), + STAR("별", 5000), + NONE("없음", 0); + + private final String name; + private final int minBenefit; + + Badge(String name, int minBenefit) { + this.name = name; + this.minBenefit = minBenefit; + } + + public String getName() { + return name; + } + + public static Badge getBadgeByBenefit(int totalBenefit) { + return Arrays.stream(values()) + .filter(badge -> totalBenefit >= badge.minBenefit) + .findFirst() + .orElse(NONE); + } +} diff --git a/src/main/java/christmas/model/domain/Menu.java b/src/main/java/christmas/model/domain/Menu.java new file mode 100644 index 0000000..5bc071d --- /dev/null +++ b/src/main/java/christmas/model/domain/Menu.java @@ -0,0 +1,25 @@ +package christmas.model.domain; + +public class Menu { + private final String name; + private final int price; + private final String category; + + public Menu(String name, int price, String category) { + this.name = name; + this.price = price; + this.category = category; + } + + public String getName() { + return name; + } + + public int getPrice() { + return price; + } + + public String getCategory() { + return category; + } +} \ No newline at end of file diff --git a/src/main/java/christmas/model/domain/Order.java b/src/main/java/christmas/model/domain/Order.java new file mode 100644 index 0000000..68b8063 --- /dev/null +++ b/src/main/java/christmas/model/domain/Order.java @@ -0,0 +1,22 @@ +package christmas.model.domain; + +import java.util.HashMap; +import java.util.Map; + +public class Order { + private final Map orderDetails = new HashMap<>(); + + public void addMenu(Menu menu, int quantity) { + orderDetails.put(menu, orderDetails.getOrDefault(menu, 0) + quantity); + } + + public Map getOrderDetails() { + return orderDetails; + } + + public int calculateTotalPrice() { + return orderDetails.entrySet().stream() + .mapToInt(entry -> entry.getKey().getPrice() * entry.getValue()) + .sum(); + } +} diff --git a/src/main/java/christmas/repository/MenuRepository.java b/src/main/java/christmas/repository/MenuRepository.java new file mode 100644 index 0000000..b683a5c --- /dev/null +++ b/src/main/java/christmas/repository/MenuRepository.java @@ -0,0 +1,17 @@ +package christmas.repository; + +import christmas.model.domain.Menu; +import java.util.HashMap; +import java.util.Map; + +public class MenuRepository { + private static final Map menus = new HashMap<>(); + + public static void addMenu(Menu menu) { + menus.put(menu.getName(), menu); + } + + public static Menu findByName(String name) { + return menus.get(name); + } +} \ No newline at end of file diff --git a/src/main/java/christmas/service/DiscountCalculator.java b/src/main/java/christmas/service/DiscountCalculator.java new file mode 100644 index 0000000..e6a7475 --- /dev/null +++ b/src/main/java/christmas/service/DiscountCalculator.java @@ -0,0 +1,53 @@ +package christmas.service; + +import christmas.model.domain.Order; + +import java.time.DayOfWeek; +import java.time.LocalDate; + +public class DiscountCalculator { + + private static final int DAILY_DISCOUNT_START = 1000; // 크리스마스 디데이 첫날 할인 금액 + private static final int DAILY_DISCOUNT_INCREMENT = 100; // 하루마다 증가하는 할인 금액 + private static final int CATEGORY_DISCOUNT_AMOUNT = 2023; // 카테고리별 할인 금액 + private static final int SPECIAL_DAY_DISCOUNT = 1000; // 특별 할인 금액 + private static final int GIFT_ELIGIBILITY_THRESHOLD = 120000; // 증정 메뉴 제공 기준 금액 + + public int calculateDailyDiscount(int day) { + if (day < 1 || day > 25) { + return 0; // 크리스마스 디데이 할인은 12월 1~25일만 적용 + } + return DAILY_DISCOUNT_START + ((day - 1) * DAILY_DISCOUNT_INCREMENT); + } + + public int calculateCategoryDiscount(Order order, LocalDate visitDate) { + DayOfWeek dayOfWeek = visitDate.getDayOfWeek(); + boolean isWeekend = (dayOfWeek == DayOfWeek.FRIDAY || dayOfWeek == DayOfWeek.SATURDAY); + + String targetCategory = isWeekend ? "메인" : "디저트"; + + return order.getOrderDetails().entrySet().stream() + .filter(entry -> entry.getKey().getCategory().equals(targetCategory)) + .mapToInt(entry -> CATEGORY_DISCOUNT_AMOUNT * entry.getValue()) + .sum(); + } + + public int calculateSpecialDayDiscount(LocalDate visitDate) { + if (isSpecialDay(visitDate)) { + return SPECIAL_DAY_DISCOUNT; + } + return 0; + } + + public boolean isEligibleForGift(int totalPrice) { + return totalPrice >= GIFT_ELIGIBILITY_THRESHOLD; + } + + private boolean isSpecialDay(LocalDate date) { + DayOfWeek dayOfWeek = date.getDayOfWeek(); + int dayOfMonth = date.getDayOfMonth(); + + // 매주 일요일 또는 12월 25일이면 특별 할인 적용 + return dayOfWeek == DayOfWeek.SUNDAY || dayOfMonth == 25; + } +} \ No newline at end of file diff --git a/src/main/java/christmas/view/InputView.java b/src/main/java/christmas/view/InputView.java new file mode 100644 index 0000000..2a6cbfc --- /dev/null +++ b/src/main/java/christmas/view/InputView.java @@ -0,0 +1,98 @@ +package christmas.view; + +import camp.nextstep.edu.missionutils.Console; +import christmas.repository.MenuRepository; + +import java.util.HashSet; +import java.util.Set; + +public class InputView { + + private static final String VISIT_DATE_PROMPT = "12월 중 식당 예상 방문 날짜는 언제인가요? (숫자만 입력해 주세요!)"; + private static final String ORDER_DETAILS_PROMPT = "주문하실 메뉴를 메뉴와 개수를 알려 주세요. (e.g. 해산물파스타-2,레드와인-1,초코케이크-1)"; + private static final String ERROR_INVALID_DATE = "[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요."; + private static final String ERROR_INVALID_ORDER = "[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요."; + private static final String ORDER_DELIMITER = ","; + private static final String DETAIL_DELIMITER = "-"; + + public int readVisitDate() { + System.out.println(VISIT_DATE_PROMPT); + String input = Console.readLine(); + return parseVisitDate(input); + } + + private int parseVisitDate(String input) { + try { + int date = Integer.parseInt(input); + validateDate(date); + return date; + } catch (NumberFormatException e) { + throw new IllegalArgumentException(ERROR_INVALID_DATE); + } + } + + private void validateDate(int date) { + if (date < 1 || date > 31) { + throw new IllegalArgumentException(ERROR_INVALID_DATE); + } + } + + public String readOrderDetails() { + System.out.println(ORDER_DETAILS_PROMPT); + String input = Console.readLine(); + validateOrderInput(input); + return input; + } + + private void validateOrderInput(String input) { + validateEmptyInput(input); + + Set uniqueMenus = new HashSet<>(); + String[] orders = input.split(ORDER_DELIMITER); + + for (String order : orders) { + validateOrder(order, uniqueMenus); + } + } + + private void validateEmptyInput(String input) { + if (input == null || input.trim().isEmpty()) { + throw new IllegalArgumentException(ERROR_INVALID_ORDER); + } + } + + private void validateOrder(String order, Set uniqueMenus) { + String[] details = order.split(DETAIL_DELIMITER); + validateOrderFormat(details); + String menuName = details[0].trim(); + validateMenuName(menuName, uniqueMenus); + String quantityString = details[1].trim(); + validateQuantity(quantityString); + } + + private void validateOrderFormat(String[] details) { + if (details.length != 2) { + throw new IllegalArgumentException(ERROR_INVALID_ORDER); + } + } + + private void validateMenuName(String menuName, Set uniqueMenus) { + if (MenuRepository.findByName(menuName) == null) { + throw new IllegalArgumentException(ERROR_INVALID_ORDER); + } + if (!uniqueMenus.add(menuName)) { + throw new IllegalArgumentException(ERROR_INVALID_ORDER); + } + } + + private void validateQuantity(String quantityString) { + try { + int quantity = Integer.parseInt(quantityString); + if (quantity < 1) { + throw new IllegalArgumentException(ERROR_INVALID_ORDER); + } + } catch (NumberFormatException e) { + throw new IllegalArgumentException(ERROR_INVALID_ORDER); + } + } +} \ No newline at end of file diff --git a/src/main/java/christmas/view/OutputView.java b/src/main/java/christmas/view/OutputView.java new file mode 100644 index 0000000..a3fb980 --- /dev/null +++ b/src/main/java/christmas/view/OutputView.java @@ -0,0 +1,121 @@ +package christmas.view; + +import christmas.model.domain.Order; + +import java.text.NumberFormat; +import java.util.Locale; + +public class OutputView { + + private static final String ORDER_MENU_HEADER = "<주문 메뉴>"; + private static final String TOTAL_PRICE_HEADER = "\n<할인 전 총주문 금액>"; + private static final String GIFT_HEADER = "\n<증정 메뉴>"; + private static final String DISCOUNT_DETAILS_HEADER = "\n<혜택 내역>"; + private static final String TOTAL_BENEFITS_HEADER = "\n<총혜택 금액>"; + private static final String FINAL_PRICE_HEADER = "\n<할인 후 예상 결제 금액>"; + private static final String BADGE_HEADER = "\n<12월 이벤트 배지>"; + private static final String WON_SUFFIX = "원"; + private static final String NO_DISCOUNT_MESSAGE = "없음"; + private static final String DAILY_DISCOUNT_LABEL = "크리스마스 디데이 할인: "; + private static final String CATEGORY_DISCOUNT_LABEL = "평일/주말 할인: "; + private static final String SPECIAL_DISCOUNT_LABEL = "특별 할인: "; + private static final String GIFT_EVENT_LABEL = "증정 이벤트: "; + private static final String ORDER_ITEM_FORMAT = "%s %d개"; + private static final String NO_GIFT = "없음"; + private static final String NEGATIVE_PREFIX = "-"; + private static final int GIFT_DISCOUNT_AMOUNT = 25000; + + public void printOrderSummary(Order order, int totalPrice, int totalDiscount, int finalPrice, String gift, int dailyDiscount, int categoryDiscount, int specialDayDiscount, String badge) { + printOrderDetails(order); + printPriceDetails(totalPrice); + printGiftDetails(gift); + printDiscountDetails(dailyDiscount, categoryDiscount, specialDayDiscount, gift); + printTotalBenefits(totalDiscount); + printFinalPrice(finalPrice); + printBadge(badge); + } + + private void printOrderDetails(Order order) { + System.out.println(ORDER_MENU_HEADER); + order.getOrderDetails().forEach((menu, quantity) -> { + System.out.println(String.format(ORDER_ITEM_FORMAT, menu.getName(), quantity)); + }); + } + + private void printPriceDetails(int totalPrice) { + System.out.println(TOTAL_PRICE_HEADER); + System.out.println(formatCurrency(totalPrice) + WON_SUFFIX); + } + + private void printGiftDetails(String gift) { + System.out.println(GIFT_HEADER); + System.out.println(gift); + } + + private void printDiscountDetails(int dailyDiscount, int categoryDiscount, int specialDayDiscount, String gift) { + System.out.println(DISCOUNT_DETAILS_HEADER); + if (hasNoDiscount(dailyDiscount, categoryDiscount, specialDayDiscount, gift)) { + System.out.println(NO_DISCOUNT_MESSAGE); + return; + } + printDailyDiscount(dailyDiscount); + printCategoryDiscount(categoryDiscount); + printSpecialDayDiscount(specialDayDiscount); + printGiftEventDiscount(gift); + } + + private boolean hasNoDiscount(int dailyDiscount, int categoryDiscount, int specialDayDiscount, String gift) { + return dailyDiscount == 0 && categoryDiscount == 0 && specialDayDiscount == 0 && NO_GIFT.equals(gift); + } + + private void printDailyDiscount(int dailyDiscount) { + if (dailyDiscount > 0) { + System.out.println(DAILY_DISCOUNT_LABEL + formatDiscount(dailyDiscount) + WON_SUFFIX); + } + } + + private void printCategoryDiscount(int categoryDiscount) { + if (categoryDiscount > 0) { + System.out.println(CATEGORY_DISCOUNT_LABEL + formatDiscount(categoryDiscount) + WON_SUFFIX); + } + } + + private void printSpecialDayDiscount(int specialDayDiscount) { + if (specialDayDiscount > 0) { + System.out.println(SPECIAL_DISCOUNT_LABEL + formatDiscount(specialDayDiscount) + WON_SUFFIX); + } + } + + private void printGiftEventDiscount(String gift) { + if (!NO_GIFT.equals(gift)) { + System.out.println(GIFT_EVENT_LABEL + formatDiscount(GIFT_DISCOUNT_AMOUNT) + WON_SUFFIX); + } + } + + private void printTotalBenefits(int totalDiscount) { + System.out.println(TOTAL_BENEFITS_HEADER); + System.out.println(formatDiscount(totalDiscount) + WON_SUFFIX); + } + + private void printFinalPrice(int finalPrice) { + System.out.println(FINAL_PRICE_HEADER); + System.out.println(formatCurrency(finalPrice) + WON_SUFFIX); + } + + private void printBadge(String badge) { + System.out.println(BADGE_HEADER); + System.out.println(badge); + } + + private String formatDiscount(int amount) { + return NEGATIVE_PREFIX + formatCurrency(amount); + } + + private String formatCurrency(int amount) { + return NumberFormat.getInstance(Locale.KOREA).format(amount); + } + + public void printError(String meesage) { + System.out.println(meesage); + } +} \ No newline at end of file From 8d0541c4f3113a6fe7161e5b8730e55d5c27acf4 Mon Sep 17 00:00:00 2001 From: 023-dev <0_2_3@naver.com> Date: Wed, 27 Nov 2024 18:17:48 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=ED=81=AC=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=EB=A7=88=EC=8A=A4=20=EB=AF=B8=EC=85=98=20=EC=A0=9C=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/christmas/controller/EventController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/christmas/controller/EventController.java b/src/main/java/christmas/controller/EventController.java index 4cb7170..6448d0b 100644 --- a/src/main/java/christmas/controller/EventController.java +++ b/src/main/java/christmas/controller/EventController.java @@ -7,7 +7,6 @@ import christmas.view.InputView; import christmas.view.OutputView; -import java.time.DayOfWeek; import java.time.LocalDate; public class EventController { From 1bb2fb3f54455c071e1d8a82ab429c6920d86b59 Mon Sep 17 00:00:00 2001 From: 023-dev <0_2_3@naver.com> Date: Wed, 27 Nov 2024 19:37:36 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20=ED=81=AC=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=EB=A7=88=EC=8A=A4=20=EB=AF=B8=EC=85=98=20=EC=A0=9C=EC=B6=9C=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=EA=B7=B8=EB=9E=98=EB=B0=8D=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=20=EC=82=AC=ED=95=AD=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../christmas/controller/EventController.java | 48 +++++++------- .../christmas/service/DiscountCalculator.java | 66 +++++++++++++------ src/main/java/christmas/view/OutputView.java | 34 +++++----- 3 files changed, 88 insertions(+), 60 deletions(-) diff --git a/src/main/java/christmas/controller/EventController.java b/src/main/java/christmas/controller/EventController.java index 6448d0b..25eab38 100644 --- a/src/main/java/christmas/controller/EventController.java +++ b/src/main/java/christmas/controller/EventController.java @@ -11,10 +11,11 @@ public class EventController { - private static final String GIFT_CHAMPAGNE = "샴페인 1개"; // 증정 메뉴 상수 - private static final String NO_GIFT = "없음"; // 증정 메뉴가 없을 때 - private static final String ORDER_DELIMITER = ","; // 주문 항목 구분자 - private static final String DETAIL_DELIMITER = "-"; // 메뉴명-개수 구분자 + private static final String GIFT_CHAMPAGNE = "샴페인 1개"; + private static final String NO_GIFT = "없음"; + private static final String ORDER_DELIMITER = ","; + private static final String DETAIL_DELIMITER = "-"; + private static final int GIFT_DISCOUNT_AMOUNT = 25000; private final InputView inputView; private final OutputView outputView; @@ -31,14 +32,17 @@ public void init() { } public void run() { - try { - int visitDay = readValidVisitDate(); - LocalDate visitDate = LocalDate.of(2023, 12, visitDay); - - Order order = createOrderFromInput(); - processOrder(order, visitDay, visitDate); // LocalDate 전달 - } catch (IllegalArgumentException e) { - outputView.printError(e.getMessage()); + while (true) { + try { + int visitDay = readValidVisitDate(); + LocalDate visitDate = LocalDate.of(2023, 12, visitDay); + + Order order = createOrderFromInput(); + processOrder(order, visitDay, visitDate); + break; + } catch (IllegalArgumentException e) { + outputView.printError(e.getMessage()); + } } } @@ -78,19 +82,19 @@ private void processOrder(Order order, int visitDay, LocalDate visitDate) { int totalPrice = order.calculateTotalPrice(); int dailyDiscount = discountCalculator.calculateDailyDiscount(visitDay); - int categoryDiscount = discountCalculator.calculateCategoryDiscount(order, visitDate); // LocalDate 사용 + int weekdayDiscount = discountCalculator.calculateWeekdayDiscount(order, visitDate); + int weekendDiscount = discountCalculator.calculateWeekendDiscount(order, visitDate); int specialDayDiscount = discountCalculator.calculateSpecialDayDiscount(visitDate); boolean eligibleForGift = discountCalculator.isEligibleForGift(totalPrice); String gift = getGiftBasedOnEligibility(eligibleForGift); - int totalDiscount = calculateTotalDiscount(dailyDiscount, categoryDiscount, specialDayDiscount, eligibleForGift); - int discountPrice = calculateDiscount(dailyDiscount, categoryDiscount, specialDayDiscount); - int finalPrice = totalPrice - discountPrice; + int totalDiscount = calculateTotalDiscount(dailyDiscount, weekdayDiscount, weekendDiscount, specialDayDiscount, eligibleForGift); + int finalPrice = totalPrice - (dailyDiscount + weekdayDiscount + weekendDiscount + specialDayDiscount); String badge = Badge.getBadgeByBenefit(totalDiscount).getName(); - outputView.printOrderSummary(order, totalPrice, totalDiscount, finalPrice, gift, dailyDiscount, categoryDiscount, specialDayDiscount, badge); + outputView.printOrderSummary(order, totalPrice, totalDiscount, finalPrice, gift, dailyDiscount, weekdayDiscount, weekendDiscount, specialDayDiscount, badge); } private String getGiftBasedOnEligibility(boolean eligibleForGift) { @@ -100,15 +104,11 @@ private String getGiftBasedOnEligibility(boolean eligibleForGift) { return NO_GIFT; } - private int calculateDiscount(int dailyDiscount, int categoryDiscount, int specialDayDiscount) { - return dailyDiscount + categoryDiscount + specialDayDiscount; - } - - private int calculateTotalDiscount(int dailyDiscount, int categoryDiscount, int specialDayDiscount, boolean eligibleForGift) { + private int calculateTotalDiscount(int dailyDiscount, int weekdayDiscount, int weekendDiscount, int specialDayDiscount, boolean eligibleForGift) { int giftDiscount = 0; if (eligibleForGift) { - giftDiscount = 25000; + giftDiscount = GIFT_DISCOUNT_AMOUNT; } - return dailyDiscount + categoryDiscount + specialDayDiscount + giftDiscount; + return dailyDiscount + weekdayDiscount + weekendDiscount + specialDayDiscount + giftDiscount; } } \ No newline at end of file diff --git a/src/main/java/christmas/service/DiscountCalculator.java b/src/main/java/christmas/service/DiscountCalculator.java index e6a7475..93e00db 100644 --- a/src/main/java/christmas/service/DiscountCalculator.java +++ b/src/main/java/christmas/service/DiscountCalculator.java @@ -7,29 +7,34 @@ public class DiscountCalculator { - private static final int DAILY_DISCOUNT_START = 1000; // 크리스마스 디데이 첫날 할인 금액 - private static final int DAILY_DISCOUNT_INCREMENT = 100; // 하루마다 증가하는 할인 금액 - private static final int CATEGORY_DISCOUNT_AMOUNT = 2023; // 카테고리별 할인 금액 - private static final int SPECIAL_DAY_DISCOUNT = 1000; // 특별 할인 금액 - private static final int GIFT_ELIGIBILITY_THRESHOLD = 120000; // 증정 메뉴 제공 기준 금액 + private static final int DAILY_DISCOUNT_START = 1000; + private static final int DAILY_DISCOUNT_INCREMENT = 100; + private static final int CATEGORY_DISCOUNT_AMOUNT = 2023; + private static final int SPECIAL_DAY_DISCOUNT = 1000; + private static final int GIFT_ELIGIBILITY_THRESHOLD = 120000; + private static final String MAIN_CATEGORY = "메인"; + private static final String DESSERT_CATEGORY = "디저트"; + private static final int CHRISTMAS_DAY = 25; public int calculateDailyDiscount(int day) { - if (day < 1 || day > 25) { - return 0; // 크리스마스 디데이 할인은 12월 1~25일만 적용 + if (isInvalidDiscountDay(day)) { + return 0; } return DAILY_DISCOUNT_START + ((day - 1) * DAILY_DISCOUNT_INCREMENT); } - public int calculateCategoryDiscount(Order order, LocalDate visitDate) { - DayOfWeek dayOfWeek = visitDate.getDayOfWeek(); - boolean isWeekend = (dayOfWeek == DayOfWeek.FRIDAY || dayOfWeek == DayOfWeek.SATURDAY); - - String targetCategory = isWeekend ? "메인" : "디저트"; + public int calculateWeekdayDiscount(Order order, LocalDate visitDate) { + if (isWeekday(visitDate.getDayOfWeek())) { + return calculateCategoryDiscount(order, DESSERT_CATEGORY); + } + return 0; + } - return order.getOrderDetails().entrySet().stream() - .filter(entry -> entry.getKey().getCategory().equals(targetCategory)) - .mapToInt(entry -> CATEGORY_DISCOUNT_AMOUNT * entry.getValue()) - .sum(); + public int calculateWeekendDiscount(Order order, LocalDate visitDate) { + if (isWeekend(visitDate.getDayOfWeek())) { + return calculateCategoryDiscount(order, MAIN_CATEGORY); + } + return 0; } public int calculateSpecialDayDiscount(LocalDate visitDate) { @@ -43,11 +48,30 @@ public boolean isEligibleForGift(int totalPrice) { return totalPrice >= GIFT_ELIGIBILITY_THRESHOLD; } - private boolean isSpecialDay(LocalDate date) { - DayOfWeek dayOfWeek = date.getDayOfWeek(); - int dayOfMonth = date.getDayOfMonth(); + private boolean isInvalidDiscountDay(int day) { + return day < 1 || day > 25; + } - // 매주 일요일 또는 12월 25일이면 특별 할인 적용 - return dayOfWeek == DayOfWeek.SUNDAY || dayOfMonth == 25; + private int calculateCategoryDiscount(Order order, String category) { + return order.getOrderDetails().entrySet().stream() + .filter(entry -> entry.getKey().getCategory().equals(category)) + .mapToInt(entry -> CATEGORY_DISCOUNT_AMOUNT * entry.getValue()) + .sum(); + } + + private boolean isWeekday(DayOfWeek dayOfWeek) { + return dayOfWeek == DayOfWeek.MONDAY || + dayOfWeek == DayOfWeek.TUESDAY || + dayOfWeek == DayOfWeek.WEDNESDAY || + dayOfWeek == DayOfWeek.THURSDAY || + dayOfWeek == DayOfWeek.SUNDAY; + } + + private boolean isWeekend(DayOfWeek dayOfWeek) { + return dayOfWeek == DayOfWeek.FRIDAY || dayOfWeek == DayOfWeek.SATURDAY; + } + + private boolean isSpecialDay(LocalDate date) { + return date.getDayOfWeek() == DayOfWeek.SUNDAY || date.getDayOfMonth() == CHRISTMAS_DAY; } } \ No newline at end of file diff --git a/src/main/java/christmas/view/OutputView.java b/src/main/java/christmas/view/OutputView.java index a3fb980..2222f18 100644 --- a/src/main/java/christmas/view/OutputView.java +++ b/src/main/java/christmas/view/OutputView.java @@ -17,7 +17,8 @@ public class OutputView { private static final String WON_SUFFIX = "원"; private static final String NO_DISCOUNT_MESSAGE = "없음"; private static final String DAILY_DISCOUNT_LABEL = "크리스마스 디데이 할인: "; - private static final String CATEGORY_DISCOUNT_LABEL = "평일/주말 할인: "; + private static final String WEEKDAY_DISCOUNT_LABEL = "평일 할인: "; + private static final String WEEKEND_DISCOUNT_LABEL = "주말 할인: "; private static final String SPECIAL_DISCOUNT_LABEL = "특별 할인: "; private static final String GIFT_EVENT_LABEL = "증정 이벤트: "; private static final String ORDER_ITEM_FORMAT = "%s %d개"; @@ -25,11 +26,11 @@ public class OutputView { private static final String NEGATIVE_PREFIX = "-"; private static final int GIFT_DISCOUNT_AMOUNT = 25000; - public void printOrderSummary(Order order, int totalPrice, int totalDiscount, int finalPrice, String gift, int dailyDiscount, int categoryDiscount, int specialDayDiscount, String badge) { + public void printOrderSummary(Order order, int totalPrice, int totalDiscount, int finalPrice, String gift, int dailyDiscount, int weekdayDiscount, int weekendDiscount, int specialDayDiscount, String badge) { printOrderDetails(order); printPriceDetails(totalPrice); printGiftDetails(gift); - printDiscountDetails(dailyDiscount, categoryDiscount, specialDayDiscount, gift); + printDiscountDetails(dailyDiscount, weekdayDiscount, weekendDiscount, specialDayDiscount, gift); printTotalBenefits(totalDiscount); printFinalPrice(finalPrice); printBadge(badge); @@ -52,31 +53,34 @@ private void printGiftDetails(String gift) { System.out.println(gift); } - private void printDiscountDetails(int dailyDiscount, int categoryDiscount, int specialDayDiscount, String gift) { + private void printDiscountDetails(int dailyDiscount, int weekdayDiscount, int weekendDiscount, int specialDayDiscount, String gift) { System.out.println(DISCOUNT_DETAILS_HEADER); - if (hasNoDiscount(dailyDiscount, categoryDiscount, specialDayDiscount, gift)) { + if (dailyDiscount == 0 && weekdayDiscount == 0 && weekendDiscount == 0 && specialDayDiscount == 0 && NO_GIFT.equals(gift)) { System.out.println(NO_DISCOUNT_MESSAGE); return; } printDailyDiscount(dailyDiscount); - printCategoryDiscount(categoryDiscount); + printWeekdayDiscount(weekdayDiscount); + printWeekendDiscount(weekendDiscount); printSpecialDayDiscount(specialDayDiscount); printGiftEventDiscount(gift); } - private boolean hasNoDiscount(int dailyDiscount, int categoryDiscount, int specialDayDiscount, String gift) { - return dailyDiscount == 0 && categoryDiscount == 0 && specialDayDiscount == 0 && NO_GIFT.equals(gift); - } - private void printDailyDiscount(int dailyDiscount) { if (dailyDiscount > 0) { System.out.println(DAILY_DISCOUNT_LABEL + formatDiscount(dailyDiscount) + WON_SUFFIX); } } - private void printCategoryDiscount(int categoryDiscount) { - if (categoryDiscount > 0) { - System.out.println(CATEGORY_DISCOUNT_LABEL + formatDiscount(categoryDiscount) + WON_SUFFIX); + private void printWeekdayDiscount(int weekdayDiscount) { + if (weekdayDiscount > 0) { + System.out.println(WEEKDAY_DISCOUNT_LABEL + formatDiscount(weekdayDiscount) + WON_SUFFIX); + } + } + + private void printWeekendDiscount(int weekendDiscount) { + if (weekendDiscount > 0) { + System.out.println(WEEKEND_DISCOUNT_LABEL + formatDiscount(weekendDiscount) + WON_SUFFIX); } } @@ -115,7 +119,7 @@ private String formatCurrency(int amount) { return NumberFormat.getInstance(Locale.KOREA).format(amount); } - public void printError(String meesage) { - System.out.println(meesage); + public void printError(String message) { + System.out.println(message); } } \ No newline at end of file From a813fd49885892aae7e717e39b593e08a7e37d7e Mon Sep 17 00:00:00 2001 From: 023-dev <0_2_3@naver.com> Date: Wed, 27 Nov 2024 19:42:57 +0900 Subject: [PATCH 4/4] =?UTF-8?q?refactor:=20=ED=81=AC=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=EB=A7=88=EC=8A=A4=20=EB=AF=B8=EC=85=98=20=EC=A0=9C=EC=B6=9C=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=EA=B7=B8=EB=9E=98=EB=B0=8D=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=20=EC=82=AC=ED=95=AD=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/christmas/controller/EventController.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/christmas/controller/EventController.java b/src/main/java/christmas/controller/EventController.java index 25eab38..faf60f4 100644 --- a/src/main/java/christmas/controller/EventController.java +++ b/src/main/java/christmas/controller/EventController.java @@ -16,6 +16,8 @@ public class EventController { private static final String ORDER_DELIMITER = ","; private static final String DETAIL_DELIMITER = "-"; private static final int GIFT_DISCOUNT_AMOUNT = 25000; + private static final int EVENT_YEAR = 2023; + private static final int EVENT_MONTH = 12; private final InputView inputView; private final OutputView outputView; @@ -35,7 +37,7 @@ public void run() { while (true) { try { int visitDay = readValidVisitDate(); - LocalDate visitDate = LocalDate.of(2023, 12, visitDay); + LocalDate visitDate = LocalDate.of(EVENT_YEAR, EVENT_MONTH, visitDay); Order order = createOrderFromInput(); processOrder(order, visitDay, visitDate);