본문 바로가기

JAVA

[Java] 도전 과제 Lv_2 키오스크

 

요구사항

  • ⬜ Enum을 활용한 사용자 유형별 할인율 관리하기
    • ⬜ 사용자 유형의 Enum 정의 및 각 사용자 유형에 따른 할인율 적용
      • ⬜ 예시 : 군인, 학생, 일반인
    • ⬜ 주문 시, 사용자 유형에 맞는 할인율 적용해 총 금액 계산
  • ⬜ 람다 & 스트림을 활용한 장바구니 조회 기능
    • ⬜ 기존에 생성한 Menu의 MenuItem을 조회 할 때 스트림을 사용하여 출력하도록 수정
    • ⬜ 기존 장바구니에서 특정 메뉴 빼기 기능을 통한 스트림 활용
      • ⬜ 예시 : 장바구니에 SmokeShack 가 들어 있다면, stream.filter를 활용하여 특정 메뉴 이름을 가진 메뉴 장바구니에서 제거

 

 


 

 

 

문제 풀이

앞서 설명한 내용은 생략하겠습니다.

 

Main

더보기
public class Main {
    public static void main(String[] args) {
        Kiosk kiosk = new Kiosk();

        kiosk.start();
    }
}

 

Kiosk

더보기
import java.util.InputMismatchException;
import java.util.Scanner;

public class Kiosk {
    // 속성
    private final Menu menu = new Menu();
    private final ShoppingBascket shoppingBascket = new ShoppingBascket();

    // 생성자
    public Kiosk() {
        menu.addMenu(new Burger("ShackBurger", 6.9, "토마토, 양상추, 쉑소스가 토핑된 치즈버거", MenuType.BURGER));
        menu.addMenu(new Burger("SmokeShack", 8.9, "베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거", MenuType.BURGER));
        menu.addMenu(new Burger("Cheeseburger", 6.9, "포테이토 번과 비프패티, 치즈가 토핑된 치즈버거", MenuType.BURGER));
        menu.addMenu(new Burger("Hamburger", 5.4, "비프패티를 기반으로 야채가 들어간 기본버거", MenuType.BURGER));
        menu.addMenu(new Cake("CheeseCake", 10.4, "내가 제일 좋아하는 치즈 케이크", MenuType.CAKE));
        menu.addMenu(new Cake("ChocolateCake", 5.4, "내가 제일 싫어하는 치즈 케이크", MenuType.CAKE));
    }

