Java/키오스크 구현

트러블 슈팅 - 키오스크 구현

JuNo_12 2025. 4. 28. 11:23

이번 개인 프로젝트는 아래의 목표를 스스로 세워 진행했습니다.

  • 기능 별로 최대한 클래스를 나누어 구현
  • 코드의 재사용성을 최대한 고려

1. 기능 별로 최대한 클래스를 나누고 나니 기능은 제대로 만들었지만, 코드 실행시 break나 코드 위치에 따라서 기능이 제대로 실행이 안되거나 순서가 꼬여버리는 상황이 많았습니다. 이를 해결하기 위해 10개가 넘는 클래스를 하나하나 찾아다니면서 결국 완성은 했지만, 아직 이 부분은 제가 미숙하다고 느껴서 다시 한 번 처음부터 만들어보면서 이 문제를 해결하기 위한 능력을 키우려고 합니다.

 

2. 코드의 재사용성을 최대한 고려하며 느낀 점은 처음에 리스트를 선언할 때가 가장 중요하다고 느꼈습니다. 리스트를 어떠한 형식으로 선언해주느냐에 따라 삭제나 추가 기능의 코드가 비약적으로 짧아지거나 길어지는 것을 보고 여러 종류의 데이터 관리 명렁어들을 알아놔야겠다고 생각했습니다. 


본격적으로 제가 코드를 구현하면서 가장 어려웠던 부분들(2종류)에 대해 정리해보는 시간을 가져보겠습니다.

 

1. Burger 클래스를 만들어서 List에 넣어 관리하는 방법

public class MenuItem {
    private final List<Burger> typeOfBurgurs = new ArrayList<>();

    {
        typeOfBurgurs.add(new Burger(1, "ShackBurger", 6.9, "토마토, 양상추, 쉑소스가 토핑된 치즈버거"));
        typeOfBurgurs.add(new Burger(2, "SmokeShack", 8.9, "베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거"));
        typeOfBurgurs.add(new Burger(3, "Cheeseburger", 6.9, "포테이토 번과 비프패티, 치즈가 토핑된 치즈버거"));
        typeOfBurgurs.add(new Burger(4, "Hamburger", 5.4, "비프패티를 기반으로 야채가 들어간 기본버거"));
    }
public class Burger {

    private final int burgerId;
    private final String menuName;
    private final double menuPrice;
    private final String menuDescription;


    public Burger(int burgerId, String menuName, double menuPrice, String menuDescription) {
        this.burgerId = burgerId;
        this.menuName = menuName;
        this.menuPrice = menuPrice;
        this.menuDescription = menuDescription;
    }

 

  • Burger라는 클래스를 만들어서 버거 하나의 정보를 하나의 객체로 표현했습니다.
  • 그 객체들을 List<Burger>라는 리스트에 담아 관리했습니다.
  • 리스트에는 단순한 데이터(문자열,숫자)가 아니라 클래스 자체를 넣을 수 있다는 것이 주목할 점입니다.
  • 필요한 정보를 꺼낼 때는 forEach문이나 get(index) 등을 사용해서 Burger 객체를 다루어주었습니다.

 

 클래스를 만들어 데이터를 객체 단위로 다루고, 이를 리스트로 관리하는 것이 처음이라 이러한 방법이 있다는 것을 모를 때까지는 HashMap을 사용하여 키 (버거이름) : 값 (가격, 설명) 구조로 사용했지만 (이는 나중에 주문 시에 버거 수량을 추가하거나 삭제하기에 있어서 코드 재사용성이 너무나도 떨어졌습니다.) 이 방법을 알고 나서 여러 기능들에 대한 코드 재사용성이 상승했습니다.


2. ShoppingCart와 BurgerMenu를 이용해 버거 이름 비교 및 수량 추가하는 기능

: 전체코드를 보고, 한 부분씩 떼어서 보겠습니다.

public class BurgerMenu {
    private final List<Burger> burgers = new ArrayList<>();{
        burgers.add(new Burger(1, "ShackBurger", 6.9, "토마토, 양상추, 쉑소스가 토핑된 치즈버거"));
        burgers.add(new Burger(2, "SmokeShack", 6.9, "베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거"));
        burgers.add(new Burger(3, "Cheeseburger", 6.9, "포테이토 번과 비프패티, 치즈가 토핑된 치즈버거"));
        burgers.add(new Burger(4, "Hamburger", 6.9, "비프패티를 기반으로 야채가 들어간 기본버거"));
    }

