[내배캠/16일차] TIL - 의존관계, Lv.4 ~ Lv.5 키오스크

euphony·2025년 1월 15일
0

내일배움캠프

목록 보기
31/66

✅오늘의 한 일

  • 키오스크 과제 Lv.5까지 완료
  • 트러블 슈팅 작성
  • 자바 중급2편 섹션4 ~ 섹션5 정리
  • 자바 중급2편 섹션6 듣기(진행중)

💻오늘의 학습

Lv.5 키오스크 진행

새로운 요구사항

LV.4 ~ LV.5 키오스크의 요구사항은 다음과 같다.

  • Menu 클래스 생성하기
    • List<MenuItem>Menu 클래스가 관리하도록 변경하기
    • 카테고리 이름 필드와 카테고리 이름을 반환하는 메서드를 구현하기
  • MenuItem, Menu 그리고 Kiosk 클래스의 필드에 직접 접근하지 못하도록 설정하기
  • GetterSetter 메서드를 사용해 데이터를 관리하기
  • 각 카테고리 메뉴에서 0을 누르면 메인 메뉴로 돌아가기

먼저 다음과 같이 categorymenuItems를 필드로 갖는 Menu 클래스를 구현했다. category를 넣어 생성하고, getMenuItems() 메서드로 menuItems을 가져와 MenuItem 클래스를 리스트에 추가할 수 있도록 했다. 또한 카테고리 이름을 반환하는 메서드인 getCategory()를 구현했다.

public class Menu {
    private final String category;
    private final List<MenuItem> menuItems = new ArrayList<>();

    public Menu(String category) {
        this.category = category;
    }

    public String getCategory() {
        return category;
    }

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

Main 클래스에 있는 initializeMenu()에서 다음과 같이 각각의 메뉴 카테고리마다 getMenuItems() 메서드를 이용해 새로운 MenuItem을 계속 추가할 수 있다.

    private static void initializeMenu() {
        Menu burgerMenu = new Menu("Burgers");
        burgerMenu.getMenuItems().add(new MenuItem("ShackBurger", 6.9, "토마토, 양상추, 쉑소스가 토핑된 치즈버거"));
        burgerMenu.getMenuItems().add(new MenuItem("SmokeShack", 8.9, "베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거"));
        burgerMenu.getMenuItems().add(new MenuItem("Cheeseburger", 6.9, "포테이토 번과 비프패티, 치즈가 토핑된 치즈버거"));
        burgerMenu.getMenuItems().add(new MenuItem("Hamburger", 5.4, "비프패티를 기반으로 야채가 들어간 기본버거"));

        menus.add(burgerMenu);
    }

그리고 Kiosk 클래스도 꽤 많이 고쳤다. start() 메서드가 너무 긴 것 같아서 조금 찜찜하다.. 메인 메뉴 번호와 상세 메뉴 아이템 번호까지 받는 부분을 처리해서 코드가 길어졌다. 주석을 꼼꼼하게 달아놓았기 때문에 알아보는데는 큰 문제가 없겠지만, 좀 더 고민해봐야겠다.

