키오스크 프로젝트 Challenge LV1

서연·2025년 5월 1일

Java

목록 보기
29/36

✅ 장바구니 및 구매하기 기능 추가

⚙️ 구조

  • 장바구니 생성 및 관리 기능
    • 사용자가 선택한 메뉴를 장바구니에 추가할 수 있는 기능을 제공한다.
    • 장바구니는 메뉴명, 수량, 가격 정보를 저장하며, 항목을 동적으로 추가 및 조회할 수 있어야 한다.
    • 사용자가 잘못된 선택을 했을 경우 예외를 처리한다. (ex : 유효하지 않은 메뉴 번호 입력)

  • 장바구니 출력 및 금액 계산
    • 사용자가 결제를 시도하기 전에, 장바구니에 담긴 모든 메뉴와 총 금액을 출력한다.
    • 출력 예시
      • 각 메뉴의 이름, 가격, 수량
      • 총 금액 합계

  • 장바구니 담기 기능
    • 메뉴를 클릭하면 장바구니에 추가할 지 물어보고, 입력값에 따라 “추가”, “취소” 처리한다.
    • 장바구니에 담은 목록을 출력한다.

  • 주문 기능
    • 장바구니에 담긴 모든 항목을 출력한다.
    • 합산하여 총 금액을 계산하고, “주문하기”를 누르면 장바구니를 초기화합니다.

📄 코드

CLv1Main.java

package ChallengeLv1;

public class CLv1Main {
    public static void main(String[] args) {
        CLv1Menu cLv1Menu = new CLv1Menu();

        // CLv1Menu 에 있는 lv4Menus 라는 리스트에 getter 를 사용해 햄버거 정보를 추가
        cLv1Menu.getCLv1Menus().add(new CLv1Menu("Burgers"));
        cLv1Menu.getCLv1Menus().add(new CLv1Menu("Drinks"));
        cLv1Menu.getCLv1Menus().add(new CLv1Menu("Desserts"));

        // CLv1Menu 에 있는 burgersMenu 라는 리스트에 getter 를 사용해 햄버거 정보를 추가
        cLv1Menu.getBurgersMenu().add(new CLv1MenuItem("ShackBurger", 6.9, "토마토, 양상추, 쉑소스가 토핑된 치즈버거"));
        cLv1Menu.getBurgersMenu().add(new CLv1MenuItem("SmokeShack", 8.9, "베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거"));
        cLv1Menu.getBurgersMenu().add(new CLv1MenuItem("Cheeseburger", 6.9, "포테이토 번과 비프패티, 치즈가 토핑된 치즈버거"));
        cLv1Menu.getBurgersMenu().add(new CLv1MenuItem("Hamburger", 5.4, "비프패티를 기반으로 야채가 들어간 기본버거"));

        // CLv1Menu 에 있는 drinksMenu 라는 리스트에 getter 를 사용해 음료 정보를 추가
        cLv1Menu.getDrinksMenu().add(new CLv1MenuItem("Fountain Soda", 2.9, "코카콜라, 코카콜라 제로, 스프라이트, 환타 오렌지"));
        cLv1Menu.getDrinksMenu().add(new CLv1MenuItem("Lemonade", 4.5, "매장에서 직접 만드는 상큼한 레몬에이드"));
        cLv1Menu.getDrinksMenu().add(new CLv1MenuItem("Fresh Brewed Iced Tea", 3.7, "직접 유기농 홍차를 우려낸 아이스 티"));
        cLv1Menu.getDrinksMenu().add(new CLv1MenuItem("Fifty/Fifty", 4.0, "레몬에이드와 유기농 홍차를 우려낸 아이스 티가 만나 탄생한 시그니처 음료"));

        // CLv1Menu 에 있는 dessertsMenu 라는 리스트에 getter 를 사용해 디저트 정보를 추가
        cLv1Menu.getDessertsMenu().add(new CLv1MenuItem("Shack Attack", 6.2, "진한 초콜릿 커스터드에 퍼지 소스와 세 가지 초콜릿 토핑이 블렌딩된 콘크리트"));
        cLv1Menu.getDessertsMenu().add(new CLv1MenuItem("Classic Hand-Spun Shakes", 6.8, "쫀득하고 진한 커스터드가 들어간 클래식 쉐이크"));
        cLv1Menu.getDessertsMenu().add(new CLv1MenuItem("Cup & Cones", 5.7, "신선하게 제조하는 쫀득하고 진한 아이스크림"));

        CLv1Kiosk cLv1Kiosk = new CLv1Kiosk(cLv1Menu);
        cLv1Kiosk.start(); // CLv1Kiosk 에 있는 start 함수 실행
    }
}