    // 기능
    // 키오스크 동작
    public void start() {
        int mainMenuInput;
        int menuInput;
        int shoppingBascketInput;

        do {
            try {
                // 메인 메뉴를 보여준다.
                menu.showMainMenu();
                if (!shoppingBascket.getList().isEmpty()) shoppingBascket.showOrderMenu();

                // 메인 메뉴에 대한 사용자의 입력을 받는다.
                System.out.print("메뉴를 선택하세요 : ");

                mainMenuInput = userInput();
                if (mainMenuInput == 0) {
                    System.out.println("종료합니다.");
                    return;
                }


                // 장바구니 메뉴가 보이지 않을 때, 전체 메뉴 갯수 보다 큰 수를 입력 시 예외 생성
                if (shoppingBascket.getList().isEmpty() && mainMenuInput > menu.getTotalMenuCount()) throw new IndexOutOfBoundsException();
                // 장바구니가 보일 때, 전체 메뉴 갯수 + 장바구니 메뉴 갯수(2) 보다 큰 수를 입력 시 예외 생성
                if (mainMenuInput > menu.getTotalMenuCount() + 2) throw new IndexOutOfBoundsException();

                // 장바구니 확인
                if (mainMenuInput == menu.getTotalMenuCount() + 1) {
                    shoppingBascket.showShoppingBascketMenu();

                    System.out.println("\n1. 주문\t\t2. 메뉴 삭제\t\t3. 메뉴판");
                    System.out.print("주문하시겠습니까? ");
                    int input = userInput();

                    // 주문 완료
                    switch (input) {
                        case 1 -> {
                            int num = 1;

                            System.out.println("할인 정보를 입력해주세요.");
                            for (DiscountType discountType : DiscountType.values()) {
                                System.out.println(num++ + ". " + discountType.getTarget() + "\t: " + discountType.getDiscount() + "%");
                            }

                            System.out.print("입력해주세요 : ");
                            Discount discount = new Discount(userInput());

                            double totalCost = shoppingBascket.getTotalCost();
                            System.out.printf("주문이 완료되었습니다. 금액은 w %.2f 입니다.\n\n", discount.Calculate(totalCost));
                            shoppingBascket.resetTotalCost();
                            shoppingBascket.resetshoppingBascket();
                            continue;
                        }
                        case 2 -> {
                            Scanner scanner = new Scanner(System.in);

                            shoppingBascket.showShoppingBascketMenu();
                            System.out.print("장바구니에서 어떤 음식을 삭제하시겠습니까? ");
                            String food_name = scanner.nextLine();

                            shoppingBascket.deleteMenu(food_name);
                            continue;
                        }
                        case 3 -> {
                            System.out.println();   // 줄바꿈
                            continue;
                        }
                        default -> throw new IndexOutOfBoundsException();
                    }
                }

                // 주문 취소
                if (mainMenuInput == menu.getTotalMenuCount() + 2) {
                    System.out.println("주문이 취소되었습니다.\n");
                    shoppingBascket.resetshoppingBascket();
                    continue;
                }

                // 메뉴를 보여준다.
                menu.showMenu(mainMenuInput);

                // 메뉴에 대한 사용자의 입력을 받는다.
                System.out.print("메뉴를 선택하세요 : ");
                menuInput = userInput();
                if (menuInput == 0) {
                    System.out.println();
                    continue;
                }

                // 선택된 메뉴 보여주기
                menu.showSelectedFood(mainMenuInput, menuInput);

                // 장바구니에 추가할건지에 대한 사용자의 입력받기
                System.out.println("위 메뉴를 장바구니에 추가하시겠습니까?");
                System.out.println("1. 확인\t\t2. 취소");
                System.out.print("추가하시겠습니까? ");
                shoppingBascketInput = userInput();

                // 장바구니에 추가하기
                switch (shoppingBascketInput) {
                    case 1 -> shoppingBascket.addMenu(menu.getMenuItems(mainMenuInput, menuInput));
                    case 2 -> System.out.println("취소되었습니다.\n");
                    default -> throw new IndexOutOfBoundsException();
                }

            } catch (IndexOutOfBoundsException e) {
                System.out.println("없는 메뉴입니다.\n");
            } catch (InputMismatchException e) {
                System.out.println("숫자를 입력해주세요.\n");
            }
        } while(true);
    }

    // 유저 메뉴 입력 받는 함수
    private int userInput() {
        Scanner scanner = new Scanner(System.in);
        return scanner.nextInt();
    }
}
  • if문을 통해 여러 분기로 나눴던 기존 코드에서 switch 문을 사용하여, 가독성을 향상시켰다.
  • 장바구니에서 특정 객체를 삭제하는 메서드를 ShoppingBascket 클래스에 만들어서 사용한다.
  • 할인을 적용하기위한 메서드를 Discount 클래스에 만들어서 사용한다. (할인을 관리하기 위한 클래스를 하나 만들었다.)

 

 

ShoppingBascket

