Light Blue Pointer
본문 바로가기
Developing/Journal

[내일배움캠프][Java 개인과제]키오스크 개발일지

by Greedy 2023. 10. 19.

과제 요구사항

💡 내가 좋아하는 카페 또는 패스트푸드점의 키오스크를 만들어보자!

  • 지금까지 배워온 Java 언어를 사용하여 키오스크 프로그램을 만들어봅시다.
  • 내가 좋아하는 카페나 패스트푸드점의 메뉴판 데이터를 사용하면 더 재밌겠죠?
  1. 메뉴판을 보고 주문할 수 있는 Java 프로그램
  1. 화면은 System.out.println() 메소드를 사용해서 심플하게 출력한다.
  2. 메뉴 클래스와 주문 클래스를 사용하여 Java 의 핵심 기능인 상속을 최대한 사용
  3. 내가 좋아하는 메뉴들로 다양하게 구성해보세요!
  • 필수 요구사항
    1. 메인 메뉴판 화면
      • 메인 메뉴판이 출력되며 메뉴판에는 상품 메뉴가 출력 됩니다.
      • 상품 메뉴는 간단한 설명과 함께 출력 되며 최소 3개 이상 출력 됩니다.
      • 상품 메뉴 아래에는 Order(주문)와 Cancel(주문 취소) 옵션을 출력해줍니다.
      "SHAKESHACK BURGER 에 오신걸 환영합니다."
      아래 메뉴판을 보시고 메뉴를 골라 입력해주세요.
      
      [ SHAKESHACK MENU ]
      1. Burgers         | 앵거스 비프 통살을 다져만든 버거
      2. Forzen Custard  | 매장에서 신선하게 만드는 아이스크림
      3. Drinks          | 매장에서 직접 만드는 음료
      4. Beer            | 뉴욕 브루클린 브루어리에서 양조한 맥주
      
      [ ORDER MENU ]
      5. Order       | 장바구니를 확인 후 주문합니다.
      6. Cancel      | 진행중인 주문을 취소합니다.
      
    2. 상품 메뉴판 화면
      • 상품 메뉴 선택 시 해당 카테고리의 메뉴판이 출력됩니다.
      • 메뉴판에는 각 메뉴의 이름과 가격과 간단한 설명이 표시됩니다.
       "SHAKESHACK BURGER 에 오신걸 환영합니다."
      아래 상품메뉴판을 보시고 상품을 골라 입력해주세요.
      
      [ Burgers MENU ]
      1. ShackBurger   | W 6.9 | 토마토, 양상추, 쉑소스가 토핑된 치즈버거
      2. SmokeShack    | W 8.9 | 베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거
      3. Shroom Burger | W 9.4 | 몬스터 치즈와 체다 치즈로 속을 채운 베지테리안 버거
      3. Cheeseburger  | W 6.9 | 포테이토 번과 비프패티, 치즈가 토핑된 치즈버거
      4. Hamburger     | W 5.4 | 비프패티를 기반으로 야채가 들어간 기본버거
      
    3. 구매 화면
      • 상품 선택 시 해당 상품을 장바구니에 추가할지 확인하는 문구가 출력 됩니다.
      • 1.확인 입력 시 장바구니에 추가되었다는 안내 문구와 함께 메인 메뉴로 다시 출력 됩니다.
      "Hamburger     | W 5.4 | 비프패티를 기반으로 야채가 들어간 기본버거"
      위 메뉴를 장바구니에 추가하시겠습니까?
      1. 확인        2. 취소
      
      Hamburger 가 장바구니에 추가되었습니다.
      
      "SHAKESHACK BURGER 에 오신걸 환영합니다."
      아래 메뉴판을 보시고 메뉴를 골라 입력해주세요.
      
      [ SHAKESHACK MENU ]
      1. Burgers         | 앵거스 비프 통살을 다져만든 버거
      2. Forzen Custard  | 매장에서 신선하게 만드는 아이스크림
      3. Drinks          | 매장에서 직접 만드는 음료
      4. Beer            | 뉴욕 브루클린 브루어리에서 양조한 맥주
      
      [ ORDER MENU ]
      5. Order       | 장바구니를 확인 후 주문합니다.
      6. Cancel      | 진행중인 주문을 취소합니다.
      
    4. 주문 화면
      • 5.Order 입력 시 장바구니 목록을 출력해줍니다.
      • 장바구니에서는 추가된 메뉴들과 총 가격의 합을 출력해줍니다.
      • 1.주문 입력 시 주문완료 화면으로 넘어가고, 2.메뉴판 입력 시 다시 메인 메뉴로 돌아옵니다.
      아래와 같이 주문 하시겠습니까?
      
      [ Orders ]
      ShackBurger   | W 6.9 | 토마토, 양상추, 쉑소스가 토핑된 치즈버거
      SmokeShack    | W 8.9 | 베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거
      
      [ Total ]
      W 15.8
      
      1. 주문      2. 메뉴판
      
    5. 주문완료 화면
      • **1.주문 입력 시 대기번호를 발급해줍니다.**
      • 장바구니는 초기화되고 3초 후에 메인 메뉴판으로 돌아갑니다.
      주문이 완료되었습니다!
      
      대기번호는 [ 1 ] 번 입니다.
      (3초후 메뉴판으로 돌아갑니다.)
      
      "SHAKESHACK BURGER 에 오신걸 환영합니다."
      아래 메뉴판을 보시고 메뉴를 골라 입력해주세요.
      
      [ SHAKESHACK MENU ]
      1. Burgers         | 앵거스 비프 통살을 다져만든 버거
      2. Forzen Custard  | 매장에서 신선하게 만드는 아이스크림
      3. Drinks          | 매장에서 직접 만드는 음료
      4. Beer            | 뉴욕 브루클린 브루어리에서 양조한 맥주
      
      [ ORDER MENU ]
      5. Order       | 장바구니를 확인 후 주문합니다.
      6. Cancel      | 진행중인 주문을 취소합니다.
      
    6. 주문 취소 화면
      • 메뉴판에서 6.Cancel 입력시 주문을 취소할지 확인을 요청하는 문구가 출력 됩니다.
      • 1.확인 을 입력하면 장바구니는 초기화되고 취소 완료 문구와 함께 메뉴판이 출력 됩니다.
      추가기능!
      1. 주문 개수 기능 추가
        • 장바구니에 똑같은 상품이 담기면 주문 화면에서 상품 개수가 출력 되도록 합니다.
        아래와 같이 주문 하시겠습니까?
        
        [ Orders ]
        ShackBurger   | W 6.9 | 2개 | 토마토, 양상추, 쉑소스가 토핑된 치즈버거
        SmokeShack    | W 8.9 | 1개 | 베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거
        
        [ Total ]
        W 15.8
        
        1. 주문      2. 메뉴판
        
      2. 상품 옵션 기능 추가
        • 상품에 옵션을 선택 후 장바구니에 추가 할 수 있게 세분화 합니다.
        1. 총 판매금액 조회 기능 추가
          • 구매가 완료될 때마다 총 판매 금액을 누적해줍니다.
          • 숨겨진 기능으로 0번 입력 시 총 판매금액을 출력합니다.
          [ 총 판매금액 현황 ]
          현재까지 총 판매된 금액은 [ W 102.4 ] 입니다.
          
          1. 돌아가기
          
        2. 총 판매상품 목록 조회 기능 추가
          • 구매가 완료될 때마다 판매 상품 목록을 저장해줍니다.
          • 숨겨진 기능으로 0번 입력 시 총 판매 상품 목록을 출력합니다.
  • Java 클래스 설계 시 필수 요구사항!
    • 메뉴 클래스는 이름, 설명 필드를 가지는 클래스로 만들어주세요.
    • 상품 클래스는 이름, 가격, 설명 필드를 가지는 클래스로 만들어주세요.
    • 상품 클래스의 이름, 가격 필드는 메뉴 클래스를 상속받아 사용하는 구조로 개발해주세요.
    • 주문 클래스도 만들어서 상품 객체를 담을 수 있도록 해주세요.//무슨뜻인지 약간 이해가 안 갔음

 