CLv1MenuItem.java

package ChallengeLv1;

public class CLv1MenuItem {
    // 1. 속성
    private String name;
    private double price;
    private String foodDetails;

    // 2. 생성자
    public CLv1MenuItem(String name, double price, String foodDetails) {
        this.name = name;
        this.price = price;
        this.foodDetails = foodDetails;

    }

    // 3. 기능(메서드)
    // 주소값을 출력하는 것이 아닌 리스트안에 들어있는 값을 출력하기 위해 toString 메서드 작성
    public String toString() {
        return name + " | " + "W" + price + " | " + foodDetails;
    }

    // name 의 getter 메서드
    public String getName() {
        return name;
    }

    // price 의 getter 메서드
    public double getPrice() {
        return price;
    }
}

CLv1Kiosk.java

package ChallengeLv1;

import java.util.InputMismatchException;
import java.util.Scanner;

public class CLv1Kiosk {
    CLv1Menu cLv1Menu;
    CLv1Cart cLv1Cart = new CLv1Cart();
    Scanner scanner = new Scanner(System.in);
    int num1 = 0; // 메인메뉴 선택을 위한 변수 생성
    int num2 = 0; // 버거메뉴, 음료메뉴, 디저트 메뉴 선택을 위한 변수 생성


    // 2. 생성자
    public CLv1Kiosk(CLv1Menu cLv1Menu) {
        this.cLv1Menu = cLv1Menu;
    }

    // 3. 기능(메서드)
    // 메뉴 입력값을 받아 유효성 검사 후 반환하는 메서드
    public int getInput(Scanner scanner, int min, int max) {
        int input = -1;
        while (true) {
            System.out.print("원하시는 메뉴를 선택해주세요: ");
            try {
                input = scanner.nextInt();
                if (input < min || input > max) {
                    throw new IllegalArgumentException();
                }
                break;
            } catch (IllegalArgumentException | InputMismatchException e) {
                System.out.println("올바른 숫자를 입력해주세요.");
                scanner.nextLine();
            }
        }
        return input;
    }