더보기
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class ShoppingBascket {
    List<MainMenu> shoppingBascket = new ArrayList<>();
    double totalCost = 0;

    public void showOrderMenu() {
        int num = MenuType.values().length;

        System.out.println();
        System.out.println("[ ORDER MENU ]");
        System.out.println(++num + " Orders\t\t | 장바구니를 확인 후 주문합니다.");
        System.out.println(++num + " Cancel\t\t | 진행중인 주문을 취소합니다.");
    }

    public void addMenu(MainMenu mainMenu) {
        System.out.println(mainMenu.getFood_name() + "이 장바구니에 추가되었습니다.\n");
        shoppingBascket.add(mainMenu);
        addItemPrice(mainMenu);
    }

    public List<MainMenu> getList() {
        return shoppingBascket;
    }

    public void showShoppingBascketMenu() {

        System.out.println("\n[ Orders ]");
        for (MainMenu menu : shoppingBascket) {
            System.out.println(menu.getFood_name() + " | " + menu.getPrice() + " | " + menu.getIngredients());
        }
        System.out.println("\n[ Total ]");
        System.out.printf("w %.2f\n", totalCost);
    }

    public double getTotalCost() {
        return totalCost;
    }

    private boolean isFindMenu(String name) {
        for (MainMenu mainMenu : shoppingBascket) {
            if(mainMenu.getFood_name().equalsIgnoreCase(name)) return true;
        }
        return false;
    }


    public void deleteMenu(String name) {
        if (isFindMenu(name)) {
            // 전체 비용에서 메뉴 값 만큼 삭제
            subtractItemPrice(name);

            shoppingBascket = shoppingBascket.stream()
                    .filter(menu -> !menu.getFood_name().equalsIgnoreCase(name))
                    .collect(Collectors.toList());
            System.out.println(name + "이/가 장바구니에서 삭제되었습니다.\n");

        } else {
            System.out.println("음식이 존재하지 않습니다.\n");
        }
    }

    public void addItemPrice(MainMenu mainMenu) {
        totalCost += mainMenu.getPrice();
    }

    private void subtractItemPrice(String name) {
        shoppingBascket.stream()
                .filter(menu -> menu.getFood_name().equalsIgnoreCase(name))
                .findAny().ifPresent(mainMenu -> totalCost -= mainMenu.getPrice());
    }

    public void resetshoppingBascket () {
        shoppingBascket.clear();
    }

    public void resetTotalCost() {
        totalCost = 0;
    }
}
  • 특정 메뉴를 삭제하는 메서드, 그 값만큼 전체 비용에서 삭제하 메서드를 만들었다.

 

 

Menu

더보기
import java.util.ArrayList;
import java.util.List;

public class Menu {
    // 속성
    private final List<List<MainMenu>> menuItems = new ArrayList<>();

    // 생성자
    public Menu() {
        for(int i = 0; i < MenuType.values().length; i ++) {
            menuItems.add(new ArrayList<>());
        }
    }

    // 메뉴 추가하는 기능
    public void addMenu(MainMenu newFood) {
        menuItems.get(newFood.getMenuType().getNum()-1).add(newFood);
    }

    // 메인 메뉴 보여주는 기능
    public void showMainMenu() {
        int num = 1;
        System.out.println("[ MAIN MENU ]");
        System.out.println("0. 종료\t\t | 종료");
        for(MenuType type : MenuType.values()){
            System.out.println(num++ + ". " + type.name());
        }
    }


    // 메뉴 보여주는 기능
    public void showMenu(int input) {
        int num = 1;

        System.out.println("\n[ SHAKESHACK MENU ]");
        System.out.println("0. 뒤로가기\t\t");
        for (MainMenu menuItem : menuItems.get(input-1)) {
            System.out.println(num++ + ". "
                    + menuItem.getFood_name() + "\t | w "
                    + menuItem.getPrice() + " |\t"
                    + menuItem.getIngredients());
        }
    }


    // 메뉴 정보 제공
    public void showSelectedFood(int mainMenuInput, int menuInput) {
        System.out.println("선택한 메뉴 : "
                + menuItems.get(mainMenuInput-1).get(menuInput-1).getFood_name() + "\t | w "
                + menuItems.get(mainMenuInput-1).get(menuInput-1).getPrice() + " |\t"
                + menuItems.get(mainMenuInput-1).get(menuInput-1).getIngredients());
        System.out.println();
    }