내가 개발하는 과정

⭐인텔리제이 코드 정렬

ctrl+shift+alt+L → Run 버튼 누르기

 

⭐ 자바 배열 선언과 초기화

int[] intArray = new int[5];

 

⭐ static 변수는 class 밑 메인 함수 시작하기 전에 써줘야 한다

*static int* [] *burgerCount* = *new int*[5];

 

⭐ 자바 배열 길이

int length = array.length;

⭐ 자바 상속

public Class Child extends Parent{}

 

함수만 가지고 코드 짜다가 깨달았다

과제에서는 상속을 쓰라고 했다는걸…

⭐ Java ArrayList

import java.util.ArrayList; // import the ArrayList class

ArrayList<String> cars = new ArrayList<String>(); // Create an ArrayList object

⭐ Java ArrayList 선언

ArrayList<String> cars = new ArrayList<String>();

⭐ Java ArrayList  쓰기

cars.add("Volvo");//추가
cars.set(0, "Opel");//수정
cars.remove(0);//삭제
cars.clear();//모두삭제

⭐ Java ArrayList  읽기

cars.get(0);//원소 
cars.size();//크기

Java ArrayList Loop

for (int i = 0; i < cars.size(); i++) {
      System.out.println(cars.get(i));
    }

⭐ Java ArrayList  forEach loop

    ArrayList<String> cars = new ArrayList<String>();
    cars.add("Volvo");
    cars.add("BMW");
    cars.add("Ford");
    cars.add("Mazda");
    for (String i : cars) {
      System.out.println(i);
    }

⭐ Java ArrayList  Sort

ArrayList<String> cars = new ArrayList<String>();
    cars.add("Volvo");
    cars.add("BMW");
    cars.add("Ford");
    cars.add("Mazda");
    Collections.sort(cars);  // Sort cars
    for (String i : cars) {
      System.out.println(i);
    }