    public void start() { // 입력과 반복문 로직
        while (true) { // 사용자가 종료를 누르기 전까지 계속 반복
            System.out.println("\n");
            cLv1Menu.mainMenu(); // 메인 메뉴를 출력하는 메서드

            if (!cLv1Cart.getCarts().isEmpty()) { // 장바구니에 값이 들어있을 경우 order menu 를 보여준다.
                System.out.println("\n");
                cLv1Cart.orderMenu();
                num1 = getInput(scanner, 0, 5); // 코드가 반복되는 부분을 getInput 메서드로 처리(메뉴 입력값을 받아 유효성 검사 후 반환하는 메서드)
            }

            if (cLv1Cart.getCarts().isEmpty()) { // 장바구니가 비어있을 경우 0,1,2,3 이외의 값 입력시 예외처리
                System.out.println("\n");
                num1 = getInput(scanner, 0, 3); // 코드가 반복되는 부분을 getInput 메서드로 처리(메뉴 입력값을 받아 유효성 검사 후 반환하는 메서드)
            }

            if (num1 == 0) break; // 프로그램 종료

            while (true) { // 사용자가 종료하기 전까지 반복한다.
                System.out.println("\n");
                if (num1 == 1) {
                    cLv1Menu.burgersMenu();
                } else if (num1 == 2) {
                    cLv1Menu.drinkMenu();
                } else if (num1 == 3) {
                    cLv1Menu.dessertsMenu();
                } else if (num1 == 4) { // 메인메뉴에서 4를 입력했을 때 orders 메서드(장바구니를 확인 후 주문하는 메서드)가 실행된다.
                    cLv1Cart.orders();
                    break;
                } else if (num1 == 5) { // 메인메뉴에서 5를 입력했을 때 cancel 메서드(진행중인 주문을 취소하는 메서드)가 실행된다.
                    cLv1Cart.cancel();
                    break;
                }
                try { // 다른 값을 입력했을 시 예외처리
                    System.out.print("원하시는 메뉴를 선택해주세요: ");
                    num2 = scanner.nextInt();
                    if (num2 == 0) break; // 0을 입력하면 메인메뉴로 돌아가게 된다.
                    if (num1 == 1) {
                        System.out.println("선택한 메뉴: " + cLv1Menu.getBurgersMenu().get(num2 - 1));
                        cLv1Cart.getCarts().add(cLv1Menu.getBurgersMenu().get(num2 - 1)); // burgerMenu 리스트에 들어있는 선택한 메뉴를 cartsList 에 저장하기 위해 getter 를 사용한다.
                    } else if (num1 == 2) {
                        System.out.println("선택한 메뉴: " + cLv1Menu.getDrinksMenu().get(num2 - 1));
                        cLv1Cart.getCarts().add(cLv1Menu.getDrinksMenu().get(num2 - 1)); // burgerMenu 리스트에 들어있는 선택한 메뉴를 cartsList 에 저장하기 위해 getter 를 사용한다.
                    } else if (num1 == 3) {
                        System.out.println("선택한 메뉴: " + cLv1Menu.getDessertsMenu().get(num2 - 1));
                        cLv1Cart.getCarts().add(cLv1Menu.getDessertsMenu().get(num2 - 1)); // burgerMenu 리스트에 들어있는 선택한 메뉴를 cartsList 에 저장하기 위해 getter 를 사용한다.
                    }
                    cLv1Cart.cartsAdd(); // cartsAdd 메서드(장바구니에 메뉴를 추가하는 메서드)를 실행한다.
                    break; // 메인메뉴로 돌아가게 된다.
                } catch (IndexOutOfBoundsException | InputMismatchException e) {
                    System.out.println("올바른 숫자를 입력해주세요");
                    scanner.nextLine(); // 버퍼에 남아있는 값을 제거하기 위해 사용
                }
            }
        }
    }
}

CLv1Menu.java

package ChallengeLv1;

import java.util.ArrayList;
import java.util.List;

public class CLv1Menu {// MenuItem 클래스를 관리하는 클래스
    // 1. 속성
    private final List<CLv1MenuItem> burgersMenu = new ArrayList<>(); // 버거 메뉴를 저장하는 리스트
    private final List<CLv1MenuItem> drinksMenu = new ArrayList<>(); // 음료 메뉴를 저장하는 리스트
    private final List<CLv1MenuItem> dessertsMenu = new ArrayList<>(); // 디저트 메뉴를 저장하는 리스트
    private final List<CLv1Menu> cLv1Menus = new ArrayList<>(); // 메인 메뉴를 저장하는 리스트
    private String name;

    // 2. 생성자
    public CLv1Menu() {
    }

    public CLv1Menu(String name) {
        this.name = name;
    }

    // 3. 기능(메서드)
    // 메인 메뉴를 보여주는 메서드
    public void mainMenu() {
        System.out.println("[ MAIN MENU ]");
        for (int i = 0; i < cLv1Menus.size(); i++) {
            System.out.print(i + 1 + ". ");
            System.out.println(cLv1Menus.get(i));
        }
        System.out.println("0. 종료");
    }

