ABOUT ME

주니어 개발자

Today
Yesterday
Total
  • [과제] 키오스크 도전 Lv1
    내일배움캠프/과제 2025. 3. 13. 16:30

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

    1️⃣ 과제 조건

    • 요구사항이 가지는 의도
      • 의도: 클래스 간 연계를 통해 객체 지향 프로그래밍의 기본적인 설계를 익히고, 사용자 입력에 따른 프로그램 흐름 제어와 상태 관리를 학습
      • 목표
        • 클래스 간 역할 분리를 이해하고, 적절히 협력하는 객체를 설계
        • 프로그램 상태 변경 및 데이터 저장을 연습
        • 사용자 입력에 따른 예외 처리와 조건 분기를 연습
    • 장바구니 생성 및 관리 기능
      • 사용자가 선택한 메뉴를 장바구니에 추가할 수 있는 기능을 제공합니다.
      • 장바구니는 메뉴명, 수량, 가격 정보를 저장하며, 항목을 동적으로 추가 및 조회할 수 있어야 합니다.
      • 사용자가 잘못된 선택을 했을 경우 예외를 처리합니다(예: 유효하지 않은 메뉴 번호 입력)
    • 장바구니 출력 및 금액 계산
      • 사용자가 결제를 시도하기 전에, 장바구니에 담긴 모든 메뉴와 총 금액을 출력합니다.
      • 출력 예시
        • 각 메뉴의 이름, 가격, 수량
        • 총 금액 합계
    • 장바구니 담기 기능
      • 메뉴를 클릭하면 장바구니에 추가할 지 물어보고, 입력값에 따라 “추가”, “취소” 처리합니다.
        • 메뉴는 한 번에 1개만 담을 수 있습니다.
      • 장바구니에 담은 목록을 출력합니다.
    • 주문 기능
      • 장바구니에 담긴 모든 항목을 출력합니다.
      • 합산하여 총 금액을 계산하고, “주문하기”를 누르면 장바구니를 초기화합니다.

     

    2️⃣ 구현 포인트

    1. 장바구니 클래스 생성

    • 선택한 MenuItem 의 정보를 List에 add 시킬 클래스 생성
    
      
    public class Order {
    private final List<MenuItem> orderList;
    public Order() {
    this.orderList = new ArrayList<>();
    }
    // 장바구니 추가
    public void addOrder(MenuItem order) {
    this.orderList.add(order);
    }
    // 장바구니 비우기
    public void clearOrder() {
    this.orderList.clear();
    }
    // 장바구니 empty 여부
    public boolean isEmptyOrder() {
    return this.orderList.isEmpty();
    }
    }

     

    2. 장바구니에 물건이 있을 시 Order 메뉴 출력

    • 장바구니에 물건이 없으면 Order 을 진행할 이유가 없기에 있는지 검사 후 메뉴 출력
    • Main menu 선택도 Order 메뉴 출력, 미출력에 따라 검증 
    
      
    while (true) {
    this.printMainMenu(); // MAIN MENU 목록 출력 함수 실행
    int menuNo;
    if (order.isEmptyOrder()) { // 장바구니가 비어있을 경우
    System.out.println(String.format("%-12s | 종료\n", "0. 종료"));
    menuNo = inputHandler.getUserInput(br, menuListSize, true); // inputHandler 실행
    } else { // 장바구니에 물건이 있을 경우
    this.printOrderMenu(); // ORDER MENU 출력
    System.out.println(String.format("%-12s | 종료\n", "0. 종료"));
    menuNo = inputHandler.getUserInput(br, menuListSize + 2, true); // inputHandler 실행
    }
    if (menuNo == 0) { // 0 이면 프로그램 종료
    break;
    }
    if (!order.isEmptyOrder() && menuNo > menuListSize) { // ORDER MENU 선택시
    if (menuNo == menuListSize + 1) { // Orders 버튼
    this.processOrder(br); // 주문 프로세스 실행
    } else { // Cancel 버튼
    order.clearOrder(); // 장바구니 초기화
    System.out.println("\n! 주문이 취소되었습니다 ! ");
    }
    } else { // MAIN MENU 선택 시 1
    this.processMenuSelection(br, menuList.get(menuNo - 1)); // 선택한 Menu 진행
    }
    }

     

    3. getUserInput 리팩토링

    • 장바구니 기능을 추가하면서 선택지에 0이 없는 번호 입력받기가 생김
    • 기존 기능을 그대로 살리고 싶어서 useZero 라는 파라미터 추가
    
      
    public class InputHandler {
    public int getUserInput(BufferedReader br, int maxOption, boolean useZero) throws IOException {
    while (true) {
    System.out.print("번호를 선택해주세요 : ");
    String input = br.readLine();
    if (isValidInput(input, maxOption, useZero)) {
    return Integer.parseInt(input);
    }
    System.out.println("\n! 올바른 번호를 입력해주세요 !\n");
    }
    }
    // valid input
    private boolean isValidInput(String input, int maxOption, boolean useZero) {
    try {
    int number = Integer.parseInt(input);
    return useZero ? (number >= 0 && number <= maxOption) : (number > 0 && number <= maxOption);
    } catch (NumberFormatException e) {
    return false;
    }
    }
    }

     

     

    4. processMenuSelection 장바구니 추가 로직

    • 메뉴를 선택하면 장바구니에 추가할건지 선택하는 로직 구현
    • 취소 시 해당 메뉴 목록 재출력
    
      
    private void processMenuSelection(BufferedReader br, Menu menu) throws IOException {
    while (true) {
    System.out.printf("\n[ %s MENU ]\n", menu.getCategory().toUpperCase()); // 선택한 메뉴 출력
    menu.printMenuItemList(); // 선택한 메뉴의 menuItem List 출력
    int itemNo = inputHandler.getUserInput(br, menu.getMenuItemsSize(), true); // 입력받기
    if (itemNo != 0) { // 메뉴 선택시
    menu.printMenuItemDetails(itemNo - 1); // menuItem Detail 출력
    MenuItem menuItem = menu.getMenuItemByIndex(itemNo - 1); // menuItem 가져 옴
    System.out.println("\n위 메뉴를 장바구니에 추가하시겠습니까?");
    System.out.println("1. 확인 2. 취소\n");
    int orderNo = inputHandler.getUserInput(br, 2, false); // 입력받기
    if (orderNo == 1) { // 장바구니 추가
    System.out.println(menuItem.getMenuNm() + " 이 장바구니에 추가되었습니다.");
    order.addOrder(menuItem);
    break;
    }
    System.out.println("취소 되었습니다.");
    } else { // 돌아가기 선택 시
    break;
    }
    }
    }

     

    5. processOrder

    • 주문시 장바구니 목록 출력
    • 총 금액 출력은 stream()함수의 sum() 함수를 이용하여 list의 모든 price 를 합쳐서 return
    
      
    private void processOrder(BufferedReader br) throws IOException {
    System.out.println("\n아래와 같이 주문 하시겠습니까?\n");
    order.printOrderList(); // 장바구니 List 출력
    order.printTotalPrice(); // 총 금액 출력
    System.out.println("\n1. 주문 2. 메뉴판\n");
    int no = inputHandler.getUserInput(br, 2, false);
    if (no == 1) { // 주문 진행
    order.order();
    }
    }

     

    
      
    // 메뉴 목록 출력 함수
    public void printOrderList() {
    System.out.println("[ Orders ]");
    for (MenuItem order : orderList) {
    System.out.println(order);
    }
    }
    // 총 금액 출력 함수
    public void printTotalPrice() {
    System.out.println("\n[ Total ]");
    System.out.printf("W %.1f\n", this.getTotalPrice());
    }
    public Double getTotalPrice() {
    return orderList.stream().mapToDouble(MenuItem::getPrice).sum();
    }

     

    3️⃣ 최종 코드

    1. Main

    
      
    import java.util.ArrayList;
    import java.util.List;
    public class Main {
    public static void main(String[] args) {
    List<Menu> menuList = new ArrayList<>();
    // Burgers
    menuList.add(new Menu("Burgers", List.of(
    new MenuItem("ShackBurger", 6.9, "토마토, 양상추, 쉑소스가 토핑된 치즈버거"),
    new MenuItem("SmokeShack", 8.9, "베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거"),
    new MenuItem("Cheeseburger", 6.9, "포테이토 번과 비프패티, 치즈가 토핑된 치즈버거"),
    new MenuItem("Hamburger", 5.4, "비프패티를 기반으로 야채가 들어간 기본버거")
    )));
    // Drinks
    menuList.add(new Menu("Drinks", List.of(
    new MenuItem("Coke", 2.5, "탄산이 가득한 코카콜라"),
    new MenuItem("Cider", 2.5, "청량미 넘치는 사이다"),
    new MenuItem("Lemon juice", 3.0, "생과일 레몬이 들어간 레몬 쥬스"),
    new MenuItem("PowerAde", 3.0, "수분을 보충시켜 줄 파워에이드")
    )));
    // Desserts
    menuList.add(new Menu("Desserts", List.of(
    new MenuItem("Cheese Cake", 5.0, "꾸덕한 치즈가 들어간 치즈 케이크"),
    new MenuItem("Chocolate cake", 5.5, "초코가 흘러내리는 달콤한 초콜릿 케이크"),
    new MenuItem("IceCream", 3.0, "시원한 아이스크림"),
    new MenuItem("Cookie", 2.0, "갓 구운 바삭한 쿠키")
    )));
    new Kiosk(menuList).start();
    }
    }

     

    2. Menu

    
      
    import java.util.List;
    public class Menu {
    private final String category; // 카테고리
    private final List<MenuItem> menuItems; // menu Item 목록
    public Menu(String category, List<MenuItem> menuItems) {
    this.category = category;
    this.menuItems = menuItems;
    }
    public String getCategory() {
    return category;
    }
    public int getMenuItemsSize() {
    return menuItems.size();
    }
    // MenuItem 목록 출력
    public void printMenuItemList() {
    for (int i = 0; i < menuItems.size(); i++) {
    System.out.println((i + 1) + ". " + menuItems.get(i));
    }
    System.out.println("0. 뒤로가기\n");
    }
    // menuItem detail 출력
    public void printMenuItemDetails(int index) {
    MenuItem item = this.getMenuItemByIndex(index);
    System.out.printf("선택한 메뉴 : %s | 가격 : W %.1f | 설명 : %s\n",
    item.getMenuNm(), item.getPrice(), item.getDesc());
    }
    public MenuItem getMenuItemByIndex(int index) {
    return menuItems.get(index);
    }
    }

     

    3. MenuItem

    
      
    public class MenuItem {
    private final String menuNm; // 메뉴명
    private final double price; // 가격
    private final String desc; // 설명
    public MenuItem(String menuNm, double price, String desc) {
    this.menuNm = menuNm;
    this.price = price;
    this.desc = desc;
    }
    public String getMenuNm() {
    return menuNm;
    }
    public double getPrice() {
    return price;
    }
    public String getDesc() {
    return desc;
    }
    @Override
    public String toString() {
    return String.format("%-13s | W %-4.1f | %s", menuNm, price, desc);
    }
    }

     

    4. Order

    
      
    import java.util.ArrayList;
    import java.util.List;
    public class Order {
    private final List<MenuItem> orderList;
    public Order() {
    this.orderList = new ArrayList<>();
    }
    // 장바구니 추가
    public void addOrder(MenuItem order) {
    this.orderList.add(order);
    }
    // 장바구니 비우기
    public void clearOrder() {
    this.orderList.clear();
    }
    // 장바구니 empty 여부
    public boolean isEmptyOrder() {
    return this.orderList.isEmpty();
    }
    // 메뉴 목록 출력 함수
    public void printOrderList() {
    System.out.println("[ Orders ]");
    for (MenuItem order : orderList) {
    System.out.println(order);
    }
    }
    // 총 금액 출력 함수
    public void printTotalPrice() {
    System.out.println("\n[ Total ]");
    System.out.printf("W %.1f\n", this.getTotalPrice());
    }
    // 총 금액 sum 함수
    public Double getTotalPrice() {
    return orderList.stream().mapToDouble(MenuItem::getPrice).sum();
    }
    public void order() {
    System.out.printf("\n주문이 완료되었습니다. 금액은 W %.1f 입니다.\n", this.getTotalPrice());
    this.clearOrder(); // 장바구니 초기화
    }
    }

     

    5. InputHandler

    
      
    import java.io.BufferedReader;
    import java.io.IOException;
    public class InputHandler {
    public int getUserInput(BufferedReader br, int maxOption, boolean useZero) throws IOException {
    while (true) {
    System.out.print("번호를 선택해주세요 : ");
    String input = br.readLine();
    if (isValidInput(input, maxOption, useZero)) {
    return Integer.parseInt(input);
    }
    System.out.println("\n! 올바른 번호를 입력해주세요 !\n");
    }
    }
    // valid input
    private boolean isValidInput(String input, int maxOption, boolean useZero) {
    try {
    int number = Integer.parseInt(input);
    return useZero ? (number >= 0 && number <= maxOption) : (number > 0 && number <= maxOption);
    } catch (NumberFormatException e) {
    return false;
    }
    }
    }

     

    6. Kiosk

    
      
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    public class Kiosk {
    private final List<Menu> menuList; // 메뉴 목록
    private final InputHandler inputHandler; // inputHandler
    private final Order order; // 장바구니
    public Kiosk(List<Menu> menuList) {
    this.menuList = menuList;
    this.inputHandler = new InputHandler();
    this.order = new Order();
    }
    public void start() {
    int menuListSize = menuList.size();
    try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
    while (true) {
    this.printMainMenu(); // MAIN MENU 목록 출력 함수 실행
    int menuNo;
    if (order.isEmptyOrder()) { // 장바구니가 비어있을 경우
    System.out.println(String.format("%-12s | 종료\n", "0. 종료"));
    menuNo = inputHandler.getUserInput(br, menuListSize, true); // inputHandler 실행
    } else { // 장바구니에 물건이 있을 경우
    this.printOrderMenu(); // ORDER MENU 출력
    System.out.println(String.format("%-12s | 종료\n", "0. 종료"));
    menuNo = inputHandler.getUserInput(br, menuListSize + 2, true); // inputHandler 실행
    }
    if (menuNo == 0) { // 0 이면 프로그램 종료
    break;
    }
    if (!order.isEmptyOrder() && menuNo > menuListSize) { // ORDER MENU 선택시
    if (menuNo == menuListSize + 1) { // Orders 버튼
    this.processOrder(br); // 주문 프로세스 실행
    } else { // Cancel 버튼
    order.clearOrder(); // 장바구니 초기화
    System.out.println("\n! 주문이 취소되었습니다 ! ");
    }
    } else { // MAIN MENU 선택 시 1
    this.processMenuSelection(br, menuList.get(menuNo - 1)); // 선택한 Menu 진행
    }
    }
    } catch (IOException e) {
    System.out.println("\n! 에러가 발생했습니다 !\n");
    }
    System.out.println("\n프로그램을 종료합니다.");
    }
    // MAIN MENU 목록 출력 함수
    private void printMainMenu() {
    System.out.println("\n[ MAIN MENU ]");
    int i = 1;
    for (Menu menu : menuList) {
    System.out.println(i++ + ". " + menu.getCategory());
    }
    }
    // ORDER MENU 목록 출력 함수
    private void printOrderMenu() {
    System.out.println("\n[ ORDER MENU ]");
    int i = menuList.size() + 1;
    System.out.println(String.format("%-13s | 장바구니를 확인 후 주문합니다.", i++ + ". Orders"));
    System.out.println(String.format("%-13s | 진행중인 주문을 취소합니다.", i + ". Cancel"));
    }
    // 주문 process
    private void processOrder(BufferedReader br) throws IOException {
    System.out.println("\n아래와 같이 주문 하시겠습니까?\n");
    order.printOrderList(); // 장바구니 List 출력
    order.printTotalPrice(); // 총 금액 출력
    System.out.println("\n1. 주문 2. 메뉴판\n");
    int no = inputHandler.getUserInput(br, 2, false);
    if (no == 1) { // 주문 진행
    order.order();
    }
    }
    // 메뉴 선택 후 process
    private void processMenuSelection(BufferedReader br, Menu menu) throws IOException {
    while (true) {
    System.out.printf("\n[ %s MENU ]\n", menu.getCategory().toUpperCase()); // 선택한 메뉴 출력
    menu.printMenuItemList(); // 선택한 메뉴의 menuItem List 출력
    int itemNo = inputHandler.getUserInput(br, menu.getMenuItemsSize(), true); // 입력받기
    if (itemNo != 0) { // 메뉴 선택시
    menu.printMenuItemDetails(itemNo - 1); // menuItem Detail 출력
    MenuItem menuItem = menu.getMenuItemByIndex(itemNo - 1); // menuItem 가져 옴
    System.out.println("\n위 메뉴를 장바구니에 추가하시겠습니까?");
    System.out.println("1. 확인 2. 취소\n");
    int orderNo = inputHandler.getUserInput(br, 2, false); // 입력받기
    if (orderNo == 1) { // 장바구니 추가
    System.out.println(menuItem.getMenuNm() + " 이 장바구니에 추가되었습니다.");
    order.addOrder(menuItem);
    break;
    }
    System.out.println("취소 되었습니다.");
    } else { // 돌아가기 선택 시
    break;
    }
    }
    }
    }
Designed by Tistory.