본문 바로가기

JAVA

키오스크 만들기 : 음식 메뉴와 카테고리를 클래스로 관리하기

고민했던 점

1. Kiosk의 start()메서드의 복잡함

  • Kiosk에서 사용자의 입력에 따라서 출력을 보여주는 start()메서드의 로직이 너무 길고 복잡해보여서 개발을 진행하면서도 너무 복잡하고 알아보기가 쉽지 않았음
  • 카테고리를 출력하는 부분과, 메뉴를 출력하는 부분을 각각 showCategories(), showMainMenes(Menu menu) 메서드로 분리하여 해결
private void showCategories() {
        System.out.println("[ MAIN MENU ]");
        for (int i = 0; i < menus.size(); i++) {
            System.out.println(i + 1 + ". " + this.menus.get(i).getCategory());
            this.indexList.add(i);
        }
        System.out.println("0. 종료 | 종료");
    }

 

 

2. 사용자로부터 적절한 값을 검증하는 부분에 대한 고민

  • 화면에 출력되는 부분에서 보여지는 숫자값만을 입력해서 검증하는 부분에서 이를 어떤 식으로 할 지 고민을 많이 했음
  • 화면에서 리스트 값들을 출력할 때 인덱스 리스트를 만들어, 이 리스트에 값들을 함께 추가한 다음에 사용자가 이 리스트에 해당되는 값만 입력했는지를 검증하는 방법으로 구현
private void showCategories() {
        System.out.println("[ MAIN MENU ]");
        for (int i = 0; i < menus.size(); i++) {
            System.out.println(i + 1 + ". " + this.menus.get(i).getCategory());
            this.indexList.add(i);
        }
        System.out.println("0. 종료 | 종료");
    }

 

검증

private void validInputRangeValue(int inputIndex, List<Integer> validIndexList) throws InvalidInputRangeException {
        if (!validIndexList.contains(inputIndex)){
            throw new InvalidInputRangeException();
        }
    }

 

3. 검증메서드를 실행할 때, 유효한 인덱스 리스트의 조회 방법에 대한 고민

  • 동일한 클래스 내부에 있는 indexList 필드이기 때문에 그냥 this.indexList로 검증메서드 매개변수에 전달해야할지 아니면 getter를 만들어서 getter를 통하여 전달해야 할지 고민이 됐음 
  • 검색을 해본 결과 지금 같은 경우는 상관없지만 JPA 프록시를 다루게 되면 중요해진다고 한다. (김영한 선생님의 답변..)
    • 나중에 JPA를 다뤄볼 때 기억할 것!

 

MenuItem

  • 카테고리 내부에 있는 해당 음식들을 관리하는 클래스
  • 음식 이름(name), 음식 가격(price), 음식 설명(description) 필드를 가지고 있음
  • 무결성을 지키기 위해 각각의 필드는 private 으로 설정하고 getter, setter을 이용 (캡슐화)
public class MenuItem {
    
    private String name;
    private double price;
    private String description;

    MenuItem (String name, double price, String description) {
        this.name = name;
        this.price = price;
        this.description = description;
    }

    // 각각의 필드에 대한 getter, setter
}

 

Menu

  • 카테고리별로 메뉴를 관리하는 클래스, 해당 카테고리에 해당하는 메뉴 리스트를 가지고 있음
  • 음식리스트(menuItems), 해당 음식의 카테고리(category), 음식리스트의 인덱스리스트(menuItemIndexList)
  • menuItemIndexList를 만든 이유
    • 사용자의 입력번호에 따라서 해당 로직(선택한 음식 출력)을 수행해야 하는데, 유요한 값을 검증하는 부분에서 해당 리스트에 벗어나는 값을 입력하는 경우 InvalidInputRangeException 을 수행하도록 함
    • 음식리스트(menuItems)를 출력할 때 menuItemIndexList에 값을 추가함
public class Menu {
    private final String category;
    private final List<MenuItem> menuItems;
    private final List<Integer> menuItemIndexList = new ArrayList<>();

    public Menu(String category, List<MenuItem> menuItems) {
        this.category = category;
        this.menuItems = menuItems;
    }