    // 버거 메뉴를 보여주는 메서드
    public void burgersMenu() {
        System.out.println("[ BURGERS MENU ]");
        for (int i = 0; i < burgersMenu.size(); i++) {
            System.out.print(i + 1 + ". ");
            System.out.println(burgersMenu.get(i));
        }
        System.out.println("0. 뒤로가기");
    }

    // 음료 메뉴를 보여주는 메서드
    public void drinkMenu() {
        System.out.println("[ DRINKS MENU ]");
        for (int i = 0; i < drinksMenu.size(); i++) {
            System.out.print(i + 1 + ". ");
            System.out.println(drinksMenu.get(i));
        }
        System.out.println("0. 뒤로가기");
    }

    // 디저트 메뉴를 보여주는 메서드
    public void dessertsMenu() {
        System.out.println("[ DESSERTS MENU ]");
        for (int i = 0; i < dessertsMenu.size(); i++) {
            System.out.print(i + 1 + ". ");
            System.out.println(dessertsMenu.get(i));
        }
        System.out.println("0. 뒤로가기");
    }

    // 주소값을 출력하는 것이 아닌 리스트안에 들어있는 값을 출력하기 위해 toString 메서드 작성
    public String toString() {
        return name;
    }

    // 버거 메뉴의 getter 메서드
    public List<CLv1MenuItem> getBurgersMenu() {
        return burgersMenu;
    }

    // 음료 메뉴의 getter 메서드
    public List<CLv1MenuItem> getDrinksMenu() {
        return drinksMenu;
    }

    // 디저트 메뉴의 getter 메서드
    public List<CLv1MenuItem> getDessertsMenu() {
        return dessertsMenu;
    }

    // 메인 메뉴의 getter 메서드
    public List<CLv1Menu> getCLv1Menus() {
        return cLv1Menus;
    }
}

CLv1Cart.java

package ChallengeLv1;

import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;

public class CLv1Cart {

    // 1. 속성
    // 선택한 메뉴의 정보를 저장하는 리스트
    private final List<CLv1MenuItem> cartsList = new ArrayList<>();
    Scanner scanner = new Scanner(System.in);

    // 2. 생성자

    // 3. 기능
    // 장바구니에 메뉴를 추가하는 메서드
    public void cartsAdd() {
        System.out.println("\n");
        System.out.println("\"" + cartsList.get(cartsList.size() - 1) + "\""); // cartsList 에 담겨있는 마지막 값을 보여준다.(선택한 메뉴가 cartsList 마지막에 저장되어 있다.)
        System.out.println("위 메뉴를 장바구니에 추가하시겠습니까?");
        System.out.println("1. 확인        2. 취소");

        int cartNum = 0; // 장바구니에 추가 여부를 위한 변수 생성
        while (true) {
            try {
                cartNum = scanner.nextInt();
                if (cartNum != 1 && cartNum != 2) {
                    throw new IllegalArgumentException();
                }
            } catch (IllegalArgumentException | InputMismatchException e) {
                System.out.println("올바른 숫자를 입력해주세요.");
                scanner.nextLine(); // 버퍼에 남아있는 값을 제거하기 위해 사용
            }

            if (cartNum == 1) { // 1을 입력하면 장바구니에 추가된 메뉴 이름을 출력한다.
                System.out.println(cartsList.get(cartsList.size() - 1).getName() + " 이 장바구니에 추가되었습니다.");
                break; // 바른 값을 입력했을 시 while 문에서 빠져나온다.
            } else if (cartNum == 2) { // 2를 입력하면 장바구니에 추가하지 않기 때문에 cartsList 에 있는 마지막 값을 삭제한다.
                cartsList.remove(cartsList.size() - 1);
                System.out.println("메뉴 선택이 취소되었습니다.");
                break; // 바른 값을 입력했을 시 while 문에서 빠져나온다.
            }
        }
    }