⭐ 자바 부모클래스에서 자식클래스 메소드 사용하기

**((Child)** parent**).**childMethod**()**


자바에도 forEach있는지 처음 알았는데 되게 편리하다

문제 1 : m이 Menu로 되어있어서 자식 클래스에 있는 price 필드에 접근이 안 됨

for (Menu m : orders) {
            m.printDesc();
            total = total + m.price;
        }

해결1 : 이 메소드로 상위클래스에도 getPrice함수 그냥 {}으로 선언해놓고 함수 오버라이딩해서 price들고와서 해결했다

public double getPrice(){
        return this.price;
    }

 

문제 2:

double total = 0;
        for (Menu m : orders) {
            m.printDesc();
            total = total + ((Good)m).getPrice();
        }

Q. 3초 기다리기

import java.lang.Thread;
import java.util.concurrent.TimeUnit;
Thread.sleep(3000);
TimeUnit.SECONDS.sleep(3)

import 해왔는데도 둘 다 안되는게 Main method안에서만 될 수도 있어

일단 내버려두자 타임스탬프 값 읽던가 하자 나중에

 

⭐자바 클래스 생성자

puclic Classname(){}//기본생성자
 Classname(Parameter parameter)(
)

⭐ 자바 객체 타입 알아내기

instanceOf
// 생성은 자식 String이지만 대입될 때 Object 타입으로 변환
	Object o1 = "string";
		
	// o1 변수가 참조하는 객체의 타입이 Object 타입?
	System.out.println(o1 instanceof Object);  // true
		
	// o1 변수가 참조하는 객체의 타입이 String 타입?
	System.out.println(o1 instanceof String);  // true
		
	// 무관한 타입이라서 false 출력
	System.out.println(o1 instanceof Integer);  // false
	// Integer가 Object를 상속받기 때문에 이건 syntax error가 아님
	}

⭐ 생성자 상위클래스의 생성자 이용

super

public Good(String name, String desc,double price){
        super(name, desc);
        this.price = price;
    }

Q.상위클래스요소 접근은 혹시 super로 해야되나? 싶어서 원래 this.쓰던거 super.으로 바꿈

public void printDesc(){
        System.out.println(super.name + "     | W "+this.price+" | "+super.desc);
    }

 

menus 를 static으로 만들어버렸는데 어떡해요?

Q. static 아니게 하는법? 코드 더 좋게 하는법 ?

menus.add(good);

이게 static이 아니면 동작을 안 함

static이면 그걸 Main 에서 forEach 돌아서 카피해서 새 menus Arraylist를 만들어서 orders에 넣는 수밖에 없지 뭐…

그리고 Main에서 결제하면 pop하고

아니면 계산중인 명수만 세면 된다면 int로 카운트해서 order 생성자에서 Main static에 카운트 올리고

계산 마치면 빠지고 하면 될거 같다

public ArrayList<Menu> instanceMenus;

일단 저장용으로 하나 만들어봄

저장하면서 menus는 싹 비워줘야됨

 

💡코드 개선 :

원래 반복 이렇게 짜고 있었는데

while (true) {//order반복
            int menu = 0;
            Order order = new Order();
            while (menu == 0) {//메뉴 선택 반복
                menu = order.selectMenu();
            }//메뉴선택 끝남
        }

여기서 가서 int가 0으로 받아져 오면 메뉴 선택 계속 돌아가게 함

public static int selectMenu() {
        Scanner sc = new Scanner(System.in);
        System.out.println("SHAKESHACK BURGER 에 오신걸 환영합니다.\\n" +
                //대충 6까지 고르라는 메뉴판
        );
        int menu = sc.nextInt();

        if (menu == 1) {//버거
            int burger = 0;
            while (burger == 0) {//버거 선택 반복
                burger = selectBurger();
            }

            return menu;//1부터 6 안에 값이 있으면 if else 돌면서 그 값 리턴하고 
        } //이하 똑같아서 생략
        }
        return 0;//1부터 6 안에 값이 없으면 0리턴함, Main의 while 안에서 0이면 계속 돌아가게 되어있음

return값 0이면 다시 돌아갔다가 나가게 함

근데 그냥 호출되는 함수에 while 넣고 함수 내에서 return이 실행되지 않으면 무한반복하게 하면 더 편하고 함수 호출도 적게 됨

public void order() {
        while (true) {
            Scanner sc = new Scanner(System.in);

            System.out.println("아래와 같이 주문 하시겠습니까?\\n" +
                    "1. 주문      2. 메뉴판");
                    
            int x = sc.nextInt();
            
            if (x == 1) {//주문
                Main.increaseWaiting();//대기 인원 증가
                System.out.println("주문이 완료되었습니다!\\n\\n" +
                        "대기번호는 [ " + Main.getWaiting() + " ] 번 입니다.\\n" +
                        "(3초후 메뉴판으로 돌아갑니다.)");
                //3초 기다려야됨
                sc.close();
                return;//1이면 돌아감
            }else if(x==2) {
                sc.close();
                return;//1이나 2면 돌아가고 아니면 계속 돌아가는 함수
            }
        }
    }

