상품주문 프로그램 핵심: 사용자가 원하는 상품을 문제없이 주문할 수 있어야 한다.
- Java version: jdk-11.0.18
- Gradle version: 8.0
- lombok version: 1.18.28
- 상품주문 프로그램 기능 출발지 - ProductController#run()
- 프로그램 객체 준비 - ProductController#ready()
- 프로그램 기능 시작 - ProductController#orderPlay()
- 상품 저장소
- 상품 데이터 가져오기 - ProductRepository#getCSVData()
- 콤마(,) 기준 분할 - ProductRepository#splitToComma()
- 상품 데이터 검증 - ProductRepository#validateTokens()
- 상품 데이터 제목 검증 - ProductRepository#validateTitle()
- 상품 데이터 추가 - ProductRepository#addProductMap()
- 상품 데이터 파일 읽기 종료 - ProductRepository#fileReaderClose()
- 상품 주문
- 주문 또는 종료 입력 - InputView#orderORQuit()
- 상품번호 입력 - InputView#orderOfNumber()
- 수량 입력 - InputView#orderOfVolume()
- 주문 처리
- 상품 주문 번호 검증 - OrderService#validateOrderNumber()
- 상품 메뉴 번호들 확인 - OrderService#hasMenuNumbers()
- 상품 주문 번호 비교 - OrderService#isOrderNumber()
- 상품수량 검증 - OrderService#validateOrderVolume()
- 상품 수량과 재고 수 확인 - Menu#volumeInStock()
- 상품 주문 번호 검증 - OrderService#validateOrderNumber()
- 주문 내역
- 총 상품 정보 출력 - OutputView#printToTotalProduct()
- 상품 주문 내역 출력 - OutputView#printToOrderResult()
- 상품 데이터 처리
- csv 파일에서 가져온 상품 데이터 가져오가 성공 - ProductRepositoryTest#getCSVDataSuccess()
- 상품 주문 처리
- 주문 상품 번호 존재하는 경우 성공 - OrderServiceTest#orderNumberToExist()
- 주문 상품 번호 존재하지 않는 경우 예외 발생 - OrderServiceTest#orderNumberToNotExist()
- 주문 상품 재고 부족 여부 확인 - OrderServiceTest#orderVolumeInStock()
- 주문 상품 재고 부족 예외 발생 - OrderServiceTest#orderVolumeNotInStock()
📦src
┣ 📂main
┃ ┗ 📂java
┃ ┃ ┗ 📂kr
┃ ┃ ┃ ┗ 📂co
┃ ┃ ┃ ┃ ┗ 📂_29cm
┃ ┃ ┃ ┃ ┃ ┗ 📂homework
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂constant
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂exception
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜messageException.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂service
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜OrderConstant.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜ResultNameConstant.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📂view
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜InputViewConstant.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜OutputViewConstant.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂exception
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜handlerException.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂model
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜Menu.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜Order.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜Product.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂repository
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜ProductRepository.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂service
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜OrderService.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂validate
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜InputViewValidator.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜OutputViewValidator.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂view
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜Console.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜InputView.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜OutputView.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜Main.java
┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜ProductController.java
┗ 📂test
┃ ┗ 📂java
┃ ┃ ┗ 📂kr
┃ ┃ ┃ ┗ 📂co
┃ ┃ ┃ ┃ ┗ 📂_29cm
┃ ┃ ┃ ┃ ┃ ┗ 📂homework
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂model
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜MenuTest.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜OrderTest.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂repository
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜ProductRepositoryTest.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂service
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜OrderServiceTest.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂validate
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┣ 📜InputViewValidatorTest.java
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜OutputViewValidatorTest.java
┃ ┃ ┃ ┃ ┃ ┃ ┣ 📂view
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜OutputViewTest.java
┃ ┃ ┃ ┃ ┃ ┃ ┗ 📜MultiThreadRequestTest.java
WorkFlow 에서 보여지는 흐름과 같이 사용자가 주문에 대한 결제를 진행할 때 다른 쓰레드에서는 주문 결제를 기다리고 있어야한다. 그렇지 않으면 상품번호:213341 의 재고가 부족함에도 주문 결제가 진행되어 사용자는 없는 상품을 주문을 하게된다.
main 에서 실행되는 method 가 2개 있다.
main 의 선언된 method 2개를 실행하면 끝나기 때문에 빅오 표기법으로 표현하면 O(1)
상수시간의 시간복잡도를 가진다.
하지만, 실행되는 method 의 내부 로직을 확인해 보아야 한다.
productRepository.getData() 로직을 확인해보면
while((line=file.readLine())!=null){
/* Service Logic */
}
while 반복문 1개가 돌고있다. 이 반복문은 CSV 파일의 존재하는 행의 개수만큼 반복하고 종료한다.
현재는 20개 행이 존재하기 때문에 20번 반복하고 종료될 것이다.
하지만, 상품 수는 증가 할 수 있는 성격을 가지기 때문에 찾으려는 상품 수 만큼 탐색한다고 할 수 있어 O(N)
시간 복잡도를 가진다.
이제 productSale.run() 로직을 확인해보자
while(true){ // 종료 입력 전까지 '주문'을 반복적으로 입력 받는 반복문
/* Service Logic */
while(true){ // '상품번호', '수량'을 반복적으로 입력 받는 반복문
/* Service Logic */
}
}
while 반복문 2개가 돌고있다.
첫 번째 반복문의 역할은 사용자가 '주문' or '종료' 를 선택하는 반복문이다.
두 번째 반복문의 역할은 사용자가 '주문' 선택시 주문할 '상품번호' and '수량' 을 반복적으로 입력받는 반복문이다.
사용자의 입력이 1번으로 끝날 수도 있고 100번으로 끝날 수도 있어 예측이 불가하지만 결국에는 사용자가 입력하는 횟수만큼 반복할 것이다.
여기서 반복문 내부의 존재하는 method 들도 확인해보자
첫 번째 반복문에서 동작하는 method 가 2개 존재한다.
- productRepository.getCurrentProductInfo()
- productRepository.getOrderComplete(productNumbers, productStocks)
// getCurrentProductInfo()
productMap.forEach((k,v)->
/* Service Logic */
)
// getOrderComplete(productNumbers, productStocks)
for(int i=0;i<productNumbers.size();i++){
/* Service Logic */
}
getCurrentProductInfo() 는 저장된 상품 정보를 하나씩 출력하고 있다.
현재는 19개의 상품정보를 가지고 있어 O(19)
상수 시간만 반복하지만 이 경우도 상품 데이터가 증가할 수 있는 성격을 띄기 때문에 존재하는 상품 수 만큼 탐색한다고 할 수 있어 O(N)
시간복잡도를 가진다.
getOrderComplete(productNumbers, productStocks) 는 사용자가 주문한 만큼 반복이 진행된다.
사용자 주문이 1번일 수 도 있고 100번 일 수도 있기 때문에 결국 사용자 주문만큼 반복하게되 O(N)
시간 복잡도를 가진다.
두 번째 반복문에서 동작하는 method 도 2개 존재한다.
- productRepository.getStockCheck(orderNumber, orderStock)
- productRepository.getProductCheck(orderNumber)
// getStockCheck(orderNumber, orderStock)
if(product!=null){
/* Service Logic */
if(currentStock<orderStock){
/* Service Logic */
}
}
// getProductCheck(orderNumber)
if(productExist!=null){
/* Service Logic */
}
getStockCheck(orderNumber, orderStock) 는 현재 존재하는 재고 수와 주문한 재고 수를 확인하는 기능이다.
이중 조건문을 사용하지만 조건문은 O(1)
상수 시간의 시간복잡도를 가진다.
getProductCheck(orderNumber) 는 사용자가 주문한 상품이 존재하는 상품인지 확인하는 기능이다.
조건문 하나를 사용하고 있어 O(1)
상수 시간의 시간복잡도를 가진다.
결론적으로, 최고차항만을 남기는 점근적 표기법인 빅오(Big-O) 표기법으로 표현한다면
두 번째 반복문에서 동작하는 함수는 실행시간에서 제외할 수 있고,
첫 번째 반복문에서는 반복문이 1개 중첩되어 사용되는걸 확인할 수 있기 때문에
이 프로그램은 O(N^2)
시간복잡도를 가진다고 할 수 있다.