키오스크_LV6_end

지혜·2025년 1월 17일

키오스크_LV6_end

💡 https://github.com/cjh0412/Kiosk

📝 추가 구현부분

추가할 부분
1. order에 수량 변경 구현
2. 할인 기능 추가
3. 코드 정리

1. Order.java 수량 변경 구현

초반 코드
선택된 메뉴를 그대로 주문 리스트에 추가


// 서브 메뉴 정보 리스트 저장
public void addOrderList(MenuItem subMenu){
        menuItemList.add(subMenu);
        printMenuName();
    }
    
 // 장바구니 확인하기
    public void printOrderList(){
        getOrderList().stream()
                .forEach(order -> System.out.println(order.toString()));    

🤔 코드의 문제점
1. 동일한 메뉴를 추가할 경우 리스트에 값이 중복된다.
2. 수량을 추가한 후, 동일 메뉴 추가 삭제등이 용이하지 못하다.

개선 코드

Order.java
// 수량 추가를 위해 Map 추가
    // key : MenuItem, value = 수량
    Map<MenuItem, Integer> menuItemMap = new HashMap<>();

    public Map<MenuItem, Integer> getMenuItemMap() {
        return menuItemMap;
    }

    // 서브 메뉴 정보 저장
    public void addOrderList(MenuItem menuItem, int quantity) {
        // 저장된 menuItem이 없다면 새로 추가, 존재할 경우 +1
        menuItemMap.put(menuItem, menuItemMap.getOrDefault(menuItem, 0) + quantity);
        printMenuName(menuItem);
    }

   // 주문완료
   public void completeOrder() {
       menuItemMap.clear();
   }

   // 주문취소
   public void cancelOrder() {
       // 키값 찾기
       MenuItem item = menuItemMap.keySet().stream().reduce((a, b) -> b).orElse(null);
       System.out.println("가장 마지막에 추가하신 메뉴 " + item + "가 삭제되었습니다.");
       menuItemMap.remove(item);
    }

Kiosk.java
 // 주문추가여부
    public void addOrderYn(List<MenuItem> subCategory, int choiceMenu) {
        System.out.println("\n" + subCategory.get(choiceMenu - 1).toString());
        System.out.println("위 메뉴를 장바구니에 추가하시겠습니까?");
        System.out.println("1. 확인      2. 취소");
        int orderYn = choiceUser();
        if (orderYn == 1) {
            order.addOrderList(subCategory.get(choiceMenu - 1), 1);
        }
    }    

💡 해결내용
1. list-> map으로 변경하여 동일 메뉴 여부 체크 후 수량만 변경
2. 주문 완료 이후 장바구니 비우기
3. 주문 취소시 가장 마지막에 저장된 메뉴 삭제

🤔 Map으로 변경한 이유는?
list: 중복 여부를 체크하는 로직 추가가 필요하다는 단점 존재
map : key : menuItem, value:수량을 관리하여 동일한 메뉴(key)인 경우 수량을 변경하여 중복 관리가 단순해지는 장점 존재

기억할것

  1. getOrDefault(key, Defaultvalue) : key가 존재할 경우 value값을 반환하며 존재하지 않을 경우 Defaultvalue 반환
  2. remove(key) : key에 해당하는 값 제거
  3. clear : map 전체 내용 초기화

2. 할인 기능 추가

Kiosk.java
  // 장바구니
    private void orderProcess() {
        System.out.println("아래와 같이 주문하시겠습니까?");
        order.printTotalOrder();

        System.out.println("[ Total ]");
        double sumPrice = order.totalOrderPrice();
        System.out.println("W " + sumPrice);

        System.out.println("1. 주문      2. 메뉴판");
        int choiceOrder = choiceUser();
        if (choiceOrder == 1) {
            order.printDiscountInfo();

		  // 할인 적용하여 값 계산하기
            int discount = choiceUser();
            System.out.println("주문이 완료되었습니다. 금액은 W "
                    + sumPrice * (1 - (DiscountType.chkDiscount(discount))) + " 입니다." + "\n");
          
          // 주문완료시 장바구니 비우기
            order.completeOrder();
        }
        
DiscountType.java
      public enum DiscountType {
          NATIONAL_MERIT("국가유공자", 0.1),
          ARMY("군인", 0.05),
          STUDENT("학생", 0.03),
          ORDINARY("일반", 0);

          private final String type;
          private final double discount;

          DiscountType(String type, double discount) {
              this.type = type;
              this.discount = discount;
          }

          public String getType() {
              return type;
          }

          public double getDiscount() {
              return discount;
          }

          @Override
          public String toString() {
              return type + ": " + (int) (discount * 100) + "%";
          }

          // 할인율 체크
          public static double chkDiscount(int index) {
              return DiscountType.values()[index - 1].getDiscount();
          }
      }
      

💡 해결내용
1. enum을 이용하여 할인 정보 나열
2. 할인 값은 discount * 100을 하여 5% 와 같이 출력하기

3. 코드 정리

초반 코드

    public void start() {
        // 스캐너 선언
        Scanner scanner = new Scanner(System.in);

        // 반복문 시작
        while (true){
            try {
                // List와 Menu 클래스 활용하여 상위 카테고리 메뉴 출력
                System.out.println("[MAIN MENU]");
                menu.printMainMenu();
                System.out.println("0. 종료   |종료");

                // 장바구니 값이 존재할 경우 : 확인, 취소까지 +2,  존재x : mainCategory의 크기값 체크
                int index = (order.getOrderList().isEmpty()) ? mainCategory.size()-1 :mainCategory.size()+2;

                if(!order.getOrderList().isEmpty()){
                    System.out.println("[ ORDER MENU ]");
                    System.out.println(index-1 +   ". Orders  | 장바구니를 확인 후 주문합니다.");
                    System.out.println(index + ". Cancel  | 장바구니 주문을 취소합니다.");
                }

                // 숫자 입력 받기
                int choiceCategory = Integer.parseInt(scanner.nextLine());

                // 장바구니 확인 하기
                if(index-1 == choiceCategory && !order.getOrderList().isEmpty()){
                    System.out.println("아래와 같이 주문하시겠습니까?");
                    order.printOrderList();

                    System.out.println("[ Total ]");
                    double sumPrice = order.totalOrderPrice();
                    System.out.println("W " + sumPrice);

                    System.out.println("1. 주문      2. 메뉴판");
                    int choiceOrder = Integer.parseInt(scanner.nextLine());
                    if(choiceOrder == 1){
                        System.out.println("주문이 완료되었습니다. 금액은 W " +sumPrice + " 입니다.");
                        break;
                    }
                    continue;
                }

                if(choiceCategory == 0){
                    System.out.println("프로그램을 종료합니다.");
                    break;
                }

                //리스트 index값보다 크거나 choiceMenu가 음수인 경우
                if (choiceCategory < 0 || choiceCategory > index) {
                    throw new RuntimeException("유효하지 않은 번호를 입력하셨습니다.");
                }

                // 입력 받은 숫자가 올바르다면 인덱스로 활용하여 List에 접근하기
                // List<Menu>에 인덱스로 접근하면 Menu만 추출할 수 있겠죠?
                // Menu가 가진 List<MenuItem>을 반복문을 활용하여 햄버거 메뉴 출력
                List<MenuItem> subCategory = mainCategory.get(choiceCategory - 1).getMenuItemList();
                menu.printSubMenu(choiceCategory);
                System.out.println("0. 뒤로가기");

                // 숫자 입력 받기
                int choiceMenu = Integer.parseInt(scanner.nextLine());
                if(choiceMenu == 0){
                    continue;
                }

                //리스트 index값보다 크거나 choiceItem이 음수인 경우
                // 상위 카테고리로 돌려보내기
                if (choiceMenu < 0 || choiceMenu > subCategory.size() - 1) {
                    System.out.println("아래 메뉴판을 보시고 메뉴를 골라 입력해주세요..");
                    continue;
                }

                // 입력 받은 숫자가 올바르다면 인덱스로 활용해서 Menu가 가지고 있는 List<MenuItem>에 접근하기
                // menu.getMenuItems().get(i); 같은 형식으로 하나씩 들어가서 얻어와야 합니다.
                // 선택한 메뉴 : 이름, 가격, 설명
                System.out.println("선택한 메뉴 : " + subCategory.get(choiceMenu - 1).toString());
                System.out.println("위 메뉴를 장바구니에 추가하시겠습니까?");
                System.out.println("1. 확인      2. 취소");
                int orderYn = Integer.parseInt(scanner.nextLine());
                if(orderYn == 1) {
                    order.addOrderList(subCategory.get(choiceMenu - 1));
                }
            }
            catch (NumberFormatException e) {
                System.out.println("입력된 값이 숫자가 아닙니다.");
                break;
            }
        }

🤔 코드의 문제점
1. 문제없이 동작하지만 개인적으로 코드가 너무 길고 반복되는 부분이 존재하여 수정하기로 함

1차 시도
처음 계획은 order에 포함되는 내용은 order로 옮기고 Menu에 포함되는 내용은 Menu로 옮기고자 했다.

예시

Menu.java
private void printMainMenu() {
        System.out.println("[MAIN MENU]");
        menu.printMainMenu();
        System.out.println("0. 종료 | 종료");

        if (!order.getMenuItemMap().isEmpty()) {
            System.out.println("[ORDER MENU]");
            System.out.println(menu.getMainCategories().size() + 1 + ". Orders | 장바구니 확인 및 주문");
            System.out.println(menu.getMainCategories().size() + 2 + ". Cancel | 장바구니 주문 취소");
        }
    }

🤔 문제 발생
위에 코드 처럼 작성할 경우 장바구니 정보 getMenuItemMap의 정보를 가져오기 위해 Order의 상태까지 Menu에서 관리해야하는 문제가 발생했다.
결국 고민하다가 kiosk에서 관리를 하기로 결정하고 단순한 데이터 출력 등의 기본적인 것만 menu, order에서 관리하기로 결정했다.

개선 코드

  1. 메인메뉴 출력 소스
    // 메인 메뉴 출력
    private void printMainCategory() {
        System.out.println("[MAIN MENU]");
        menu.printMainMenu();
        System.out.println("0. 종료   |종료");
        // 장바구니 값이 있을 경우
        order.isEmptyOrderMap(mainCategory.size());
    }
  1. 하위 메뉴 출력 및 선택
    // 하위 메뉴 선택
    private void choiceSubCategory(int choiceUser) {
        List<MenuItem> subCategory = mainCategory.get(choiceUser - 1).getMenuItemList();

        // 서브메뉴 출력
        menu.printSubMenu(choiceUser);

        // 숫자 입력 받기
        int choiceMenu = choiceUser();

        // 0. 뒤로가기 : 상위메뉴로 돌려보내기
        if (choiceMenu == 0) {
            return;
        }

        //리스트 index값보다 크거나 choiceItem이 음수인 경우
        // 상위 카테고리로 돌려보내기
        if (choiceMenu < 0 || choiceMenu > subCategory.size()) {
            System.out.println("아래 메뉴판을 보시고 메뉴를 골라 입력해주세요..");
            return;
        }

        // 선택한 메뉴 : 이름, 가격, 설명
        System.out.println("선택한 메뉴 : " + subCategory.get(choiceMenu - 1).toString());
        // 주문 추가 여부
        addOrderYn(subCategory, choiceMenu);
    }
  1. 장바구니
// 장바구니
    private void orderProcess() {
        System.out.println("아래와 같이 주문하시겠습니까?");
        order.printTotalOrder();

        System.out.println("[ Total ]");
        double sumPrice = order.totalOrderPrice();
        System.out.println("W " + sumPrice);

        System.out.println("1. 주문      2. 메뉴판");
        int choiceOrder = choiceUser();
        if (choiceOrder == 1) {
            order.printDiscountInfo();

            int discount = choiceUser();
            System.out.println("주문이 완료되었습니다. 금액은 W "
                    + sumPrice * (1 - (DiscountType.chkDiscount(discount))) + " 입니다." + "\n");
            // 주문완료시 장바구니 비우기
            order.completeOrder();
        }
    }
  1. 주문추가
    // 주문추가여부
    public void addOrderYn(List<MenuItem> subCategory, int choiceMenu) {
        System.out.println("\n" + subCategory.get(choiceMenu - 1).toString());
        System.out.println("위 메뉴를 장바구니에 추가하시겠습니까?");
        System.out.println("1. 확인      2. 취소");
        int orderYn = choiceUser();
        if (orderYn == 1) {
            order.addOrderList(subCategory.get(choiceMenu - 1), 1);
        }
    }

그밖의 수정사항

1.메뉴 정렬

수정 전
[ BURGERS MENU ]
1. ShackBurger |W 6.9 |토마토, 양상추, 쉑소스가 토핑된 치즈버거
2. SmokeShack |W 8.9 |베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거
3. Cheeseburger |W 6.9 |포테이토 번과 비프패티, 치즈가 토핑된 치즈버거
4. Hamburger |W 5.9 |비프패티를 기반으로 야채가 들어간 기본버거

메뉴 출력 값이 정렬되지 않은 상태로 나타나는 부분이 개인적으로 마음에 들지 않았다.
해당 부분을 수정하기 위해 string.format을 이용하여 정렬을 진행했다.

수정 코드

MenuItem.java
    @Override
    public String toString() {
        // 고정 폭 설정
        int width = 15;

        return String.format("%-" + width + "s| %-" + width + "s| %-" + width + "s'",
                name, price, text);
    }

0개의 댓글