일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 알고리즘
- QueryDSL
- 유니티
- 구현
- Unity2D
- 해시
- C++
- 워크플로
- Inventory
- 언리얼엔진
- 이분탐색
- 스파르타내일배움캠프
- Photon
- 프로그래머스
- 문자열
- 스택
- unityui
- Unity
- 유클리드호제법
- 포톤
- FSM
- 내일배움캠프
- Unity3d
- BFS
- UE4
- Firebase
- 스파르타내일배움캠프TIL
- UnrealEngine
- 순열
- c#
- Today
- Total
개발 낙서장
JAVA 개인 과제 - 키오스크 만들기 - 2일차 본문
이전 글
https://dachomi97.tistory.com/60
JAVA 개인 과제 - 키오스크 만들기 - 1일차
과제 소개 📢 내가 좋아하는 카페 또는 패스트푸드점의 키오스크를 만들어보자! 지금까지 배워온 Java 언어를 사용하여 키오스크 프로그램을 만들기. 내가 좋아하는 카페나 패스트푸드점의 메
dachomi97.tistory.com
피드백 영상을 보고 전반적으로 코드를 수정했다. 스파르타 돈까스 2호점 오픈
클래스 재설계
이게 기존 클래스의 설계도이다. Menu라는 클래스를 각각의 메뉴들이 상속받아 구현하고 있으며
TopMenu에서 DetailMenu들을 List로, DetailMenu에서 ProductMenu들을 List로 갖고 있다.
처음에 설계할 때는 나름 객체지향적이고 상속도 받고 자식으로 리스트도 갖고 있어 관리도 편리하겠다 라고 생각했는데 피드백 영상을 보고 클래스 관계를 다시 보니 좀 복잡하고 쓸데없이 종속적이고 과하게 클래스를 나눈 감도 있는 것 같았다.
그래서 그냥 Menu 클래스를 상속 받는 클래스는 Product 클래스만 냅두고 데이터 클래스에서 Map으로 메뉴들을 관리하는 방식으로 바꿔야겠다.
이렇게 하면 따로 클래스를 나누는 것이 아니라 Map에 저장할 때 Key값을 통해 보다 간단하게 클래스를 나누는 효과를 기대할 수 있다.
package Data;
import Menu.Menu;
import Menu.Product;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class MenuData {
public static String restaurantName = "스파르타 돈까스";
Map<String, List<Menu>> menus;
Map<String, List<Product>> products;
public MenuData() {
menus = new LinkedHashMap<>();
products = new LinkedHashMap<>();
Init();
}
public void Init() {
List<Menu> mainMenus = new ArrayList<>();
List<Menu> addMenus = new ArrayList<>();
List<Menu> orderMenus = new ArrayList<>();
mainMenus.add(new Menu("돈까스", "바삭바삭한 돈까스"));
...
addMenus.add(new Menu("미니 우동", "뜨끈뜨끈한 미니 우동"));
orderMenus.add(new Menu("주문하기", "장바구니를 확인 후 주문합니다."));
orderMenus.add(new Menu("취소하기", "진행 중인 주문을 취소합니다."));
menus.put("메인 메뉴", mainMenus);
menus.put("추가 메뉴", addMenus);
menus.put("주문 메뉴", orderMenus);
List<Product> cutlets = new ArrayList<>();
cutlets.add(new Product("등심까스", "부드러운 등심으로 만든 돈까스", 10500.0));
cutlets.add(new Product("모짜렐라치즈까스", "쭉 늘어나는 치즈까스", 12900.0));
cutlets.add(new Product("에비텐모듬까스", "새우튀김과 돈까스", 13900.0));
...
List<Product> miniUdons = new ArrayList<>();
miniUdons.add(new Product("미니 우동", "뜨끈뜨끈한 미니 우동", 4500.));
products.put("돈까스", cutlets);
...
products.put("미니 우동", miniUdons);
}
public Map<String, List<Menu>> getMenuMap() {
return menus;
}
public List<Menu> getMenus(String key) {
return menus.get(key);
}
public Map<String, List<Product>> getProductMap() {
return products;
}
public List<Product> getProducts(String key) {
return products.get(key);
}
}
원래는 메인 메뉴, 추가 메뉴, 주문, 취소 등 모든 것을 클래스화해서 사용했지만 이렇게 기본 클래스만 만들어놓고 Map을 사용하면 훨씬 더 간편하게 사용할 수 있었다.역시 자료구조를 활용할 줄 모르면 몸이 고생한다
입력 예외 처리
KioskApp 클래스도 수정했다.
클래스 구조가 바뀐 만큼 메뉴 조회하는 부분을 대부분 변경했고, 입력값을 nextLine이 아닌 nextInt로 숫자로 입력받도록 했다.
그리고 예외 처리를 해서 잘못된 입력이 들어올 경우 메인 화면으로 돌아가도록 했다.
try {
int answer = sc.nextInt();
...
} catch(Exception e) {
// 잘못된 입력입니다
ShowMain();
}
이런 식으로 예외 처리를 구성했는데 문제가 발생했다.
입력값이 초기화되지 않아 계속해서 예외가 발생해 StackOverflow가 발생했다.예외 처리를 했는데 에러가 발생돼버리는 기이한 현상.....
이유가 뭔가 하니 nextInt는 정수 값만 받게 돼있는데 보통 입력할 때 정수와 '엔터'를 입력한다.
그래서 Scanner 스택에 엔터값이 남아있게 되고 nextInt는 정수값만 빼오기 때문에 계속해서 남아있는 엔터 값은 사라지지 않고 예외가 반복되어 StackOverflow 에러가 발생하는 것이다.
입력을 받을 때 Scanner 객체를 계속해서 new로 생성해 버퍼를 지워줄까 했지만 입력값이 많아질 수록 메모리 부하가 일어나기 때문에 좋지 않은 방법이라 생각했고
while문을 통해 올바른 값을 입력 받을 때까지 입력을 반복할까 했지만 나는 그냥 잘못된 값이 입력되면 바로 메인 화면으로 돌아가게 하고 싶었기 때문에 이 방법도 별로였다.
그래서 조금 더 검색해보니 next()나 nextLine()을 사용하면 간단히 해결되는 거였다.
스택에 있는 문자열을 저 메소드들이 비워주기 때문에 다시 깨끗한 상태로 입력받을 수 있다.
예외 처리까지 완료된 KioskApp 클래스는 다음과 같다.
package Kiosk;
import Data.CartData;
import Data.MenuData;
import Menu.Menu;
import Menu.Product;
import java.util.*;
import static Data.MenuData.restaurantName;
public class KioskApp {
static MenuData md;
static CartData cd;
Scanner sc = new Scanner(System.in);
Map<Integer, Menu> controlKiosk = new HashMap<>();
public KioskApp() {
Init();
}
public void Init() {
md = new MenuData();
cd = new CartData();
cd.ClearCart();
ShowMain();
}
public void ShowMain() {
System.out.println("\"" + restaurantName + "에 오신걸 환영합니다.\"");
System.out.println("아래 메뉴판을 보시고 메뉴를 골라 입력해주세요.");
int index = 1;
controlKiosk.clear();
for (String menuName : md.getMenuMap().keySet()) {
System.out.println("\n[ " + menuName + " ]");
for (Menu menu : md.getMenus(menuName)) {
System.out.printf("%d. %-30s | %-50s\n", index, menu.getName(), menu.getDesc());
controlKiosk.put(index, menu);
index++;
}
}
try {
System.out.print("\n입력 : ");
int answer = sc.nextInt();
switch (controlKiosk.get(answer).getName()) {
case "주문하기":
ShowOrder();
break;
case "취소하기":
ShowCancel();
break;
default:
ShowDetail(answer);
break;
}
} catch (Exception e) {
WrongInput();
}
}
void ShowDetail(int input) {
System.out.println("\n\"" + restaurantName + "에 오신걸 환영합니다.\"");
System.out.println("아래 메뉴판을 보시고 상품를 골라 입력해주세요.");
String menuName = controlKiosk.get(input).getName();
List<Product> products = md.getProducts(menuName);
System.out.println("[ " + menuName + " ]");
int index = 1;
controlKiosk.clear();
for (Product p : products) {
System.out.printf("%d. %-30s | %-10s | %-50s\n", index, p.getName(), p.getPrice().toString(), p.getDesc());
controlKiosk.put(index, p);
index++;
}
try {
System.out.print("\n입력 : ");
int answer = sc.nextInt();
ShowAddCart(answer);
} catch (Exception e) {
WrongInput();
}
}
void ShowAddCart(int input) {
Product product = (Product) controlKiosk.get(input);
controlKiosk.clear();
System.out.printf("\n[ %-30s | %-10s | %-50s ]\n", product.getName(), product.getPrice().toString(), product.getDesc());
System.out.println("위 메뉴를 장바구니에 추가하시겠습니까?");
System.out.println("1. 확인\t2. 취소");
try {
System.out.print("\n입력 : ");
int answer = sc.nextInt();
if (answer == 1) {
System.out.println(product.getName() + "(이)가 장바구니에 추가되었습니다.");
cd.AddProductInCart(product);
}
ShowMain();
} catch (Exception e) {
WrongInput();
}
}
void ShowOrder() {
System.out.println("아래와 같이 주문하시겠습니까?");
controlKiosk.clear();
double totalPrice = 0;
System.out.println("\n[ 장바구니 ]");
for (Product p : cd.GetCart().keySet()) {
System.out.printf("%-30s | %-10s | %-10s개 | %-50s\n", p.getName(), p.getPrice(), cd.GetCart().get(p), p.getDesc());
totalPrice += p.getPrice();
}
System.out.println("\n[ 가격 ]");
System.out.println(totalPrice + " 원");
System.out.println("\n1. 주문 \t 2. 메뉴판");
try {
System.out.print("\n입력 : ");
int answer = sc.nextInt();
if (answer == 1) {
ShowClearOrder();
} else {
ShowMain();
}
} catch (Exception e) {
WrongInput();
}
}
void ShowClearOrder() {
cd.ClearCart();
System.out.println("주문이 완료되었습니다!");
System.out.println("(3초 후 메인 화면으로 돌아갑니다.)");
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
ShowMain();
}
};
timer.schedule(task, 3000);
}
void ShowCancel() {
System.out.println("진행하던 주문을 취소하시겠습니까?");
System.out.println("1. 확인 \t 2. 취소");
try {
System.out.print("\n입력 : ");
int answer = sc.nextInt();
if (answer == 1) {
System.out.println("\n진행하던 주문이 취소되었습니다.");
cd.ClearCart();
}
} catch (Exception e) {
WrongInput();
}
}
void WrongInput() {
System.out.println("\n잘못된 입력입니다.\n1초 후 메인 화면으로 돌아갑니다.\n");
sc.next();
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
ShowMain();
}
};
timer.schedule(task, 1000);
}
}
확실히 메뉴와 상품 클래스들을 압축하니 직관성도 올라갔고 사용하기에도 편리했다.
너무 객체지향에 매몰되어 모든 것을 하나하나 나누어 개발하다 보면 오히려 먼 길을 돌아서 갈 수도 있다는 걸 깨닫게 됐다.
그래도 나름 객체지향적인 개발을 하려고 노력했어서 코드를 수정하는게 어렵지 않았다. 메뉴를 사용한 부분만 수정한 것을 제외하면 나머지 코드는 거의 그대로 갖다 썼다.
그래도 여기서 나름 객체지향의 장점인 코드 재사용성이 드러난 부분..?
'Java > Sparta' 카테고리의 다른 글
JAVA 개인 과제 - 키오스크 만들기 - 3일차 (0) | 2024.01.10 |
---|---|
[TIL] 내일배움캠프 11일차 - 개인 과제 - (0) | 2024.01.09 |
[TIL] 내일배움캠프 10일차 - 쓰레드 - (0) | 2024.01.08 |
[TIL] 내일배움캠프 9일차 - 개인 과제 - (0) | 2024.01.05 |
JAVA 개인 과제 - 키오스크 만들기 - 1일차 (0) | 2024.01.05 |