    public void showMenuItems(){
        for(int i = 0; i < menuItems.size(); i++){
            System.out.println( i + 1 + ". " + menuItems.get(i).getName() + " | W " + menuItems.get(i).getPrice() + " | " + menuItems.get(i).getDescription());
            menuItemIndexList.add(i+1);
        }
    }

    public List<MenuItem> getMenuItems(){
        return this.menuItems;
    }

    public String getCategory(){
        return this.category;
    }

    public List<Integer> getMenuItemIndexList() {
        return this.menuItemIndexList;
    }

}

 

Kiosk

  • 사용자에게 메뉴를 보여주고, 해당 입력값에 따라서 결과를 보여주는 역할을 수행하는 클래스
  • 카테고리별 메뉴 리스트(menus), 사용자에게 숫자를 입력받았는지를 검증하는 정규표현식 변수(NUMBER_REG), 카테고리 인덱스 리스트(indexList)
  • 카테고리 인덱스 리스트(indexList) 또한 menuItemIndexList를 만든 이유와 동일
  • 에러를 검증하는 메서드
    • validInputValue : 사용자가 숫자를 입력했는지 검증, 숫자 이외의 값을 입력했을 시에 InvalidInputException 객체 생성
    • validInputRangeValue : 사용자가 유효한 범위의 숫자를 입력했는지 검증, 유효하지 않은 범위의 숫자를 입력했을 시에 InvalidInputRangeException에러 객체 생성 
private void validInputValue(String inputIndex) throws InvalidInputException {
        if (!inputIndex.matches(NUMBER_REG)){
            throw new InvalidInputException();
        }
    }
    private void validInputRangeValue(int inputIndex, List<Integer> validIndexList) throws InvalidInputRangeException {
        if (!validIndexList.contains(inputIndex)){
            throw new InvalidInputRangeException();
        }
    }
public class Kiosk {

    private final List<Menu> menus;
    private final String NUMBER_REG = "[0-9]+";
    private final List<Integer> indexList = new ArrayList<>();

    public Kiosk(List<Menu> menus) {
        this.menus = menus;
    }

    public void start() {
        Scanner sc = new Scanner(System.in);

        while (true) {
            try {
                showCategories();

                String inputCategoryIndex = sc.next();
                if ("0".equals(inputCategoryIndex)) {
                    System.out.println("프로그램이 종료되었습니다.");
                    break;
                }

                validInputValue(inputCategoryIndex);
                int categoryIndex = Integer.parseInt(inputCategoryIndex) - 1;
                validInputRangeValue(categoryIndex, this.getIndexList());

                Menu menu = this.menus.get(categoryIndex);
                showMainMenes(menu);

                while (true){
                    String inputMenuIndex = sc.next();
                    if ("0".equals(inputMenuIndex)) {
                        System.out.println("메인 화면으로 돌아갑니다.");
                        break;
                    }

                    validInputValue(inputMenuIndex);
                    int menuIndex = Integer.parseInt(inputMenuIndex) - 1;
                    validInputRangeValue(menuIndex, menu.getMenuItemIndexList());

                    MenuItem menuItem = menu.getMenuItems().get(menuIndex);
                    System.out.println("선택한 메뉴 : " + menuItem.getName() + " | W " + menuItem.getPrice() + " | " + menuItem.getDescription());
                }

            } catch (InvalidInputException | InvalidInputRangeException e){
                System.out.println(e.getMessage());
            }
        }

    }

    public List<Integer> getIndexList() {
        return this.indexList;
    }

    private void showCategories() {
        System.out.println("[ MAIN MENU ]");
        for (int i = 0; i < menus.size(); i++) {
            System.out.println(i + 1 + ". " + this.menus.get(i).getCategory());
            this.indexList.add(i);
        }
        System.out.println("0. 종료 | 종료");
    }

    private void showMainMenes(Menu menu) {
        System.out.println("[ " + menu.getCategory()+ " MENU ]");
        menu.showMenuItems();
        System.out.println("0. 뒤로가기");
    }

}