    public List<Burger> getBurgers() {
        return burgers;
    }

    public Optional<Burger> findBurgerByName(String burgerName){
        return burgers.stream()
                .filter(burger -> burger.getBurgerName().equals(burgerName))
                .findFirst();
    }
}

 

    public Optional<Burger> findBurgerByName(String burgerName){
        return burgers.stream()
                .filter(burger -> burger.getBurgerName().equals(burgerName))
                .findFirst();
    }

 

burgerName의 문자열을 받아서 버거 리스트 안에서 그 이름을 가진 버거를 찾아보고 있으면 Optional<Burger>로 감싸서 리턴하는 메소드입니다. 스트림 안에서 각 버거에 대해 이름이 파라미터랑 일치하는 것만 필터링해주고 그 필터된 버거들 중 첫번째 것 하나만 가져와서 그 결과는 Optional<Burger>로 리턴됩니다.

 


 

public class Burger {
    int burgerId;
    String burgerName;
    double burgerPrice;
    String burgerDescription;

    public Burger(int burgerId, String burgerName, double burgerPrice, String burgerDescription) {
        this.burgerId = burgerId;
        this.burgerName = burgerName;
        this.burgerPrice = burgerPrice;
        this.burgerDescription = burgerDescription;
    }

    public String getBurgerName() {
        return burgerName;
    }

    public double getBurgerPrice() {
        return burgerPrice;
    }
}

 

Burger 클래스를 활용하여 속성을 정의해주고 Burger 생성자에 데이터 형태를 정의해주었습니다.

그리고 게터로 버거 이름과 가격을 조회할 수 있도록 해주었습니다.


public class ShoppingCartList {

    private final HashMap<String,Integer> shoppingCart = new HashMap<>();

    BurgerMenu burgerMenu;

    public ShoppingCartList(BurgerMenu burgerMenu) {
        this.burgerMenu = burgerMenu;
    }

    public HashMap<String, Integer> getBurgerHashMap() {
        return shoppingCart;
    }

    public void addBurger(String burgerName) {
        shoppingCart.put(burgerName, shoppingCart.getOrDefault(burgerName, 0) + 1);
    }
}

 

장바구니에 추가할 목록들을 HashMap 타입으로 정의해주었습니다.

BurgerMenu 클래스의 객체를 가져와서 addBurger를 통해 버거 이름을 가지고 shoppingCart 리스트에 목록을 추가할 수 있도록 해주었습니다. 또한 게터로 장바구니 목록에 추가된 버거 이름과 가격을 조회할 수 있도록 해주었습니다.


while (true) {
            int inputForBurgerMenu = scanner.nextInt();

            if (inputForBurgerMenu > 0 && inputForBurgerMenu <= burgerMenu.getBurgers().size()) {
                Burger selectedBurger = burgerMenu.getBurgers().get(inputForBurgerMenu - 1);
                System.out.println(selectedBurger.burgerName + " | W " + selectedBurger.burgerPrice + " | " + selectedBurger.burgerDescription);
                System.out.println("위 메뉴를 장바구니에 추가하시겠습니까?");

                System.out.println("1. 확인       2. 취소");

                while (true) {
                    int inputForBurgerAddToCart = scanner.nextInt();

                    if (inputForBurgerAddToCart == 1) {
                        shoppingCartList.addBurger(selectedBurger.burgerName);
                        System.out.println(selectedBurger.burgerName+ " 이 장바구니에 추가되었습니다.");
                        return;
                    } else if (inputForBurgerAddToCart == 2) {
                        return;
                    } else {
                        System.out.println("올바른 번호를 입력해주세요.");
                    }
                }

            } else if (inputForBurgerMenu == 0){
                return;
            } else {
                System.out.println("올바른 번호를 입력해주세요.");
            }
        }

 

 

Burger selectedBurger = burgerMenu.getBurgers().get(inputForBurgerMenu - 1);

: BurgerMenu 클래스에 있는 게터 메소드로 리스트에 접근한 다음에 (inputForBurgerMenu - 1)번째 있는 인덱스를 selectedBurger로 지정해주었습니다.

 

shoppingCartList.addBurger(selectedBurger.burgerName);

: ShoppingCartList 에 있는 addBurger() 메소드를 통해 장바구니 리스트에 선택된 인덱스의 burgerName을 추가해주었습니다.