전체를 while(true)로 감싸버리면 더 간편함

 

 

💡 코드 개선:

public static int selectBurger() {
        while(true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("SHAKESHACK BURGER 에 오신걸 환영합니다.\\n" +
                    "아래 상품메뉴판을 보시고 상품을 골라 입력해주세요.\\n\\n" +
                    "[ Burgers MENU ]\\n" +
                    "1. ShackBurger   | W 6.9 | 토마토, 양상추, 쉑소스가 토핑된 치즈버거\\n" +
                    "2. SmokeShack    | W 8.9 | 베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거\\n" +
                    "3. Shroom Burger | W 9.4 | 몬스터 치즈와 체다 치즈로 속을 채운 베지테리안 버거\\n" +
                    "4. Cheeseburger  | W 6.9 | 포테이토 번과 비프패티, 치즈가 토핑된 치즈버거\\n" +
                    "5. Hamburger     | W 5.4 | 비프패티를 기반으로 야채가 들어간 기본버거"
            );
            int burger = sc.nextInt();
            sc.close();

            Good good;
            if (burger == 1) {
                good = new Good("ShackBurger", "토마토, 양상추, 쉑소스가 토핑된 치즈버거", 6.9);
            } else if (burger == 2) {
                good = new Good("SmokeShack", "베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거", 8.9);
            } else if (burger == 3) {
                good = new Good("Shroom Burger", "몬스터 치즈와 체다 치즈로 속을 채운 베지테리안 버거", 9.4);
            } else if (burger == 4) {
                good = new Good("Cheeseburger", "포테이토 번과 비프패티, 치즈가 토핑된 치즈버거", 6.9);
            } else if (burger == 5) {
                good = new Good("Hamburger", "비프패티를 기반으로 야채가 들어간 기본버거", 5.4);
            }

            int confirm = 0;
            while (confirm == 0) {
                **good.printDesc();//오류남**
                confirm = confirmMenu();
            }
            if (confirm == 1) {
                menus.add(good);
                System.out.println(good.getName() + " 가 장바구니에 추가되었습니다.");
            }
            return burger;
        }
    }

good.printDesc();

여기에 빨간줄 가고 else의 경우에 good이 지정이 안 된다고 함

근데 int confirm 부터 다 else if안에다 똑같은 코드를 반복해서 쓰기가 싫었음

그렇다고 int confirm 문 실행하기 전에 if로 감싸서 if burger = 1or 2 or 3 or 4 or 5 or 6

이런 비교문 또 만들기도 싫었음

while(true){
	if (burger == 1) {
               
    } else if (burger == 2) {
               
    } else if (burger == 3) {
              
    } else if (burger == 4) {
              
    } else if (burger == 5) {
             
    }else{
         continue;//burger가 1~6이 아니면 다음 while문으로 가서 아래 코드 스킵됨
    }
    
    burger가 1~6일때만 실행하고 싶은 코드
    
}

elseif들 밑에다 else면 그냥continue;로 while문 다음으로 넘겨버리는 코드 만들어서 해결함

 

문제 3 :

Scanner이용하고 함수 호출 끝나기 전에 sc.close 해놓으니까 같은 class의 다른 함수가 호출됐을때 Scanner객체 새로 생성해도 닫힌상태라 안 됨

해결 3:그냥 sc.close(); 다 뺌

닫고 열고 닫고 열고 개념이 아니라 한번 닫으면 영영 닫히나봄

Q.닫는게 정확히 어떻게 되길래 그럴까?

 

문제 4:

넣고 주문목록이랑 주문까지 되는데 그러고 에러뜸

(3초후 메뉴판으로 돌아갑니다.)

Exception in thread "main" java.lang.NullPointerException at Main.main(Main.java:214)

Process finished with exit code 1

 

214줄 : order.instanceMenus.add(good); //여기서 에러남

public static ArrayList<Order> orders = new ArrayList<Order>();

여기에도 주황 줄이 뜸

Class 'Order' is exposed outside its defined visibility scope

어쩔 수 없이 public으로 만들어서 import해야하려나…

걍 public으로 class 만들어서 다 뺌

원래는 Menu랑 Good이랑 다 내부클래스로 class로 있었음Main.java안에

order.instanceMenus.add(good); 여기서 똑같은 에러가 남

 

코드 보다보니 public ArrayList<Menu> instanceMenus; 이렇게 선언만 하고 초기화를 안 해서 접근이 안 되는거 같음

분명 저거 코딩할때는 나중에 생성하고 써야지 했는데 생성하는걸 잊어버렸다

당연히 선언만 되어있고 아무것도 없으니까 NullPointerException이 뜨지

Exception in thread "main" java.lang.NullPointerException at Main.main(Main.java:28)

order.instanceMenus = new ArrayList<Menu>();
order.instanceMenus.add(good);