    public MainMenu getMenuItems(int num, int num1) {
        return menuItems.get(num-1).get(num1-1);
    }

    public int getTotalMenuCount() {
        return MenuType.values().length;
    }
}

 

 

MenuType

더보기
public enum MenuType {
    BURGER(1),
    DRINK(2),
    DESSERT(3),
    CAKE(4);

    private final int num;

    MenuType(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }
}

 

 

MainMenu

더보기
public abstract class MainMenu {
    private final String food_name;
    private final double price;
    private final String ingredients;
    private final MenuType menuType;

    public MainMenu(String food_name, double price, String ingredients, MenuType menuType) {
        this.food_name = food_name;
        this.price = price;
        this.ingredients = ingredients;
        this.menuType = menuType;
    }

    public String getFood_name() {
        return food_name;
    }

    public double getPrice() {
        return price;
    }

    public String getIngredients() {
        return ingredients;
    }

    public MenuType getMenuType() {
        return menuType;
    }
}

 

 

Burger

더보기
public class Burger extends MainMenu {

    public Burger(String food_name, double price, String ingredients, MenuType menuType) {
        super(food_name, price, ingredients, menuType);
    }
}

 

 

Drink

더보기
public class Drink extends MainMenu {

    public Drink(String food_name, double price, String ingredients, MenuType menuType) {
        super(food_name, price, ingredients, menuType);
    }
}

 

 

Dessert

더보기
public class Dessert extends MainMenu {

    public Dessert(String food_name, double price, String ingredients, MenuType menuType) {
        super(food_name, price, ingredients, menuType);
    }
}

 

 

Cake

더보기
package com.example.kiosk.challenge_2;

public class Cake extends MainMenu {

    public Cake(String food_name, double price, String ingredients, MenuType menuType) {
        super(food_name, price, ingredients, menuType);
    }
}

 

 

DiscountType

더보기
public enum DiscountType {
    VETERAN("국가 유공자", 10),
    SOLDER("군인", 5),
    STUDENT("학생",3),
    NORMAL("일반",0);

    private final String target;
    private final int discount;

    DiscountType(String target, int discount) {
        this.target = target;
        this.discount = discount;
    }

    public String getTarget() {
        return target;
    }

    public int getDiscount() {
        return discount;
    }
}
  • 각 할인율을 적용하기 위해 할인 타입을 정해주는 enum을 추가하였다.

 

 

Discount

public class Discount {
    DiscountType type;

    public Discount(int num) {
        switch(num) {
            case 1 -> type=DiscountType.VETERAN;
            case 2 -> type=DiscountType.SOLDER;
            case 3 -> type=DiscountType.STUDENT;
            case 4 -> type=DiscountType.NORMAL;
            default -> throw new IndexOutOfBoundsException();
        }
    }

    public double Calculate(double totalCost) {
        return totalCost - totalCost*(type.getDiscount()*0.01);
    }
}
  • 입력받은 값을 통해 생성자에서 할인 타입을 만들어주었다.
  • Kiosk 클래스에서 예외처리를 한 번에 해주기 위해, RuntimeException의 자식인 IndexOutOfBoundsException을 생성하고 던져주었다.
  • Calculate() 메서드를 통해 할인율이 적용된 값을 반환해준다.

'JAVA' 카테고리의 다른 글

[Java] Lv_2 도서관 프로젝트  (0) 2025.05.01
[Java] Lv_1 도서관 프로젝트  (0) 2025.05.01
[Java] 제네릭(Generic), 왜 사용할까?  (0) 2025.04.28
[Java] 도전 과제 Lv_1 키오스크  (0) 2025.04.26
[Java] Lv_4 & 5 키오스크 문제  (0) 2025.04.25