    public void order(){
        System.out.println("아래와 같이 주문하시겠습니까?");
        System.out.println(" [ ORDER ]");

        final double[] totalPrice = {0.0};

        for (String burgerName : shoppingCartList.getBurgerHashMap().keySet()) {
            int count = shoppingCartList.getBurgerHashMap().get(burgerName);
            Optional<Burger> burger = burgerMenu.findBurgerByName(burgerName);

            burger.ifPresent(burger1 -> {
                double price = burger1.getBurgerPrice();
                totalPrice[0] += price * count;
                System.out.println(burgerName + " | " + price + "원 | " + count + "개 | ");
            });


        }

        System.out.println();
        System.out.println("[ TOTAL ]");
        System.out.println("W " + totalPrice[0]);
        System.out.println();

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

        while(true) {
            int inputForOrder = scanner.nextInt();

            if (inputForOrder == 1){
                System.out.println("주문이 완료되었습니다. 금액은 W " + totalPrice[0] + "입니다.");
                break;
            } if (inputForOrder == 2){
                break;
            } else {
                System.out.println("올바른 번호를 입력해주세요.");
            }
        }
    }

 

 

for (String burgerName : shoppingCartList.getBurgerHashMap().keySet())

: 장바구니 리스트에 추가된 값들 중에 burgerName이 들어가 있는 목록을 조회하고

 

int count = shoppingCartList.getBurgerHashMap().get(burgerName);

: 장바구니 리스트에 추가된 burgerName의 개수를 보고 그 개수를 count로 저장해줬습니다.

(이는 총 가격을 계산할 때 사용하기 위함)

 

Optional<Burger> burger = burgerMenu.findBurgerByName(burgerName);

: 아까 위에서 정의 된 메서드를 호출해준 것입니다. 리턴받은 값을 burger에 넣어줬습니다.

 

 burger.ifPresent(burger1 -> {
                double price = burger1.getBurgerPrice();
                totalPrice[0] += price * count;
                System.out.println(burgerName + " | " + price + "원 | " + count + "개 | ");
            });

: burger 안에 실제로 Burger 객체가 존재할 경우에 burger1을 실행하는데,

버거 객체에서 가격을 꺼내어 price에 저장해주고 (여기서는 burger1이 Optional 안에 있던 진짜 버거 객체)

totialPrice[0] 에 저장해서 총 가격에 누적해줬습니다.

(배열로 사용한 이유는 람다 안에서 바깥 변수 값을 수정할 수 없기 때문입니다.)

마지막으로 그 객체의 burgerName 등을 출력해준 모습입니다.


 HashMap에서 같은 버거 이름이 들어올 때 수량을 늘리는 로직이 처음에는 헷갈렸지만, getOrDefault를 쓰면서 깔끔하게 해결 할 수 있었습니다.


 지금까지 배운 내용들이 정말 다 들어가있는 과제였던거같습니다. 클래스를 여러 개로 나누다보니 흐름을 놓치면 다시 찾아서 하기 힘들더군요. 그래서 정말 집중이 끊이지 않게 쉬지 않고 계속해서 앉아있었습니다. (뭔가 하얗게 불태웠다? 라는 말이 이 때 쓰는 것 같아요.) 

 이번 과제를 하면서 가장 어려웠던 부분은 리스트를 다루는 부분이였습니다. 객체를 다룸에 있어서 기초적인 부분은 이해했다고 생각이 들긴하지만, 조금이라도 심화된 개념에는 아직 많이 미흡하다고 생각합니다. 남은 과제 제출 시간동안은 리스트와 enum타입에 대한 공부를 집중적으로 해봐야겠다고 느꼈습니다.