사용하기 전에 생성하는 코드를 추가해보았다

 

문제 5:

Exception in thread "main" java.util.NoSuchElementException at java.base/java.util.Scanner.throwFor(Scanner.java:937) at java.base/java.util.Scanner.next(Scanner.java:1594) at java.base/java.util.Scanner.nextInt(Scanner.java:2258) at java.base/java.util.Scanner.nextInt(Scanner.java:2212) at Order.selectMenu(Order.java:24) at Main.main(Main.java:22)

Process finished with exit code 1

이번엔 주문 버튼 누르니까 다른데서 에러가 난다

아까랑 다르게 대기자 명단도 안 뜨는걸 보니까 주문하러 못 들어간 거 같음

public static void selectMenu() {
        while(true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("SHAKESHACK BURGER 에 오신걸 환영합니다.\\n" +
                    "아래 메뉴판을 보시고 메뉴를 골라 입력해주세요.\\n" +
                    "[ SHAKESHACK MENU ]\\n" +
                    "1. Burgers         | 앵거스 비프 통살을 다져만든 버거\\n" +
                    "2. Forzen Custard  | 매장에서 신선하게 만드는 아이스크림\\n" +
                    "3. Drinks          | 매장에서 직접 만드는 음료\\n" +
                    "4. Beer            | 뉴욕 브루클린 브루어리에서 양조한 맥주\\n\\n" +
                    "[ ORDER MENU ]\\n" +
                    "5. Order       | 장바구니를 확인 후 주문합니다.\\n" +
                    "6. Cancel      | 진행중인 주문을 취소합니다."
            );
            **int menu = sc.nextInt();//에러나는곳**

음 생각해보니 int menu가 이미 있는데 또 생성해서 그런게 아닐까 생각한다

public static void selectMenu() {
        int menu;
        while(true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("SHAKESHACK BURGER 에 오신걸 환영합니다.\\n" +
                    "아래 메뉴판을 보시고 메뉴를 골라 입력해주세요.\\n" +
                    "[ SHAKESHACK MENU ]\\n" +
                    "1. Burgers         | 앵거스 비프 통살을 다져만든 버거\\n" +
                    "2. Forzen Custard  | 매장에서 신선하게 만드는 아이스크림\\n" +
                    "3. Drinks          | 매장에서 직접 만드는 음료\\n" +
                    "4. Beer            | 뉴욕 브루클린 브루어리에서 양조한 맥주\\n\\n" +
                    "[ ORDER MENU ]\\n" +
                    "5. Order       | 장바구니를 확인 후 주문합니다.\\n" +
                    "6. Cancel      | 진행중인 주문을 취소합니다."
            );
            menu = sc.nextInt();

해결 5: 그래서 int menu를 while문이 아무리 많이 돌아도 두번 생성되지 않게 밖으로 뺐더니 해결되었다

 

오늘은 공통되는 부분이 많아서 코드를 축약하는 과정을 거쳤다

 

 

public static void selectBeer() {
        while(true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("SHAKESHACK BURGER 에 오신걸 환영합니다.\n" +
                    "아래 상품메뉴판을 보시고 상품을 골라 입력해주세요.\n\n" +
                    "[ Beers MENU ]\n" +
                    "1. Lager   | W 4.8 | 강한 탄산감이 있는 청량한 맥주\n" +
                    "2. Ale    | W 4.3 | 풍부한 향과 단맛이 나는 높은 바디감의 맥주\n" +
                    "3. Abita Root Beer | W 3.5 | 맥주인 척 하는 탄산음료\n"
            );
            int select = sc.nextInt();


            Product good;
            if (select == 1) {
                good = new Product("Lager", "강한 탄산감이 있는 청량한 맥주", 4.8);
            } else if (select == 2) {
                good = new Product("Ale", "풍부한 향과 단맛이 나는 높은 바디감의 맥주", 4.3);
            } else if (select == 3){
                good = new Product("Abita Root Beer", "맥주인 척 하는 탄산음료", 3.5);
            } else{
                continue;
            }

            int confirm = 0;
            while (confirm == 0) {
                good.printDesc();
                confirm = confirmMenu();
            }
            if (confirm == 1) {
                menus.add(good);
                System.out.println(good.getName() + " 가 장바구니에 추가되었습니다.");
            }
            return;
        }
    }

원래 이렇게 selectBeer 따로, selectBurger따로 selectIcecream 따로 selectDrink 따로 있었는데

그냥 하나로 통합해봤다

 

원래 이렇게 있고

if (menu == 1) {//버거
                selectBurger();
            } else if (menu == 2) {//아이스크림
                selectIcecream();
            } else if (menu == 3) {//음료
                selectDrink();
            } else if (menu == 4) {//맥주
                selectBeer();
            } else if (menu == 5) {//Order
                int order = order();
                if(order == 1){//1이면 주문 2이면 걍 반복
                    return 1;
                }
            } else if (menu == 6) {//Cancel
                int order = cancel();
                if(order == 1){//1이면 주문취소 아니면 걍 반복
                    return 2;
                }

고르는 함수도 다 따로 있었다

public static void selectBurger() {
        while(true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("SHAKESHACK BURGER 에 오신걸 환영합니다.\n" +
                    "아래 상품메뉴판을 보시고 상품을 골라 입력해주세요.\n\n" +
                    "[ Burgers MENU ]\n" +
                    "1. ShackBurger   | W 6.9 | 토마토, 양상추, 쉑소스가 토핑된 치즈버거\n" +
                    "2. SmokeShack    | W 8.9 | 베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거\n" +
                    "3. Shroom Burger | W 9.4 | 몬스터 치즈와 체다 치즈로 속을 채운 베지테리안 버거\n" +
                    "4. Cheeseburger  | W 6.9 | 포테이토 번과 비프패티, 치즈가 토핑된 치즈버거\n" +
                    "5. Hamburger     | W 5.4 | 비프패티를 기반으로 야채가 들어간 기본버거"
            );
            int select = sc.nextInt();


            Product good;
            if (select == 1) {
                good = new Product("ShackBurger", "토마토, 양상추, 쉑소스가 토핑된 치즈버거", 6.9);
            } else if (select == 2) {
                good = new Product("SmokeShack", "베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거", 8.9);
            } else if (select == 3) {
                good = new Product("Shroom Burger", "몬스터 치즈와 체다 치즈로 속을 채운 베지테리안 버거", 9.4);
            } else if (select == 4) {
                good = new Product("Cheeseburger", "포테이토 번과 비프패티, 치즈가 토핑된 치즈버거", 6.9);
            } else if (select == 5) {
                good = new Product("Hamburger", "비프패티를 기반으로 야채가 들어간 기본버거", 5.4);
            } else{
                continue;
            }

            int confirm = 0;
            while (confirm == 0) {
                good.printDesc();
                confirm = confirmMenu();
            }
            if (confirm == 1) {
                menus.add(good);
                System.out.println(good.getName() + " 가 장바구니에 추가되었습니다.");
            }
            return;
        }
    }

근데 그냥 코드에서 반복되는 줄글 다 묶어서 한 파일에다 넣으려고 따로 뺌

공통되는 부분은 묶어서 클래스 타입에 따라서 알아서 오버라이딩 되게 하고 메뉴 줄글이 길다 보니까 계속 데리고 다니기 거추장스러워서 메뉴의 값에 관련된 부분은 그 메뉴의 타입 (버거,비어,드링크,아이스크림)에 따라서 출력되게 하위클래스에다 넣음..

public class Drink extends Product {
    public Drink(int select) {
        if (select == 1) {
            super.setName("Raspberry Lemonade");
            super.setDesc("쉐이크쉑 시그니처 레몬에이드에 상큼 달콤한 라즈베리가 더해진 시즌 한정 레몬에이드");
            super.setPrice(4.8);
        } else if (select == 2) {
            super.setName("Lemonade");
            super.setDesc("매장에서 직접 만드는 상큼한 레몬에이드");
            super.setPrice(4.3);
        } else if (select == 3) {
            super.setName("Fresh Brewed Iced Tea");
            super.setDesc("직접 유기농 홍차를 우려낸 아이스 티");
            super.setPrice(3.5);
        }
    }
    public static void printProduct() {
        System.out.println(
                "[ Drinks MENU ]\\n" +
                "1. Raspberry Lemonade   | W 4.8 | 쉐이크쉑 시그니처 레몬에이드에 상큼 달콤한 라즈베리가 더해진 시즌 한정 레몬에이드\\n" +
                "2. Lemonade    | W 4.3 | 매장에서 직접 만드는 상큼한 레몬에이드\\n" +
                "3. Fresh Brewed Iced Tea | W 3.5 | 직접 유기농 홍차를 우려낸 아이스 티\\n"
        );
    }
}

그리고 또 저기도 글자가 너무 반복되는 거 같아서 수정이 용이하도록 또 바꿈

public class Drink extends Product {
    private static int [] count ={0,0,0};
    private static String [] name = {"Raspberry Lemonade","Lemonade","Fresh Brewed Iced Tea"};
    private static String [] desc = {"쉐이크쉑 시그니처 레몬에이드에 상큼 달콤한 라즈베리가 더해진 시즌 한정 레몬에이드",
            "매장에서 직접 만드는 상큼한 레몬에이드",
            "직접 유기농 홍차를 우려낸 아이스 티"};
    private static double [] price = {4.8,4.3,3.5};
    public Drink(int select) {
        super.setName(name[select-1]);
        super.setDesc(desc[select-1]);
        super.setPrice(price[select-1]);
        count[select-1] = count[select-1]+1;
    }
    public static void printProduct() {//메뉴 선택시 출력
        System.out.println("[ Burgers MENU ]\n");
        for(int i=0;i<count.length;i++){//for문 돌면서 있으면 출력
            System.out.println((i+1)+". "+name[i]+"   | W "+price[i]+" | "+desc[i]);
        }
    }

이렇게 간편해졌다

생성자를 잘 만들어 두니까 selectBurger,Icecream,Beer,Drink를 selectProduct로 축약하는게 가능했고

printDesc함수는 타입별로 오버라이딩해서 나오게 했더니 편해졌음

public static void selectProduct(int menu) {
        while (true) {
            Scanner sc = new Scanner(System.in);
            System.out.println("SHAKESHACK BURGER 에 오신걸 환영합니다.\n" +
                    "아래 상품메뉴판을 보시고 상품을 골라 입력해주세요.\n\n");

            switch (menu) {
                case 1:
                    Burger.printProduct();
                    break;
                case 2:
                    Icecream.printProduct();
                    break;
                case 3:
                    Drink.printProduct();
                    break;
                case 4:
                    Beer.printProduct();
                    break;
                default:
                	continue;
            }
            int select = sc.nextInt();
            Product product;
            switch (menu) {
                case 1:
                    if ((0 < select) && (select < 6)) {
                        product = new Burger(select);
                    } else {
                        continue;
                    }
                    break;
                case 2:
                    if ((0 < select) && (select < 4)) {
                        product = new Icecream(select);
                    } else {
                        continue;
                    }
                    break;
                case 3:
                    if ((0 < select) && (select < 4)) {
                        product = new Drink(select);
                    } else {
                        continue;
                    }
                    break;
                case 4:
                    if ((0 < select) && (select < 4)) {
                        product = new Beer(select);
                    } else {
                        continue;
                    }
                    break;
                default:
                	continue;
            }
            int confirm = 0;
            while (confirm == 0) {
                product.printDesc();
                confirm = confirmMenu();
            }
            if (confirm == 1) {
                menus.add(product);
                System.out.println(product.getName() + " 가 장바구니에 추가되었습니다.");
            }
            return;
        }
    }

지금은 printDescTotal로 이름이 바뀌었는데 

public void printDescTotal() {
        int productCount = 0;
        for(int i=0;i<name.length;i++){//for문 돌면서 이름 일치하는 상품이 2개 이상 있으면 개수 출력
            if(name[i]==super.getName()){
                productCount=count[i];
            }
        }
        if(productCount>1){//이름 일치하는 상품이 2개 이상이면 몇개라고 알려줌
            System.out.println(super.getName() + "     | W " + super.getPrice() + " | " +productCount+ " | " + super.getDesc());
        }else{//아니면 개수 빼고 출력
            System.out.println(super.getName() + "     | W " + super.getPrice() + " | "+ super.getDesc());
        }
    }
public class Drink extends Product {
    private static int [] count ={0,0,0};
    private static String [] name = {"Raspberry Lemonade","Lemonade","Fresh Brewed Iced Tea"};
    private static String [] desc = {"쉐이크쉑 시그니처 레몬에이드에 상큼 달콤한 라즈베리가 더해진 시즌 한정 레몬에이드",
            "매장에서 직접 만드는 상큼한 레몬에이드",
            "직접 유기농 홍차를 우려낸 아이스 티"};

그냥 상위클래스인 Product로 받아서 넘겨주면 타입별로(Burger,Drink,Beer,Icecream) count name desc를 각자 타입에 맞는걸로 접근해서 쓰니까 좋았다

 

⭐중첩 forEach문 돌리는 법

else if(result==3){//총 판매목록
                System.out.println(
                        "[ 총 판매 목록 ]\\n");
                for (Order o : orders) {
                    for (Menu m : o.instanceMenus) {
                        m.printDesc();
                    }
                }
                System.out.println("[ 총 판매 목록 출력 완료 ]");

            }

 

 

Q. printDesc 상위클래스에서 비게 놔둬서 쟤는 자동으로 오버라이딩되나 왜 (Product)로 캐스팅 안 해도 되지?

return 값 있어서 상위클래스에 return 0; 해둔 getPrice()만 캐스팅해서 써야됨

 

문제 : m.getPrice();가 안 됐다 

double total = 0;
            for (Menu m : menus) {
                m.printDesc();
                total = total + ((Product) m).getPrice();
            }

해결 :

하위클래스의 메소드를 쓰려면 캐스팅을 해 줘야 한다고 함

그래서 ((Product)m).getPrice();로 바꾸니까 잘 됐다

Product extends Menu 임

 

원래 Product에 구현되어있던 printDesc 함수를 각각 버거개수 아이스크림개수 맥주개수 음료개수를 종류대로 숫자 카운팅해서 출력하기 위해

각각 Burger,Icecream,Beer,Drink에 구현함

public void printDesc() {
        int productCount = 0;
        for(int i=0;i<name.length;i++){//for문 돌면서 이름 일치하는 상품이 2개 이상 있으면 개수 출력
            if(name[i]==super.getName()){
                productCount=count[i];
            }
        }
        if(productCount>1){
            System.out.println(super.getName() + "     | W " + super.getPrice() + " | " +productCount+ " | " + super.getDesc());
        }

 

문제 :  printDesc가 오버라이딩돼서 실행이 안 되고 상위클래스의 printDesc가 실행이 되어버림

for (Order o : orders) {
                    for (Menu m : o.instanceMenus) {
                        if(m instanceof Burger){
                            
                        }
                        m.printDesc();//이거 아래에서 구현했더니 여기서 안뜸 ㅜㅜ
                        total = total+ ((Product)m).getPrice();
                    }
                }
for (Order o : orders) {
                    for (Menu m : o.instanceMenus) {
                        //m.printDesc();//이거 아래에서 구현했더니 여기서 안뜸 ㅜㅜ이게 왜 안될까
                        System.out.println(m.getName() + "     | W " + m.getPrice() +  " | " + m.getDesc());
                        total = total+ ((Product)m).getPrice();
                    }
                }

Q.저게 왜 안되는지 알고싶다

public class Menu {
    public void printDesc() {
    }
    public void printDescTotal(){}
    public double getPrice() {
        return 0;
    }
public class Product extends Menu {

    public void printDesc() {
    }

     public void printDescTotal(){
    }



    public double getPrice() {
        return this.price;
    }
 }
public class Burger extends Product {

    public void printDescTotal() {
        int productCount = 0;
        for(int i=0;i<name.length;i++){//for문 돌면서 이름 일치하는 상품이 2개 이상 있으면 개수 출력
            if(name[i]==super.getName()){
                productCount=count[i];
            }
        }
        if(productCount>1){//이름 일치하는 상품이 2개 이상이면 몇개라고 알려줌
            System.out.println(super.getName() + "     | W " + super.getPrice() + " | " +productCount+ " | " + super.getDesc());
        }else{//아니면 개수 빼고 출력
            System.out.println(super.getName() + "     | W " + super.getPrice() + " | "+ super.getDesc());
        }
    }
    public void printDesc() {
        System.out.println(super.getName() + "     | W " + super.getPrice() +  " | " + super.getDesc());
    }

}

 

 

이렇게 하위클래스에서 구현되어 있는데 

printDescTotal은 버거인지 아이스크림인지에 따라 오버라이딩이 잘 되어서 잘 나옴

public void printDescTotal() {
        int productCount = 0;
        for(int i=0;i<name.length;i++){//for문 돌면서 이름 일치하는 상품이 2개 이상 있으면 개수 출력
            if(name[i]==super.getName()){
                productCount=count[i];
            }
        }
        if(productCount>1){
            System.out.println(super.getName() + "     | W " + super.getPrice() + " | " +productCount+ " | " + super.getDesc());
        }
    }

 

public void printDesc() {
        System.out.println(super.getName() + "     | W " + super.getPrice() +  " | " + super.getDesc());
    }

도대체 왜 이건 안 되는 거지?

 

 

int select = sc.nextInt();
            Product product;
            switch (menu) {
                case 1:
                    if ((0 < select) && (select < 6)) {
                        product = new Burger(select);
                    } else {
                        continue;
                    }
                    break;
                case 2:
                    if ((0 < select) && (select < 4)) {
                        product = new Icecream(select);
                    } else {
                        continue;
                    }
                    break;
                case 3:
                    if ((0 < select) && (select < 4)) {
                        product = new Drink(select);
                    } else {
                        continue;
                    }
                    break;
                case 4:
                    if ((0 < select) && (select < 4)) {
                        product = new Beer(select);
                    } else {
                        continue;
                    }
                    break;
                default:
                    continue;
            }
            int confirm = 0;
            while (confirm == 0) {
                product.printDescTotal();//개수출력
                confirm = confirmMenu();
            }

저 코드 안에서 printDescTotal은 버거냐 아이스크림이냐에 따라서 멀쩡히 오버라이딩이 잘 됨

그래서 혹시 상위상위 클래스인 Menu가 아니라 상위클래스인 Product로 받아와서 다 되나 싶어서 

다 Product로 바꿔봄

public class Order {
    public ArrayList<Product> instanceMenus; //여기도 바꾸고

    public Order() {
    }
}

order.instanceMenus = new ArrayList<Product>();//여기도 바꿈
else if(result==3){//총 판매목록
                double total = 0;
                System.out.println(
                        "[ 총 판매 목록 ]");
                for (Order o : orders) {
                    for (Product p : o.instanceMenus) {
                        p.printDesc();//
                        //System.out.println(m.getName() + "     | W " + m.getPrice() +  " | " + m.getDesc());
                        total = total+ p.getPrice();
                    }
                }
                System.out.println("[ Total ]\\nW " + total);

            }

 

Product로 다 바꿨는데도 안 됨

나중엔 알게되길 바라며 그냥 

System.out.println(p.getName() + "     | W " + p.getPrice() +  " | " + p.getDesc());

이렇게 써서 해결함 ㅎㅎ..

 

오늘 클래스에다 반복되는거 다듬고 오버라이딩되게 싹싹 정리했는데 너무 재밌었다