    // ORDER MENU 를 출력하는 메서드
    public void orderMenu() {
        System.out.println("[ ORDER MENU ]\n" +
                "4. Orders       | 장바구니를 확인 후 주문합니다.\n" +
                "5. Cancel       | 진행중인 주문을 취소합니다.");
    }

    // 진행중인 주문을 취소하는 메서드
    public void cancel() {
        cartsList.clear(); // cartsList 에 담겨 있는 모든 값을 제거한다.
    }

    // 장바구니를 확인 후 주문하는 메서드
    public void orders() {
        int finalOrd = 0; // 최종으로 메뉴를 주문하기 위한 변수 생성
        double sumResult = 0; // 주문할 가격의 합을 나타내기 위한 변수 생성

        while (finalOrd != 1 && finalOrd != 2) { // 1또는 2를 입력하기 전까지 반복
            System.out.println("\n" + "아래와 같이 주문 하시겠습니까?");
            System.out.println("[ Orders ]\n" + cartsList + "\n"); // 장바구니에 담겨 있는 메뉴를 보여준다.

            int size = cartsList.size(); // cartsList 의 사이즈 변수 생성
            double sum = 0; // total 금액 변수 생성
            for (int i = 0; i < size; i++) { // cartsList 에 있는 가격의 합을 for 문을 활용해 구한다.
                sum += cartsList.get(i).getPrice();
            }
            sumResult = Math.round(sum * 10) / 10.0; // 가격의 합을 소숫점 첫째자리까지 나타내기 위해 Math.round 를 사용한다.
            System.out.println("[ Total ]" + "\n" + "W " + sumResult + "\n");

            System.out.println("1. 주문      2. 메뉴판");

            try { // 1과 2 제외 다른 값이 입력됐을 경우 예외처리
                finalOrd = scanner.nextInt(); // 최종으로 메뉴를 주문하기 위해 숫자를 입력 받는다.
                if (finalOrd < 1 || finalOrd > 2) {
                    throw new IllegalArgumentException();
                }
            } catch (IllegalArgumentException | InputMismatchException e) {
                System.out.println("올바른 값을 입력해주세요");
                scanner.nextLine(); // 버퍼에 남아있는 값을 제거하기 위해 사용
            }
        }
        if (finalOrd == 1) {
            System.out.println("\n" + "주문이 완료되었습니다. 금액은 W " + sumResult + "입니다.");
            cartsList.clear();
        }
    }

    // cartsList 의 getter 메서드
    public List<CLv1MenuItem> getCarts() {
        return cartsList;
    }
}

⚠️ 트러블 슈팅 ⚠️

문제 상황

장바구니에 추가할 메뉴의 이름을 불러올 때 정상적으로 작동하지 않고 IndexOutOfBoundsException 오류가 나는 상황

문제 이유

System.out.println("\"" + cartsList.get(cartsList.size()) + "\""); 처럼 잘못 작성했을 때 오류가 발생한다. cartsList.size()는 리스트의 크기를 반환하는데 리스트의 인덱스는 0부터 시작하므로 size()는 마지막 인덱스보다 1 더 큰 값을 반환한다. 예를 들어 리스트의 크기가 3일 경우 마지막 인덱스는 2인데 size()3를 반환하므로 size(3)는 존재하지 않는 인덱스이기 때문에 IndexOutOfBoundsException 오류가 발생한다.

해결 방법

System.out.println("\"" + cartsList.get(cartsList.size() - 1) + "\""); 로 적어줘야한다.

💡 느낀점

IndexOutOfBoundsException 오류를 통해 리스트의 인덱스 범위를 잘못 이해하고 접근할 때 발생하는 문제를 경험하면서 size()는 리스트의 크기일 뿐 마지막 인덱스를 의미하지 않는다는 점을 새로 배웠다.
또한 소수점 처리를 할 때 Math.round(sum * 10) / 10.0을 사용하여 소수점을 특정 자리까지 반올림하는 방법을 알게 되었다.

🔗 GitHub

프로젝트 코드 보러 가기

0개의 댓글