    public void start() {
        try (Scanner sc = new Scanner(System.in)) {
            while (true) {
                // 메뉴 출력
                showMenu();
                System.out.print("메인 메뉴를 선택하세요: ");

                if (!sc.hasNextInt()) {
                    System.out.println("숫자를 입력해주세요.");
                    sc.next();
                    continue;
                }

                // 메뉴 입력 받기
                int selectedMenu = sc.nextInt();
                if (selectedMenu == 0) {
                    System.out.println("프로그램을 종료합니다.");
                    break;
                }

                if (isValidMenu(selectedMenu)) {
                    // 메뉴 아이템 출력
                    showMenuItems(selectedMenu);
                    // 메뉴 아이템 입력 받기
                    System.out.print("메뉴를 선택하세요: ");
                    int selectedMenuItem = sc.nextInt();
                    // 0 입력 시 뒤로가기(메인 메뉴)
                    if (selectedMenuItem == 0) continue;
                    // 선택한 메뉴 아이템 출력
                    if (isValidMenuItem(selectedMenu, selectedMenuItem)) {
                        displaySelectedMenuItems(selectedMenu, selectedMenuItem);
                    } else {
                        System.out.println("올바른 메뉴 아이템 번호를 입력해주세요.");
                    }
                } else { // 메뉴에 없는 값을 입력할 경우
                    System.out.println("올바른 메뉴 번호를 입력해주세요.");
                }
                System.out.println();
            }
        }
    }

트러블 슈팅

메뉴 선택 시 IndexOutOfBoundsException이 발생했다. 그나마 고치기 쉬운 에러라 다행이다.🙄

menus.get(input) 을 할 때 input을 그대로 넣은 것이 문제였다. 인덱스는 0부터 시작인데 길이가 3개인 리스트에서 3번째 데이터를 가져오려고 하면 오류가 나는 것은 당연하다. menus.get(input - 1)로 수정해주었다.

private void showMenuItems(int input) {
    System.out.printf("[ %s MENU ]", menus.get(input).getCategory()); // 에러 발생
    System.out.println();
    int size = menus.get(input).getMenuItems().size(); // 에러 발생
    for (int i = 0; i < size; i++) {
        MenuItem menuItem = menus.get(input).getMenuItems().get(i); // 에러 발생
        System.out.printf("%d. %s   | W %.1f | %s%n", i + 1,
                menuItem.getName(), menuItem.getPrice(), menuItem.getDescription());
    }
    System.out.println("0. 뒤로가기");
}

자바 중급2편 강의

"의존한다" 라는 것은 뭘까? 다음과 같이 MyList를 구현하는 MyArrayList와 MyArrayList를 만들었다.

public interface MyList<E> {
    int size();
    void add(E e);
    void add(int index, E e);
    E get(int index);
    E set(int index, E element);
    E remove(int index);
    int indexOf(E o);
}
public class MyArrayList<E> implements MyList<E> {
 //...
}
public class MyLinkedList<E> implements MyList<E> {
 //...
}

MyArrayList 를 활용해서 많은 데이터를 처리하는 BatchProcessor 클래스를 개발하고 있다고 할 때, 데이터를 앞에서 추가하는 일이 많은 상황이 올 수 있다. 그러면 그때마다 MyLinkedList 를 사용하도록 코드를 변경해야 한다. 이런 상황을 BatchProcessor가 구체적인 클래스에 의존한다고 표현한다.

public class BatchProcessor {

    private final MyArrayList<Integer> list = new MyArrayList<>();

    public BatchProcessor(MyList<Integer> list) {
        this.list = list;
    }

    public void logic(int size) {
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            list.add(0, i); // 앞에 추가
        }
        long endTime = System.currentTimeMillis();
        System.out.println("크기: " + size + 
        ", 계산 시간: " + (endTime - startTime) + "ms");
    }

}

구체적인 클래스에 의존하는 대신, 추상적인 MyList 인터페이스에 의존할 수 있다. 이렇게 하면 BatchProcessor를 생성하는 시점에 리스트 전략을 선택해 전달하면 되고, 클라이언트 코드인 BatchProcessor의 변경 없이도 MyArrayList에서 MyLinkedList로 변경하는 것이 가능하다. 바로 이것을 의존 관계 주입(Dependency Injection, DI)이라고 한다.

public class BatchProcessor {

    private final MyList<Integer> list = new MyList<>();

    public BatchProcessor(MyList<Integer> list) {
        this.list = list;
    }

    public void logic(int size) {
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            list.add(0, i); // 앞에 추가
        }
        long endTime = System.currentTimeMillis();
        System.out.println("크기: " + size + 
        ", 계산 시간: " + (endTime - startTime) + "ms");
    }

}

📝오늘의 회고

오늘은 계획한 일을 거의 끝냈지만, 뭔가 완전히 집중하진 못했던 것 같다.

📌내일의 할 일

  • Lv.5 키오스크 리팩토링
  • Lv.6 키오스크 시작
  • 트러블 슈팅 및 몰랐던 내용 정리
  • 자바 중급2편 섹션6 ~ 7 듣기

0개의 댓글

관련 채용 정보