From f2bbdc4e7b773e06334e444c56d3f54223a2a404 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 17:11:52 +0900 Subject: [PATCH 01/25] =?UTF-8?q?docs=20:=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=AA=A9=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..70fd4a3c3 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,22 @@ +# 기능 구현 목록 +- [ ] : 동전 금액을 입력 받는다. + - [ ] : `예외 사항` : 빈 값인 경우 + - [ ] : `예외 사항` : 숫자가 아닌 경우 + - [ ] : `예외 사항` : 음수인 경우 +- +- [ ] : 잔돈을 돌려준다. + - [ ] : 남은 금액이 최저 가격보다 적은 경우 + - [ ] : 상품이 모두 소진된 경우 + - [ ] : 동전으로만 반환한다. + - [ ] : 최소 개수의 동전으로 잔돈을 돌려준다. + +- [ ] : 반환되지 않은 금액은 자판기에 남는다. + +- [ ] : 상품을 추가할 수 있는 기능이 있다. + - [ ] : 상품은 `;` 으로 구분하고 대괄호`[]` 로 묶여 있다. + - [ ] : 상품명, 가격, 수량 순서대로 쉼표로 구분되어 입력 받는다. + - [ ] : 상품의 가격은 100원 부터 시작하고 10원으로 나누어 떨어진다. + +- [ ] : 예외 발생시 IllegalArgumentException 발생시키고 다시 입력 받는다. + - [ ] : `[ERROR]` 로 시작하는 에러 메시지를 출력한다. + From 9cc5a65e1140ac2eae2c8157b0f9438fc9279bef Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 17:14:07 +0900 Subject: [PATCH 02/25] =?UTF-8?q?docs=20:=20=ED=95=B5=EC=8B=AC=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=ED=95=9C=20=EC=A4=84=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/README.md b/docs/README.md index 70fd4a3c3..85f05b7d4 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,3 +1,6 @@ +# 핵심 기능 +- 자판기의 상품 구매를 처리한다. + # 기능 구현 목록 - [ ] : 동전 금액을 입력 받는다. - [ ] : `예외 사항` : 빈 값인 경우 From 701c4686c58a51e12aa07052080d4540c0252fb3 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 17:18:10 +0900 Subject: [PATCH 03/25] =?UTF-8?q?feat=20:=20=EC=83=81=ED=92=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/Product.java | 6 ++++++ .../vendingmachine/ProductRepository.java | 20 +++++++++++++++++++ .../VendingMachineController.java | 7 +++++++ 3 files changed, 33 insertions(+) create mode 100644 src/main/java/vendingmachine/Product.java create mode 100644 src/main/java/vendingmachine/ProductRepository.java create mode 100644 src/main/java/vendingmachine/VendingMachineController.java diff --git a/src/main/java/vendingmachine/Product.java b/src/main/java/vendingmachine/Product.java new file mode 100644 index 000000000..4085cef49 --- /dev/null +++ b/src/main/java/vendingmachine/Product.java @@ -0,0 +1,6 @@ +package vendingmachine; + +public class Product { + private String name; + private int price; +} diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductRepository.java new file mode 100644 index 000000000..47c41064a --- /dev/null +++ b/src/main/java/vendingmachine/ProductRepository.java @@ -0,0 +1,20 @@ +package vendingmachine; + +import java.util.HashMap; +import java.util.Map; + +public class ProductRepository { + private final Map repository; + + private ProductRepository() { + repository = new HashMap<>(); + } + + public static ProductRepository getInstance() { + return new ProductRepository(); + } + + public void addProduct(Product product, int quantity) { + repository.put(product, repository.getOrDefault(product, 0) + quantity); + } +} diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java new file mode 100644 index 000000000..a79c969a1 --- /dev/null +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -0,0 +1,7 @@ +package vendingmachine; + +public class VendingMachineController { + public static void run() { + + } +} From f90af6d1ad2a270fc39f17906598b58c010b9c38 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 17:43:03 +0900 Subject: [PATCH 04/25] =?UTF-8?q?feat=20:=20=EC=83=81=ED=92=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20=EC=8B=A4=EC=A0=9C=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/Application.java | 2 +- src/main/java/vendingmachine/Product.java | 6 +++ .../vendingmachine/ProductRepository.java | 36 ++++++++++++++--- .../VendingMachineController.java | 16 ++++++++ .../java/vendingmachine/view/InputView.java | 22 ++++++++++ .../java/vendingmachine/view/OutputView.java | 10 +++++ .../vendingmachine/ProductRepositoryTest.java | 40 +++++++++++++++++++ 7 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 src/main/java/vendingmachine/view/InputView.java create mode 100644 src/main/java/vendingmachine/view/OutputView.java create mode 100644 src/test/java/vendingmachine/ProductRepositoryTest.java diff --git a/src/main/java/vendingmachine/Application.java b/src/main/java/vendingmachine/Application.java index 9d3be447b..ce96233b0 100644 --- a/src/main/java/vendingmachine/Application.java +++ b/src/main/java/vendingmachine/Application.java @@ -2,6 +2,6 @@ public class Application { public static void main(String[] args) { - // TODO: 프로그램 구현 + VendingMachineController.run(); } } diff --git a/src/main/java/vendingmachine/Product.java b/src/main/java/vendingmachine/Product.java index 4085cef49..ef71c9a1c 100644 --- a/src/main/java/vendingmachine/Product.java +++ b/src/main/java/vendingmachine/Product.java @@ -3,4 +3,10 @@ public class Product { private String name; private int price; + + public Product(String name, int price) { + this.name = name; + this.price = price; + } + } diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductRepository.java index 47c41064a..1dbd17b7d 100644 --- a/src/main/java/vendingmachine/ProductRepository.java +++ b/src/main/java/vendingmachine/ProductRepository.java @@ -1,20 +1,46 @@ package vendingmachine; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ProductRepository { - private final Map repository; + private static final Map repository = new HashMap<>(); private ProductRepository() { - repository = new HashMap<>(); + } - public static ProductRepository getInstance() { - return new ProductRepository(); + public static void initProductsByString(String input) { + String regex = "\\[([^,]+),([0-9]+),([0-9]+)\\]"; + + Pattern pattern = Pattern.compile(regex); + + + Arrays.stream(input.split(";")) + .forEach((value) -> { + Matcher matcher = pattern.matcher(value); + if (matcher.find()) { + String item = matcher.group(1); + int price = Integer.parseInt(matcher.group(2)); + int quantity = Integer.parseInt(matcher.group(3)); + + Product product = new Product(item, price); + repository.put(product, quantity); + return; + } + throw new IllegalArgumentException("잘못된 상품 입력입니다."); + }); + System.out.println(repository); } - public void addProduct(Product product, int quantity) { + public static void addProduct(Product product, int quantity) { repository.put(product, repository.getOrDefault(product, 0) + quantity); } + + private static void validate(String input) { + + } } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index a79c969a1..99456f1ad 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -1,7 +1,23 @@ package vendingmachine; +import java.util.function.Supplier; +import vendingmachine.view.InputView; +import vendingmachine.view.OutputView; + public class VendingMachineController { public static void run() { +// ProductRepository.addProductByString(readValidInput(InputView::readProduct)); + + + } + + private static String readValidInput(Supplier inputMethod) { + try { + return inputMethod.get(); + } catch (IllegalArgumentException error) { + OutputView.printError(error); + return readValidInput(inputMethod); + } } } diff --git a/src/main/java/vendingmachine/view/InputView.java b/src/main/java/vendingmachine/view/InputView.java new file mode 100644 index 000000000..2a2f50861 --- /dev/null +++ b/src/main/java/vendingmachine/view/InputView.java @@ -0,0 +1,22 @@ +package vendingmachine.view; + +import camp.nextstep.edu.missionutils.Console; + +public class InputView { + + public static final String INPUT_PRODUCT = "상품명과 가격, 수량을 입력해 주세요."; + + public static String readProduct() { + System.out.println(INPUT_PRODUCT); + String input = Console.readLine(); + validate(input); + return input; + } + + private static void validate(String input) { + if (input == null || input.isEmpty()) { + throw new IllegalArgumentException("입력값이 없습니다."); + } + } + +} diff --git a/src/main/java/vendingmachine/view/OutputView.java b/src/main/java/vendingmachine/view/OutputView.java new file mode 100644 index 000000000..8c4c06d94 --- /dev/null +++ b/src/main/java/vendingmachine/view/OutputView.java @@ -0,0 +1,10 @@ +package vendingmachine.view; + +public class OutputView { + + public static final String ERROR_PREFIX = "[ERROR] : "; + + public static void printError(IllegalArgumentException error) { + System.out.println(ERROR_PREFIX + error.getMessage()); + } +} diff --git a/src/test/java/vendingmachine/ProductRepositoryTest.java b/src/test/java/vendingmachine/ProductRepositoryTest.java new file mode 100644 index 000000000..c79569c8f --- /dev/null +++ b/src/test/java/vendingmachine/ProductRepositoryTest.java @@ -0,0 +1,40 @@ +package vendingmachine; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class ProductRepositoryTest { + @ParameterizedTest + @ValueSource(strings = {"[콜라,1500,20];[사이다,1000,10]"}) + void initProductsByStringSuccess(String input) { + Assertions.assertThatNoException().isThrownBy(() -> { + ProductRepository.initProductsByString(input); + }); + } + +// @Test +// void t() { +// String input = "[콜라,1500,20]"; +// String regex = "\\[([^,]+),([0-9]+),([0-9]+)\\]"; +// +// Pattern pattern = Pattern.compile(regex); +// Matcher matcher = pattern.matcher(input); +// +// if (matcher.matches()) { +// String item = matcher.group(1); +// String price = matcher.group(2); +// String quantity = matcher.group(3); +// +// System.out.println("상품: " + item); +// System.out.println("가격: " + price); +// System.out.println("수량: " + quantity); +// } else { +// System.out.println("일치하는 패턴이 없습니다."); +// } +// } + +} From 5e1b2e6a5e96e90130a22cc8cc2975658d3b612c Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 17:55:25 +0900 Subject: [PATCH 05/25] =?UTF-8?q?feat=20:=20=EC=83=81=ED=92=88=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=85=EB=A0=A5=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 6 +++--- .../vendingmachine/ProductRepository.java | 2 +- .../VendingMachineController.java | 14 +++++++------- .../vendingmachine/ProductRepositoryTest.java | 19 +++++++++++++++++++ 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/docs/README.md b/docs/README.md index 85f05b7d4..6f22e3ea8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,9 +15,9 @@ - [ ] : 반환되지 않은 금액은 자판기에 남는다. -- [ ] : 상품을 추가할 수 있는 기능이 있다. - - [ ] : 상품은 `;` 으로 구분하고 대괄호`[]` 로 묶여 있다. - - [ ] : 상품명, 가격, 수량 순서대로 쉼표로 구분되어 입력 받는다. +- [X] : 상품을 추가할 수 있는 기능이 있다. + - [X] : 상품은 `;` 으로 구분하고 대괄호`[]` 로 묶여 있다. + - [X] : 상품명, 가격, 수량 순서대로 쉼표로 구분되어 입력 받는다. - [ ] : 상품의 가격은 100원 부터 시작하고 10원으로 나누어 떨어진다. - [ ] : 예외 발생시 IllegalArgumentException 발생시키고 다시 입력 받는다. diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductRepository.java index 1dbd17b7d..ca901c9c5 100644 --- a/src/main/java/vendingmachine/ProductRepository.java +++ b/src/main/java/vendingmachine/ProductRepository.java @@ -14,7 +14,7 @@ private ProductRepository() { } public static void initProductsByString(String input) { - String regex = "\\[([^,]+),([0-9]+),([0-9]+)\\]"; + String regex = "^\\[([^,]+),([0-9]+),([0-9]+)\\]$"; Pattern pattern = Pattern.compile(regex); diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index 99456f1ad..f1e5e2259 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -1,23 +1,23 @@ package vendingmachine; -import java.util.function.Supplier; import vendingmachine.view.InputView; import vendingmachine.view.OutputView; public class VendingMachineController { public static void run() { -// ProductRepository.addProductByString(readValidInput(InputView::readProduct)); - - + initProducts(); } - private static String readValidInput(Supplier inputMethod) { + private static void initProducts() { try { - return inputMethod.get(); + String readProduct = InputView.readProduct(); + ProductRepository.initProductsByString(readProduct); } catch (IllegalArgumentException error) { OutputView.printError(error); - return readValidInput(inputMethod); + initProducts(); } } + + } diff --git a/src/test/java/vendingmachine/ProductRepositoryTest.java b/src/test/java/vendingmachine/ProductRepositoryTest.java index c79569c8f..c6f1ad786 100644 --- a/src/test/java/vendingmachine/ProductRepositoryTest.java +++ b/src/test/java/vendingmachine/ProductRepositoryTest.java @@ -3,6 +3,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -16,6 +17,24 @@ void initProductsByStringSuccess(String input) { }); } + @DisplayName("상품 구분자 형식이 잘못된 경우 예외 발생") + @ParameterizedTest + @ValueSource(strings = {"[콜라,1500,20] [사이다,1000,10]", "[콜라,1500,20].[사이다,1000,10]", "[콜라,1500,20];(사이다,1000,10)"}) + void initProductsByStringFailWithInvalidDelimiter(String input) { + Assertions.assertThatThrownBy(() -> { + ProductRepository.initProductsByString(input); + }).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("상품 입력 타입이 잘못된 경우 예외 발생") + @ParameterizedTest + @ValueSource(strings = {"[콜라,1500,a];[사이다,1000,10]", "[사이다,a,10]", "[,,10]", "[사이다,,10]", "[사이다,10]"}) + void initProductsByStringFailWithInvalidType(String input) { + Assertions.assertThatThrownBy(() -> { + ProductRepository.initProductsByString(input); + }).isInstanceOf(IllegalArgumentException.class); + } + // @Test // void t() { // String input = "[콜라,1500,20]"; From 15172780781fc460616c1fcbeebba1b4d7051cd2 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 18:01:13 +0900 Subject: [PATCH 06/25] =?UTF-8?q?feat=20:=20=EC=83=81=ED=92=88=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EC=97=90=20=EA=B4=80=ED=95=9C=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- src/main/java/vendingmachine/Product.java | 22 +++++++++ src/test/java/vendingmachine/ProductTest.java | 47 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/test/java/vendingmachine/ProductTest.java diff --git a/docs/README.md b/docs/README.md index 6f22e3ea8..14eeb035c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,7 +18,7 @@ - [X] : 상품을 추가할 수 있는 기능이 있다. - [X] : 상품은 `;` 으로 구분하고 대괄호`[]` 로 묶여 있다. - [X] : 상품명, 가격, 수량 순서대로 쉼표로 구분되어 입력 받는다. - - [ ] : 상품의 가격은 100원 부터 시작하고 10원으로 나누어 떨어진다. + - [X] : 상품의 가격은 100원 부터 시작하고 10원으로 나누어 떨어진다. - [ ] : 예외 발생시 IllegalArgumentException 발생시키고 다시 입력 받는다. - [ ] : `[ERROR]` 로 시작하는 에러 메시지를 출력한다. diff --git a/src/main/java/vendingmachine/Product.java b/src/main/java/vendingmachine/Product.java index ef71c9a1c..9a4975b0a 100644 --- a/src/main/java/vendingmachine/Product.java +++ b/src/main/java/vendingmachine/Product.java @@ -1,12 +1,34 @@ package vendingmachine; public class Product { + public static final int MIN_PRICE = 100; private String name; private int price; public Product(String name, int price) { + validate(name, price); this.name = name; this.price = price; } + private void validate(String name, int price) { + validateName(name); + validatePrice(price); + } + + private void validateName(String name) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("상품의 이름은 null이거나 빈 문자열일 수 없습니다."); + } + } + + private void validatePrice(int price) { + if (price < MIN_PRICE) { + throw new IllegalArgumentException("상품의 가격은 100원 이상이어야 합니다."); + } + if (price % 10 != 0) { + throw new IllegalArgumentException("상품의 가격은 10원 단위여야 합니다."); + } + } + } diff --git a/src/test/java/vendingmachine/ProductTest.java b/src/test/java/vendingmachine/ProductTest.java new file mode 100644 index 000000000..c409820c9 --- /dev/null +++ b/src/test/java/vendingmachine/ProductTest.java @@ -0,0 +1,47 @@ +package vendingmachine; + +import java.util.stream.Stream; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class ProductTest { + + @DisplayName("상품 등록에 성공하는 경우") + @ParameterizedTest + @MethodSource("productSuccessProvider") + void productSuccess(String name, int price) { + Assertions.assertThatNoException().isThrownBy(() -> { + new Product(name, price); + }); + } + + static Stream productSuccessProvider() { + return Stream.of( + Arguments.of("asd", 100), + Arguments.of("콜라", 1000), + Arguments.of("사이다", 2000) + ); + } + + @DisplayName("상품 등록에 실패하는 경우") + @ParameterizedTest + @MethodSource("productFailProvider") + void productFail(String name, int price) { + Assertions.assertThatThrownBy(() -> { + new Product(name, price); + }).isInstanceOf(IllegalArgumentException.class); + } + + static Stream productFailProvider() { + return Stream.of( + Arguments.of("", 100), + Arguments.of("콜라", 0), + Arguments.of("사이다", -99), + Arguments.of("사이다", 99), + Arguments.of("사이다", 101) + ); + } +} From 3798a8f3b6da3c443bc34b7505e5db701a564d0e Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 18:32:14 +0900 Subject: [PATCH 07/25] =?UTF-8?q?feat=20:=20=EB=8F=99=EC=A0=84=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 8 ++--- src/main/java/vendingmachine/Coin.java | 24 +++++++++++++- .../vendingmachine/ProductRepository.java | 12 +++---- .../java/vendingmachine/VendingMachine.java | 33 +++++++++++++++++++ .../VendingMachineController.java | 21 +++++++++--- .../java/vendingmachine/view/InputView.java | 22 +++++++++++-- .../vendingmachine/ProductRepositoryTest.java | 23 +++++++++++-- .../vendingmachine/VendingMachineTest.java | 19 +++++++++++ 8 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 src/main/java/vendingmachine/VendingMachine.java create mode 100644 src/test/java/vendingmachine/VendingMachineTest.java diff --git a/docs/README.md b/docs/README.md index 14eeb035c..67f227d61 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,10 +2,10 @@ - 자판기의 상품 구매를 처리한다. # 기능 구현 목록 -- [ ] : 동전 금액을 입력 받는다. - - [ ] : `예외 사항` : 빈 값인 경우 - - [ ] : `예외 사항` : 숫자가 아닌 경우 - - [ ] : `예외 사항` : 음수인 경우 +- [X] : 동전 금액을 입력 받는다. + - [X] : `예외 사항` : 빈 값인 경우 + - [X] : `예외 사항` : 숫자가 아닌 경우 + - [X] : `예외 사항` : 음수인 경우 - - [ ] : 잔돈을 돌려준다. - [ ] : 남은 금액이 최저 가격보다 적은 경우 diff --git a/src/main/java/vendingmachine/Coin.java b/src/main/java/vendingmachine/Coin.java index c76293fbc..6d26849bb 100644 --- a/src/main/java/vendingmachine/Coin.java +++ b/src/main/java/vendingmachine/Coin.java @@ -1,5 +1,10 @@ package vendingmachine; +import camp.nextstep.edu.missionutils.Randoms; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + public enum Coin { COIN_500(500), COIN_100(100), @@ -12,5 +17,22 @@ public enum Coin { this.amount = amount; } - // 추가 기능 구현 + public static Coin getRandomCoin() { + List amountList = Arrays.stream(Coin.values()) + .map(coin -> coin.amount) + .collect(Collectors.toList()); + int randomAmount = Randoms.pickNumberInList(amountList); + return findByAmount(randomAmount); + } + + private static Coin findByAmount(int amount) { + return Arrays.stream(Coin.values()) + .filter(coin -> coin.amount == amount) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 동전입니다.")); + } + + public int getAmount() { + return amount; + } } diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductRepository.java index ca901c9c5..abbbc3b9f 100644 --- a/src/main/java/vendingmachine/ProductRepository.java +++ b/src/main/java/vendingmachine/ProductRepository.java @@ -7,13 +7,13 @@ import java.util.regex.Pattern; public class ProductRepository { - private static final Map repository = new HashMap<>(); - - private ProductRepository() { + private Map repository; + public ProductRepository() { + repository = new HashMap<>(); } - public static void initProductsByString(String input) { + public void initProductsByString(String input) { String regex = "^\\[([^,]+),([0-9]+),([0-9]+)\\]$"; Pattern pattern = Pattern.compile(regex); @@ -36,11 +36,11 @@ public static void initProductsByString(String input) { System.out.println(repository); } - public static void addProduct(Product product, int quantity) { + public void addProduct(Product product, int quantity) { repository.put(product, repository.getOrDefault(product, 0) + quantity); } - private static void validate(String input) { + private void validate(String input) { } } diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java new file mode 100644 index 000000000..226af11c8 --- /dev/null +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -0,0 +1,33 @@ +package vendingmachine; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +public class VendingMachine { + private ProductRepository repository; + private Map coinMap; + private int leftMoney; + + public VendingMachine() { + repository = new ProductRepository(); + coinMap = new EnumMap<>(Coin.class); + leftMoney = 0; + } + + public void initProducts(ProductRepository repository) { + this.repository = repository; + } + + public void initMoney(int money) { + while (money >= Coin.COIN_10.getAmount()) { + Coin pickedCoin = Coin.getRandomCoin(); + if (money < pickedCoin.getAmount()) { + continue; + } + money -= pickedCoin.getAmount(); + coinMap.put(pickedCoin, coinMap.getOrDefault(pickedCoin, 0) + 1); + } + leftMoney += money; + } +} diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index f1e5e2259..e83259d39 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -5,17 +5,30 @@ public class VendingMachineController { public static void run() { + VendingMachine vendingMachine = new VendingMachine(); + initMoney(vendingMachine); + initProducts(vendingMachine); + } - initProducts(); + private static void initMoney(VendingMachine vendingMachine) { + try { + Integer money = InputView.readMoney(); + vendingMachine.initMoney(money); + } catch (IllegalArgumentException error) { + OutputView.printError(error); + initMoney(vendingMachine); + } } - private static void initProducts() { + private static void initProducts(VendingMachine vendingMachine) { try { String readProduct = InputView.readProduct(); - ProductRepository.initProductsByString(readProduct); + ProductRepository repository = new ProductRepository(); + repository.initProductsByString(readProduct); + vendingMachine.initProducts(repository); } catch (IllegalArgumentException error) { OutputView.printError(error); - initProducts(); + initProducts(vendingMachine); } } diff --git a/src/main/java/vendingmachine/view/InputView.java b/src/main/java/vendingmachine/view/InputView.java index 2a2f50861..c60e10044 100644 --- a/src/main/java/vendingmachine/view/InputView.java +++ b/src/main/java/vendingmachine/view/InputView.java @@ -4,19 +4,35 @@ public class InputView { + public static final String INPUT_MONEY = "자판기가 보유하고 있는 금액을 입력해 주세요."; public static final String INPUT_PRODUCT = "상품명과 가격, 수량을 입력해 주세요."; public static String readProduct() { System.out.println(INPUT_PRODUCT); - String input = Console.readLine(); - validate(input); + String input = Console.readLine().trim(); + validateBlank(input); return input; } - private static void validate(String input) { + private static void validateBlank(String input) { if (input == null || input.isEmpty()) { throw new IllegalArgumentException("입력값이 없습니다."); } } + // TODO 비즈니스 로직 분리 + public static Integer readMoney() { + System.out.println(INPUT_MONEY); + String input = Console.readLine().trim(); + validateBlank(input); + validateInteger(input); + return Integer.parseInt(input); + } + private static void validateInteger(String input) { + try { + Integer.parseInt(input); + } catch (NumberFormatException error) { + throw new IllegalArgumentException("숫자가 아닙니다."); + } + } } diff --git a/src/test/java/vendingmachine/ProductRepositoryTest.java b/src/test/java/vendingmachine/ProductRepositoryTest.java index c6f1ad786..7d8e6cb43 100644 --- a/src/test/java/vendingmachine/ProductRepositoryTest.java +++ b/src/test/java/vendingmachine/ProductRepositoryTest.java @@ -3,17 +3,25 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; public class ProductRepositoryTest { + ProductRepository repository; + + @BeforeEach + void setUp() { + repository = new ProductRepository(); + } + @ParameterizedTest @ValueSource(strings = {"[콜라,1500,20];[사이다,1000,10]"}) void initProductsByStringSuccess(String input) { Assertions.assertThatNoException().isThrownBy(() -> { - ProductRepository.initProductsByString(input); + repository.initProductsByString(input); }); } @@ -22,7 +30,7 @@ void initProductsByStringSuccess(String input) { @ValueSource(strings = {"[콜라,1500,20] [사이다,1000,10]", "[콜라,1500,20].[사이다,1000,10]", "[콜라,1500,20];(사이다,1000,10)"}) void initProductsByStringFailWithInvalidDelimiter(String input) { Assertions.assertThatThrownBy(() -> { - ProductRepository.initProductsByString(input); + repository.initProductsByString(input); }).isInstanceOf(IllegalArgumentException.class); } @@ -31,7 +39,16 @@ void initProductsByStringFailWithInvalidDelimiter(String input) { @ValueSource(strings = {"[콜라,1500,a];[사이다,1000,10]", "[사이다,a,10]", "[,,10]", "[사이다,,10]", "[사이다,10]"}) void initProductsByStringFailWithInvalidType(String input) { Assertions.assertThatThrownBy(() -> { - ProductRepository.initProductsByString(input); + repository.initProductsByString(input); + }).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("상품 가격이 잘못된 경우 예외 발생") + @ParameterizedTest + @ValueSource(strings = {"[콜라,1501,20]", "[콜라,15,20]", "[콜라, ,20]", "[콜라,-10,20]"}) + void initProductsByStringFailWithInvalidMoney(String input) { + Assertions.assertThatThrownBy(() -> { + repository.initProductsByString(input); }).isInstanceOf(IllegalArgumentException.class); } diff --git a/src/test/java/vendingmachine/VendingMachineTest.java b/src/test/java/vendingmachine/VendingMachineTest.java new file mode 100644 index 000000000..49a80399c --- /dev/null +++ b/src/test/java/vendingmachine/VendingMachineTest.java @@ -0,0 +1,19 @@ +package vendingmachine; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +public class VendingMachineTest { + + @ParameterizedTest + @ValueSource(ints = {100, 1000, 50000}) + void initMoneySuccess(int money) { + Assertions.assertThatNoException().isThrownBy(() -> { + VendingMachine vendingMachine = new VendingMachine(); + vendingMachine.initMoney(money); + }); + } + +} From 77d3e486e59d42618ce2d3f7d6923ba32ed6510c Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 18:37:00 +0900 Subject: [PATCH 08/25] =?UTF-8?q?feat=20:=20=EC=9E=90=ED=8C=90=EA=B8=B0=20?= =?UTF-8?q?=EB=B3=B4=EC=9C=A0=20=EB=8F=99=EC=A0=84=20=EC=B6=9C=EB=A0=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/Coin.java | 6 ++++++ src/main/java/vendingmachine/ProductRepository.java | 1 - src/main/java/vendingmachine/VendingMachine.java | 4 ++++ .../java/vendingmachine/VendingMachineController.java | 1 + src/main/java/vendingmachine/view/OutputView.java | 9 +++++++++ 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/vendingmachine/Coin.java b/src/main/java/vendingmachine/Coin.java index 6d26849bb..29b854a9e 100644 --- a/src/main/java/vendingmachine/Coin.java +++ b/src/main/java/vendingmachine/Coin.java @@ -32,6 +32,12 @@ private static Coin findByAmount(int amount) { .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 동전입니다.")); } + public static List getCoinOrderedList() { + return Arrays.stream(Coin.values()) + .sorted((o1, o2) -> o2.amount - o1.amount) + .collect(Collectors.toList()); + } + public int getAmount() { return amount; } diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductRepository.java index abbbc3b9f..0911a1742 100644 --- a/src/main/java/vendingmachine/ProductRepository.java +++ b/src/main/java/vendingmachine/ProductRepository.java @@ -33,7 +33,6 @@ public void initProductsByString(String input) { } throw new IllegalArgumentException("잘못된 상품 입력입니다."); }); - System.out.println(repository); } public void addProduct(Product product, int quantity) { diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index 226af11c8..a2a3c9dd3 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -30,4 +30,8 @@ public void initMoney(int money) { } leftMoney += money; } + + public Map getCoinMap() { + return coinMap; + } } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index e83259d39..75a9f6af1 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -8,6 +8,7 @@ public static void run() { VendingMachine vendingMachine = new VendingMachine(); initMoney(vendingMachine); initProducts(vendingMachine); + OutputView.printCoins(vendingMachine.getCoinMap()); } private static void initMoney(VendingMachine vendingMachine) { diff --git a/src/main/java/vendingmachine/view/OutputView.java b/src/main/java/vendingmachine/view/OutputView.java index 8c4c06d94..7283e07b9 100644 --- a/src/main/java/vendingmachine/view/OutputView.java +++ b/src/main/java/vendingmachine/view/OutputView.java @@ -1,5 +1,8 @@ package vendingmachine.view; +import java.util.Map; +import vendingmachine.Coin; + public class OutputView { public static final String ERROR_PREFIX = "[ERROR] : "; @@ -7,4 +10,10 @@ public class OutputView { public static void printError(IllegalArgumentException error) { System.out.println(ERROR_PREFIX + error.getMessage()); } + + public static void printCoins(Map coinMap) { + Coin.getCoinOrderedList().forEach((coin) -> { + System.out.println(coin.getAmount() + "원 - " + coinMap.getOrDefault(coin, 0) + "개"); + }); + } } From 0c825d764120a33ed545bddbece4e22ac98d2124 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 18:40:48 +0900 Subject: [PATCH 09/25] =?UTF-8?q?feat=20:=20=EC=83=81=ED=92=88=20=EC=88=98?= =?UTF-8?q?=EB=9F=89=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/ProductRepository.java | 7 +++++++ .../java/vendingmachine/VendingMachineController.java | 2 +- src/main/java/vendingmachine/view/InputView.java | 10 +++++++++- src/main/java/vendingmachine/view/OutputView.java | 1 + 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductRepository.java index 0911a1742..fb06928d8 100644 --- a/src/main/java/vendingmachine/ProductRepository.java +++ b/src/main/java/vendingmachine/ProductRepository.java @@ -28,6 +28,7 @@ public void initProductsByString(String input) { int quantity = Integer.parseInt(matcher.group(3)); Product product = new Product(item, price); + validateQuantity(quantity); repository.put(product, quantity); return; } @@ -35,6 +36,12 @@ public void initProductsByString(String input) { }); } + private void validateQuantity(int quantity) { + if (quantity <= 0) { + throw new IllegalArgumentException("잘못된 수량입니다."); + } + } + public void addProduct(Product product, int quantity) { repository.put(product, repository.getOrDefault(product, 0) + quantity); } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index 75a9f6af1..adaffb080 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -13,7 +13,7 @@ public static void run() { private static void initMoney(VendingMachine vendingMachine) { try { - Integer money = InputView.readMoney(); + Integer money = InputView.readHoldingMoney(); vendingMachine.initMoney(money); } catch (IllegalArgumentException error) { OutputView.printError(error); diff --git a/src/main/java/vendingmachine/view/InputView.java b/src/main/java/vendingmachine/view/InputView.java index c60e10044..eab89952c 100644 --- a/src/main/java/vendingmachine/view/InputView.java +++ b/src/main/java/vendingmachine/view/InputView.java @@ -20,7 +20,7 @@ private static void validateBlank(String input) { } } // TODO 비즈니스 로직 분리 - public static Integer readMoney() { + public static Integer readHoldingMoney() { System.out.println(INPUT_MONEY); String input = Console.readLine().trim(); validateBlank(input); @@ -35,4 +35,12 @@ private static void validateInteger(String input) { throw new IllegalArgumentException("숫자가 아닙니다."); } } + + public static Integer readInputMoney() { + System.out.println("투입할 금액을 입력해 주세요."); + String input = Console.readLine().trim(); + validateBlank(input); + validateInteger(input); + return Integer.parseInt(input); + } } diff --git a/src/main/java/vendingmachine/view/OutputView.java b/src/main/java/vendingmachine/view/OutputView.java index 7283e07b9..fda1f4b05 100644 --- a/src/main/java/vendingmachine/view/OutputView.java +++ b/src/main/java/vendingmachine/view/OutputView.java @@ -15,5 +15,6 @@ public static void printCoins(Map coinMap) { Coin.getCoinOrderedList().forEach((coin) -> { System.out.println(coin.getAmount() + "원 - " + coinMap.getOrDefault(coin, 0) + "개"); }); + System.out.println(); } } From 104dbddbe39ab79637ae2ab3f238a17405d70914 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 18:59:48 +0900 Subject: [PATCH 10/25] =?UTF-8?q?feat=20:=20=EC=83=81=ED=92=88=20=EA=B5=AC?= =?UTF-8?q?=EB=A7=A4=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/Product.java | 3 +++ .../vendingmachine/ProductRepository.java | 19 ++++++++++++++ .../java/vendingmachine/VendingMachine.java | 26 ++++++++++++++++--- .../VendingMachineController.java | 24 ++++++++++++++--- .../java/vendingmachine/view/InputView.java | 7 +++++ .../java/vendingmachine/view/OutputView.java | 4 +++ 6 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/main/java/vendingmachine/Product.java b/src/main/java/vendingmachine/Product.java index 9a4975b0a..b1995fe88 100644 --- a/src/main/java/vendingmachine/Product.java +++ b/src/main/java/vendingmachine/Product.java @@ -31,4 +31,7 @@ private void validatePrice(int price) { } } + public int getPrice() { + return price; + } } diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductRepository.java index fb06928d8..b08a45926 100644 --- a/src/main/java/vendingmachine/ProductRepository.java +++ b/src/main/java/vendingmachine/ProductRepository.java @@ -49,4 +49,23 @@ public void addProduct(Product product, int quantity) { private void validate(String input) { } + + public boolean canBuySomething(int money) { + return getMinPrice() <= money && getLeftProductCount() > 0; + } + private int getMinPrice() { + return repository.keySet() + .stream() + .mapToInt(Product::getPrice) + .min() + .orElseThrow(() -> new IllegalArgumentException("상품이 없습니다.")); + } + + private int getLeftProductCount() { + return repository.values() + .stream() + .mapToInt(Integer::intValue) + .sum(); + } + } diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index a2a3c9dd3..558162abf 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -1,18 +1,17 @@ package vendingmachine; import java.util.EnumMap; -import java.util.HashMap; import java.util.Map; public class VendingMachine { private ProductRepository repository; private Map coinMap; - private int leftMoney; + private int holdingMoney; public VendingMachine() { repository = new ProductRepository(); coinMap = new EnumMap<>(Coin.class); - leftMoney = 0; + holdingMoney = 0; } public void initProducts(ProductRepository repository) { @@ -28,10 +27,29 @@ public void initMoney(int money) { money -= pickedCoin.getAmount(); coinMap.put(pickedCoin, coinMap.getOrDefault(pickedCoin, 0) + 1); } - leftMoney += money; } public Map getCoinMap() { return coinMap; } + + public boolean canPurchaseSomething() { + return repository.canBuySomething(holdingMoney); + } + + public void initInputMoney(int inputMoney) { + validateMoney(inputMoney); + holdingMoney = inputMoney; + } + + private static void validateMoney(int money) { + if (money < 0) { + throw new IllegalArgumentException("음수는 입력할 수 없습니다."); + } + } + +// public void purchaseProduct(String product) { +// product +// } } + diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index adaffb080..80440dcaf 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -6,18 +6,20 @@ public class VendingMachineController { public static void run() { VendingMachine vendingMachine = new VendingMachine(); - initMoney(vendingMachine); + initVendingMachineMoney(vendingMachine); initProducts(vendingMachine); OutputView.printCoins(vendingMachine.getCoinMap()); + + initInputMoney(vendingMachine); } - private static void initMoney(VendingMachine vendingMachine) { + private static void initVendingMachineMoney(VendingMachine vendingMachine) { try { Integer money = InputView.readHoldingMoney(); vendingMachine.initMoney(money); } catch (IllegalArgumentException error) { OutputView.printError(error); - initMoney(vendingMachine); + initVendingMachineMoney(vendingMachine); } } @@ -33,5 +35,21 @@ private static void initProducts(VendingMachine vendingMachine) { } } + private static void initInputMoney(VendingMachine vendingMachine) { + try { + int inputMoney = InputView.readInputMoney(); + vendingMachine.initInputMoney(inputMoney); + } catch (IllegalArgumentException error) { + OutputView.printError(error); + initInputMoney(vendingMachine); + } + } + private static void proceedPurchase(VendingMachine vendingMachine, int inputMoney) { + while (vendingMachine.canPurchaseSomething()) { + OutputView.printLeftMoney(inputMoney); + String product = InputView.readPurchaseProduct(); +// vendingMachine.purchaseProduct(product); + } + } } diff --git a/src/main/java/vendingmachine/view/InputView.java b/src/main/java/vendingmachine/view/InputView.java index eab89952c..55988db44 100644 --- a/src/main/java/vendingmachine/view/InputView.java +++ b/src/main/java/vendingmachine/view/InputView.java @@ -43,4 +43,11 @@ public static Integer readInputMoney() { validateInteger(input); return Integer.parseInt(input); } + + public static String readPurchaseProduct() { + System.out.println("구매할 상품명을 입력해 주세요."); + String input = Console.readLine().trim(); + validateBlank(input); + return input; + } } diff --git a/src/main/java/vendingmachine/view/OutputView.java b/src/main/java/vendingmachine/view/OutputView.java index fda1f4b05..f8d1fe92f 100644 --- a/src/main/java/vendingmachine/view/OutputView.java +++ b/src/main/java/vendingmachine/view/OutputView.java @@ -17,4 +17,8 @@ public static void printCoins(Map coinMap) { }); System.out.println(); } + + public static void printLeftMoney(int money) { + System.out.printf("투입 금액: %d원\n", money); + } } From aead22c7a71b11f1e02686a780d787b142fe519b Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 19:15:12 +0900 Subject: [PATCH 11/25] =?UTF-8?q?feat=20:=20=EC=9E=94=EB=8F=88=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/Product.java | 4 ++ .../vendingmachine/ProductRepository.java | 30 +++++++++++---- .../java/vendingmachine/VendingMachine.java | 37 +++++++++++++++++-- .../VendingMachineController.java | 10 +++-- .../java/vendingmachine/view/OutputView.java | 4 ++ 5 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/main/java/vendingmachine/Product.java b/src/main/java/vendingmachine/Product.java index b1995fe88..00df9969d 100644 --- a/src/main/java/vendingmachine/Product.java +++ b/src/main/java/vendingmachine/Product.java @@ -34,4 +34,8 @@ private void validatePrice(int price) { public int getPrice() { return price; } + + public String getName() { + return name; + } } diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductRepository.java index b08a45926..be5708a8e 100644 --- a/src/main/java/vendingmachine/ProductRepository.java +++ b/src/main/java/vendingmachine/ProductRepository.java @@ -42,17 +42,30 @@ private void validateQuantity(int quantity) { } } - public void addProduct(Product product, int quantity) { - repository.put(product, repository.getOrDefault(product, 0) + quantity); - } +// public void addProduct(Product product, int quantity) { +// repository.put(product, repository.getOrDefault(product, 0) + quantity); +// } +// +// private void validate(String input) { +// +// } - private void validate(String input) { + public boolean canBuySomething(int money) { + return getMinPrice() <= money && getLeftTotalProductCount() > 0; + } + public Product findProductByName(String name) { + return repository.keySet() + .stream() + .filter((product) -> product.getName().equals(name)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("상품이 없습니다.")); } - public boolean canBuySomething(int money) { - return getMinPrice() <= money && getLeftProductCount() > 0; + public void purchaseProduct(Product product) { + repository.put(product, repository.get(product) - 1); } + private int getMinPrice() { return repository.keySet() .stream() @@ -61,11 +74,14 @@ private int getMinPrice() { .orElseThrow(() -> new IllegalArgumentException("상품이 없습니다.")); } - private int getLeftProductCount() { + private int getLeftTotalProductCount() { return repository.values() .stream() .mapToInt(Integer::intValue) .sum(); } + public int getLeftProductCount(Product product) { + return repository.get(product); + } } diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index 558162abf..4e40d9e76 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -48,8 +48,39 @@ private static void validateMoney(int money) { } } -// public void purchaseProduct(String product) { -// product -// } + public void purchaseProduct(String productName) { + Product product = repository.findProductByName(productName); + validatePurchase(product); + repository.purchaseProduct(product); + holdingMoney -= product.getPrice(); + } + + private void validatePurchase(Product product) { + if (product.getPrice() > holdingMoney) { + throw new IllegalArgumentException("잔액이 부족합니다."); + } + if (repository.getLeftProductCount(product) <= 0) { + throw new IllegalArgumentException("재고가 부족합니다."); + } + } + + public int getHoldingMoney() { + return holdingMoney; + } + + public Map getChange() { + Map change = new EnumMap<>(Coin.class); + Coin.getCoinOrderedList() + .forEach((coin) -> handleChange(change, coin)); + return change; + } + + private void handleChange(Map change, Coin coin) { + if (holdingMoney >= coin.getAmount()) { + int quantity = holdingMoney / coin.getAmount(); + change.put(coin, quantity); + holdingMoney -= coin.getAmount() * quantity; + } + } } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index 80440dcaf..b55e08a66 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -11,6 +11,7 @@ public static void run() { OutputView.printCoins(vendingMachine.getCoinMap()); initInputMoney(vendingMachine); + proceedPurchase(vendingMachine); } private static void initVendingMachineMoney(VendingMachine vendingMachine) { @@ -45,11 +46,14 @@ private static void initInputMoney(VendingMachine vendingMachine) { } } - private static void proceedPurchase(VendingMachine vendingMachine, int inputMoney) { + private static void proceedPurchase(VendingMachine vendingMachine) { while (vendingMachine.canPurchaseSomething()) { - OutputView.printLeftMoney(inputMoney); + OutputView.printLeftMoney(vendingMachine.getHoldingMoney()); String product = InputView.readPurchaseProduct(); -// vendingMachine.purchaseProduct(product); + vendingMachine.purchaseProduct(product); } + OutputView.printLeftMoney(vendingMachine.getHoldingMoney()); + OutputView.printLeft(); + OutputView.printCoins(vendingMachine.getChange()); } } diff --git a/src/main/java/vendingmachine/view/OutputView.java b/src/main/java/vendingmachine/view/OutputView.java index f8d1fe92f..8f5717bcc 100644 --- a/src/main/java/vendingmachine/view/OutputView.java +++ b/src/main/java/vendingmachine/view/OutputView.java @@ -21,4 +21,8 @@ public static void printCoins(Map coinMap) { public static void printLeftMoney(int money) { System.out.printf("투입 금액: %d원\n", money); } + + public static void printLeft() { + System.out.println("잔돈"); + } } From 7b6c32af0866ff0be208879c2c0881298382343e Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 19:24:35 +0900 Subject: [PATCH 12/25] =?UTF-8?q?feat=20:=20=EC=B6=9C=EB=A0=A5=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/VendingMachine.java | 5 ++++- .../vendingmachine/VendingMachineController.java | 5 ++--- src/main/java/vendingmachine/view/OutputView.java | 13 ++++++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index 4e40d9e76..198859f85 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -76,8 +76,11 @@ public Map getChange() { } private void handleChange(Map change, Coin coin) { + if (coinMap.get(coin) == null || coinMap.get(coin) <= 0) { + return; + } if (holdingMoney >= coin.getAmount()) { - int quantity = holdingMoney / coin.getAmount(); + int quantity = Math.min(holdingMoney / coin.getAmount(), coinMap.get(coin)); change.put(coin, quantity); holdingMoney -= coin.getAmount() * quantity; } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index b55e08a66..bff46f445 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -8,7 +8,7 @@ public static void run() { VendingMachine vendingMachine = new VendingMachine(); initVendingMachineMoney(vendingMachine); initProducts(vendingMachine); - OutputView.printCoins(vendingMachine.getCoinMap()); + OutputView.printHoldingCoins(vendingMachine.getCoinMap()); initInputMoney(vendingMachine); proceedPurchase(vendingMachine); @@ -53,7 +53,6 @@ private static void proceedPurchase(VendingMachine vendingMachine) { vendingMachine.purchaseProduct(product); } OutputView.printLeftMoney(vendingMachine.getHoldingMoney()); - OutputView.printLeft(); - OutputView.printCoins(vendingMachine.getChange()); + OutputView.printChangeCoins(vendingMachine.getChange()); } } diff --git a/src/main/java/vendingmachine/view/OutputView.java b/src/main/java/vendingmachine/view/OutputView.java index 8f5717bcc..9bc5eee1d 100644 --- a/src/main/java/vendingmachine/view/OutputView.java +++ b/src/main/java/vendingmachine/view/OutputView.java @@ -10,6 +10,15 @@ public class OutputView { public static void printError(IllegalArgumentException error) { System.out.println(ERROR_PREFIX + error.getMessage()); } + public static void printHoldingCoins(Map coinMap) { + System.out.println("자판기가 보유한 동전"); + printCoins(coinMap); + } + + public static void printChangeCoins(Map coinMap) { + System.out.println("잔돈"); + printCoins(coinMap); + } public static void printCoins(Map coinMap) { Coin.getCoinOrderedList().forEach((coin) -> { @@ -22,7 +31,5 @@ public static void printLeftMoney(int money) { System.out.printf("투입 금액: %d원\n", money); } - public static void printLeft() { - System.out.println("잔돈"); - } + } From fd2d587fdb65fda91e6cf8b567c7d2a00587066b Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 19:31:05 +0900 Subject: [PATCH 13/25] =?UTF-8?q?feat=20:=20=EC=98=88=EC=99=B8=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/VendingMachine.java | 1 + src/main/java/vendingmachine/view/InputView.java | 3 ++- src/main/java/vendingmachine/view/OutputView.java | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index 198859f85..e724d5919 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -19,6 +19,7 @@ public void initProducts(ProductRepository repository) { } public void initMoney(int money) { + validateMoney(money); while (money >= Coin.COIN_10.getAmount()) { Coin pickedCoin = Coin.getRandomCoin(); if (money < pickedCoin.getAmount()) { diff --git a/src/main/java/vendingmachine/view/InputView.java b/src/main/java/vendingmachine/view/InputView.java index 55988db44..130427bfe 100644 --- a/src/main/java/vendingmachine/view/InputView.java +++ b/src/main/java/vendingmachine/view/InputView.java @@ -32,11 +32,12 @@ private static void validateInteger(String input) { try { Integer.parseInt(input); } catch (NumberFormatException error) { - throw new IllegalArgumentException("숫자가 아닙니다."); + throw new IllegalArgumentException("금액은 숫자여야 합니다."); } } public static Integer readInputMoney() { + System.out.println(); System.out.println("투입할 금액을 입력해 주세요."); String input = Console.readLine().trim(); validateBlank(input); diff --git a/src/main/java/vendingmachine/view/OutputView.java b/src/main/java/vendingmachine/view/OutputView.java index 9bc5eee1d..7e8e4dca8 100644 --- a/src/main/java/vendingmachine/view/OutputView.java +++ b/src/main/java/vendingmachine/view/OutputView.java @@ -11,6 +11,7 @@ public static void printError(IllegalArgumentException error) { System.out.println(ERROR_PREFIX + error.getMessage()); } public static void printHoldingCoins(Map coinMap) { + System.out.println(); System.out.println("자판기가 보유한 동전"); printCoins(coinMap); } @@ -28,6 +29,7 @@ public static void printCoins(Map coinMap) { } public static void printLeftMoney(int money) { + System.out.println(); System.out.printf("투입 금액: %d원\n", money); } From 4ae70300c8c404827813faa978ad18e988655fbe Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 19:36:19 +0900 Subject: [PATCH 14/25] =?UTF-8?q?feat=20:=20=EC=B6=9C=EB=A0=A5=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=EC=97=90=20?= =?UTF-8?q?=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/VendingMachineController.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index bff46f445..e160a4af8 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -1,14 +1,15 @@ package vendingmachine; +import java.util.function.Consumer; import vendingmachine.view.InputView; import vendingmachine.view.OutputView; public class VendingMachineController { public static void run() { VendingMachine vendingMachine = new VendingMachine(); + initVendingMachineMoney(vendingMachine); initProducts(vendingMachine); - OutputView.printHoldingCoins(vendingMachine.getCoinMap()); initInputMoney(vendingMachine); proceedPurchase(vendingMachine); @@ -18,6 +19,7 @@ private static void initVendingMachineMoney(VendingMachine vendingMachine) { try { Integer money = InputView.readHoldingMoney(); vendingMachine.initMoney(money); + OutputView.printHoldingCoins(vendingMachine.getCoinMap()); } catch (IllegalArgumentException error) { OutputView.printError(error); initVendingMachineMoney(vendingMachine); From 907d0264a1c2b1f867e9ef38dc7f86742f44ec44 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 19:44:04 +0900 Subject: [PATCH 15/25] =?UTF-8?q?feat=20:=20canBuySomething=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 2 +- .../vendingmachine/ProductRepository.java | 8 ------- .../VendingMachineController.java | 1 - .../vendingmachine/ProductRepositoryTest.java | 22 +++++++++++++++++++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/docs/README.md b/docs/README.md index 67f227d61..38d268f22 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,7 +7,7 @@ - [X] : `예외 사항` : 숫자가 아닌 경우 - [X] : `예외 사항` : 음수인 경우 - -- [ ] : 잔돈을 돌려준다. +- [X] : 잔돈을 돌려준다. - [ ] : 남은 금액이 최저 가격보다 적은 경우 - [ ] : 상품이 모두 소진된 경우 - [ ] : 동전으로만 반환한다. diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductRepository.java index be5708a8e..6fb385eca 100644 --- a/src/main/java/vendingmachine/ProductRepository.java +++ b/src/main/java/vendingmachine/ProductRepository.java @@ -42,14 +42,6 @@ private void validateQuantity(int quantity) { } } -// public void addProduct(Product product, int quantity) { -// repository.put(product, repository.getOrDefault(product, 0) + quantity); -// } -// -// private void validate(String input) { -// -// } - public boolean canBuySomething(int money) { return getMinPrice() <= money && getLeftTotalProductCount() > 0; } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index e160a4af8..ec4ccaa83 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -1,6 +1,5 @@ package vendingmachine; -import java.util.function.Consumer; import vendingmachine.view.InputView; import vendingmachine.view.OutputView; diff --git a/src/test/java/vendingmachine/ProductRepositoryTest.java b/src/test/java/vendingmachine/ProductRepositoryTest.java index 7d8e6cb43..b1eda5401 100644 --- a/src/test/java/vendingmachine/ProductRepositoryTest.java +++ b/src/test/java/vendingmachine/ProductRepositoryTest.java @@ -2,11 +2,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Stream; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; public class ProductRepositoryTest { @@ -52,6 +55,25 @@ void initProductsByStringFailWithInvalidMoney(String input) { }).isInstanceOf(IllegalArgumentException.class); } + @DisplayName("상품 구매 가능 여부 확인") + @ParameterizedTest + @MethodSource("canBuySomethingProvider") + void canBuySomething(int leftMoney, boolean expected) { + ProductRepository repository = new ProductRepository(); + repository.initProductsByString("[콜라,1500,20];[사이다,1000,10]"); + Assertions.assertThat(repository.canBuySomething(leftMoney)).isEqualTo(expected); + } + + static Stream canBuySomethingProvider() { + return Stream.of( + Arguments.of(1000, true), + Arguments.of(1500, true), + Arguments.of(2000, true), + Arguments.of(500, false), + Arguments.of(0, false) + ); + } + // @Test // void t() { // String input = "[콜라,1500,20]"; From d74b11aaeb0f2e5e433fae2a6caf64998bd00f69 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 19:53:35 +0900 Subject: [PATCH 16/25] =?UTF-8?q?feat=20:=20=EC=83=81=ED=92=88=20=EA=B5=AC?= =?UTF-8?q?=EB=A7=A4=EC=97=90=20=EB=8C=80=ED=95=9C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 14 +++---- .../vendingmachine/VendingMachineTest.java | 39 +++++++++++++++++++ 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/docs/README.md b/docs/README.md index 38d268f22..9dbd11c0c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,18 +8,18 @@ - [X] : `예외 사항` : 음수인 경우 - - [X] : 잔돈을 돌려준다. - - [ ] : 남은 금액이 최저 가격보다 적은 경우 - - [ ] : 상품이 모두 소진된 경우 - - [ ] : 동전으로만 반환한다. - - [ ] : 최소 개수의 동전으로 잔돈을 돌려준다. + - [X] : 남은 금액이 최저 가격보다 적은 경우 + - [X] : 상품이 모두 소진된 경우 + - [X] : 동전으로만 반환한다. + - [X] : 최소 개수의 동전으로 잔돈을 돌려준다. -- [ ] : 반환되지 않은 금액은 자판기에 남는다. +- [X] : 반환되지 않은 금액은 자판기에 남는다. - [X] : 상품을 추가할 수 있는 기능이 있다. - [X] : 상품은 `;` 으로 구분하고 대괄호`[]` 로 묶여 있다. - [X] : 상품명, 가격, 수량 순서대로 쉼표로 구분되어 입력 받는다. - [X] : 상품의 가격은 100원 부터 시작하고 10원으로 나누어 떨어진다. -- [ ] : 예외 발생시 IllegalArgumentException 발생시키고 다시 입력 받는다. - - [ ] : `[ERROR]` 로 시작하는 에러 메시지를 출력한다. +- [X] : 예외 발생시 IllegalArgumentException 발생시키고 다시 입력 받는다. + - [X] : `[ERROR]` 로 시작하는 에러 메시지를 출력한다. diff --git a/src/test/java/vendingmachine/VendingMachineTest.java b/src/test/java/vendingmachine/VendingMachineTest.java index 49a80399c..547829ea5 100644 --- a/src/test/java/vendingmachine/VendingMachineTest.java +++ b/src/test/java/vendingmachine/VendingMachineTest.java @@ -1,6 +1,7 @@ package vendingmachine; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -16,4 +17,42 @@ void initMoneySuccess(int money) { }); } + @DisplayName("남은 금액이 부족한 경우 구매 시 예외 발생") + @ParameterizedTest + @ValueSource(ints = {1500, 2000, 2999}) + void purchaseProductFailWithLackMoney(int money) { + VendingMachine vendingMachine = new VendingMachine(); + vendingMachine.initMoney(0); + + ProductRepository productRepository = new ProductRepository(); + productRepository.initProductsByString("[콜라,1500,1]"); + vendingMachine.initProducts(productRepository); + + vendingMachine.initInputMoney(money); + + vendingMachine.purchaseProduct("콜라"); + + Assertions.assertThatThrownBy(() -> { + vendingMachine.purchaseProduct("콜라"); + }).isInstanceOf(IllegalArgumentException.class); + } + + @DisplayName("상품이 소진된 경우 구매 시 예외 발생") + @Test + void purchaseProductFailWithQuantity() { + VendingMachine vendingMachine = new VendingMachine(); + vendingMachine.initMoney(0); + + ProductRepository productRepository = new ProductRepository(); + productRepository.initProductsByString("[콜라,1500,1]"); + vendingMachine.initProducts(productRepository); + + vendingMachine.initInputMoney(3000); + + vendingMachine.purchaseProduct("콜라"); + + Assertions.assertThatThrownBy(() -> { + vendingMachine.purchaseProduct("콜라"); + }).isInstanceOf(IllegalArgumentException.class); + } } From 9f41bd31fa2f9a9959153a6d025b30ac05a98842 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 20:00:51 +0900 Subject: [PATCH 17/25] =?UTF-8?q?refactor=20:=20=EC=83=81=ED=92=88=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=EC=86=8C=20=EA=B0=9D=EC=B2=B4=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...oductRepository.java => ProductStore.java} | 43 +++++++++---------- .../java/vendingmachine/VendingMachine.java | 16 +++---- .../VendingMachineController.java | 2 +- .../vendingmachine/ProductRepositoryTest.java | 9 ++-- .../vendingmachine/VendingMachineTest.java | 4 +- 5 files changed, 35 insertions(+), 39 deletions(-) rename src/main/java/vendingmachine/{ProductRepository.java => ProductStore.java} (60%) diff --git a/src/main/java/vendingmachine/ProductRepository.java b/src/main/java/vendingmachine/ProductStore.java similarity index 60% rename from src/main/java/vendingmachine/ProductRepository.java rename to src/main/java/vendingmachine/ProductStore.java index 6fb385eca..55fee9e4c 100644 --- a/src/main/java/vendingmachine/ProductRepository.java +++ b/src/main/java/vendingmachine/ProductStore.java @@ -6,34 +6,33 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class ProductRepository { - private Map repository; +public class ProductStore { + private static final String PRODUCT_DELIMITER = ";"; + private static final String PRODUCT_REGEX = "^\\[([^,]+),([0-9]+),([0-9]+)\\]$"; + private static final Pattern PRODUCT_PATTERN = Pattern.compile(PRODUCT_REGEX); + private final Map repository; - public ProductRepository() { + public ProductStore() { repository = new HashMap<>(); } public void initProductsByString(String input) { - String regex = "^\\[([^,]+),([0-9]+),([0-9]+)\\]$"; - - Pattern pattern = Pattern.compile(regex); - - - Arrays.stream(input.split(";")) - .forEach((value) -> { - Matcher matcher = pattern.matcher(value); - if (matcher.find()) { - String item = matcher.group(1); - int price = Integer.parseInt(matcher.group(2)); - int quantity = Integer.parseInt(matcher.group(3)); + Arrays.stream(input.split(PRODUCT_DELIMITER)) + .forEach(this::handleProductByString); + } - Product product = new Product(item, price); - validateQuantity(quantity); - repository.put(product, quantity); - return; - } - throw new IllegalArgumentException("잘못된 상품 입력입니다."); - }); + private void handleProductByString(String value) { + Matcher matcher = PRODUCT_PATTERN.matcher(value); + if (matcher.find()) { + String name = matcher.group(1); + int price = Integer.parseInt(matcher.group(2)); + int quantity = Integer.parseInt(matcher.group(3)); + Product product = new Product(name, price); + validateQuantity(quantity); + repository.put(product, quantity); + return; + } + throw new IllegalArgumentException("잘못된 상품 입력입니다."); } private void validateQuantity(int quantity) { diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index e724d5919..e4ade239b 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -4,18 +4,18 @@ import java.util.Map; public class VendingMachine { - private ProductRepository repository; + private ProductStore productStore; private Map coinMap; private int holdingMoney; public VendingMachine() { - repository = new ProductRepository(); + productStore = new ProductStore(); coinMap = new EnumMap<>(Coin.class); holdingMoney = 0; } - public void initProducts(ProductRepository repository) { - this.repository = repository; + public void initProducts(ProductStore repository) { + this.productStore = repository; } public void initMoney(int money) { @@ -35,7 +35,7 @@ public Map getCoinMap() { } public boolean canPurchaseSomething() { - return repository.canBuySomething(holdingMoney); + return productStore.canBuySomething(holdingMoney); } public void initInputMoney(int inputMoney) { @@ -50,9 +50,9 @@ private static void validateMoney(int money) { } public void purchaseProduct(String productName) { - Product product = repository.findProductByName(productName); + Product product = productStore.findProductByName(productName); validatePurchase(product); - repository.purchaseProduct(product); + productStore.purchaseProduct(product); holdingMoney -= product.getPrice(); } @@ -60,7 +60,7 @@ private void validatePurchase(Product product) { if (product.getPrice() > holdingMoney) { throw new IllegalArgumentException("잔액이 부족합니다."); } - if (repository.getLeftProductCount(product) <= 0) { + if (productStore.getLeftProductCount(product) <= 0) { throw new IllegalArgumentException("재고가 부족합니다."); } } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index ec4ccaa83..8a620608f 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -28,7 +28,7 @@ private static void initVendingMachineMoney(VendingMachine vendingMachine) { private static void initProducts(VendingMachine vendingMachine) { try { String readProduct = InputView.readProduct(); - ProductRepository repository = new ProductRepository(); + ProductStore repository = new ProductStore(); repository.initProductsByString(readProduct); vendingMachine.initProducts(repository); } catch (IllegalArgumentException error) { diff --git a/src/test/java/vendingmachine/ProductRepositoryTest.java b/src/test/java/vendingmachine/ProductRepositoryTest.java index b1eda5401..323e7d9e6 100644 --- a/src/test/java/vendingmachine/ProductRepositoryTest.java +++ b/src/test/java/vendingmachine/ProductRepositoryTest.java @@ -1,23 +1,20 @@ package vendingmachine; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Stream; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; public class ProductRepositoryTest { - ProductRepository repository; + ProductStore repository; @BeforeEach void setUp() { - repository = new ProductRepository(); + repository = new ProductStore(); } @ParameterizedTest @@ -59,7 +56,7 @@ void initProductsByStringFailWithInvalidMoney(String input) { @ParameterizedTest @MethodSource("canBuySomethingProvider") void canBuySomething(int leftMoney, boolean expected) { - ProductRepository repository = new ProductRepository(); + ProductStore repository = new ProductStore(); repository.initProductsByString("[콜라,1500,20];[사이다,1000,10]"); Assertions.assertThat(repository.canBuySomething(leftMoney)).isEqualTo(expected); } diff --git a/src/test/java/vendingmachine/VendingMachineTest.java b/src/test/java/vendingmachine/VendingMachineTest.java index 547829ea5..f2c832a61 100644 --- a/src/test/java/vendingmachine/VendingMachineTest.java +++ b/src/test/java/vendingmachine/VendingMachineTest.java @@ -24,7 +24,7 @@ void purchaseProductFailWithLackMoney(int money) { VendingMachine vendingMachine = new VendingMachine(); vendingMachine.initMoney(0); - ProductRepository productRepository = new ProductRepository(); + ProductStore productRepository = new ProductStore(); productRepository.initProductsByString("[콜라,1500,1]"); vendingMachine.initProducts(productRepository); @@ -43,7 +43,7 @@ void purchaseProductFailWithQuantity() { VendingMachine vendingMachine = new VendingMachine(); vendingMachine.initMoney(0); - ProductRepository productRepository = new ProductRepository(); + ProductStore productRepository = new ProductStore(); productRepository.initProductsByString("[콜라,1500,1]"); vendingMachine.initProducts(productRepository); From 9438b018db8c7ecf2e08bdef79e623ca6408990e Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 20:09:46 +0900 Subject: [PATCH 18/25] =?UTF-8?q?refactor=20:=20CoinStore=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1=EC=9C=BC=EB=A1=9C=20=EC=B1=85?= =?UTF-8?q?=EC=9E=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/CoinStore.java | 50 +++++++++++++++++++ .../java/vendingmachine/VendingMachine.java | 35 +++---------- 2 files changed, 57 insertions(+), 28 deletions(-) create mode 100644 src/main/java/vendingmachine/CoinStore.java diff --git a/src/main/java/vendingmachine/CoinStore.java b/src/main/java/vendingmachine/CoinStore.java new file mode 100644 index 000000000..413a4b627 --- /dev/null +++ b/src/main/java/vendingmachine/CoinStore.java @@ -0,0 +1,50 @@ +package vendingmachine; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.Map; + +public class CoinStore { + private Map repository; + + public CoinStore(Map repository) { + this.repository = repository; + } + + public void addCoinRandomly(int money) { + while (money >= Coin.COIN_10.getAmount()) { + Coin pickedCoin = Coin.getRandomCoin(); + if (money < pickedCoin.getAmount()) { + continue; + } + money -= pickedCoin.getAmount(); + addCoin(pickedCoin); + } + } + + private void addCoin(Coin coin) { + repository.put(coin, repository.getOrDefault(coin, 0) + 1); + } + + public Map getChange(int holdingMoney) { + Map change = new EnumMap<>(Coin.class); + Coin.getCoinOrderedList() + .forEach((coin) -> handleChange(change, coin, holdingMoney)); + return change; + } + + private void handleChange(Map change, Coin coin, int holdingMoney) { + if (repository.get(coin) == null || repository.get(coin) <= 0) { + return; + } + if (holdingMoney >= coin.getAmount()) { + int quantity = Math.min(holdingMoney / coin.getAmount(), repository.get(coin)); + change.put(coin, quantity); + holdingMoney -= coin.getAmount() * quantity; + } + } + + public Map getRepository() { + return Collections.unmodifiableMap(repository); + } +} diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index e4ade239b..46b662998 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -5,12 +5,12 @@ public class VendingMachine { private ProductStore productStore; - private Map coinMap; + private CoinStore coinStore; private int holdingMoney; public VendingMachine() { productStore = new ProductStore(); - coinMap = new EnumMap<>(Coin.class); + coinStore = new CoinStore(new EnumMap<>(Coin.class)); holdingMoney = 0; } @@ -20,18 +20,7 @@ public void initProducts(ProductStore repository) { public void initMoney(int money) { validateMoney(money); - while (money >= Coin.COIN_10.getAmount()) { - Coin pickedCoin = Coin.getRandomCoin(); - if (money < pickedCoin.getAmount()) { - continue; - } - money -= pickedCoin.getAmount(); - coinMap.put(pickedCoin, coinMap.getOrDefault(pickedCoin, 0) + 1); - } - } - - public Map getCoinMap() { - return coinMap; + coinStore.addCoinRandomly(money); } public boolean canPurchaseSomething() { @@ -69,22 +58,12 @@ public int getHoldingMoney() { return holdingMoney; } - public Map getChange() { - Map change = new EnumMap<>(Coin.class); - Coin.getCoinOrderedList() - .forEach((coin) -> handleChange(change, coin)); - return change; + public Map getCoinMap() { + return coinStore.getRepository(); } - private void handleChange(Map change, Coin coin) { - if (coinMap.get(coin) == null || coinMap.get(coin) <= 0) { - return; - } - if (holdingMoney >= coin.getAmount()) { - int quantity = Math.min(holdingMoney / coin.getAmount(), coinMap.get(coin)); - change.put(coin, quantity); - holdingMoney -= coin.getAmount() * quantity; - } + public Map getChange() { + return coinStore.getChange(holdingMoney); } } From db82752bfce57a8da8a1742b61b4d2943585d3fa Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 20:42:52 +0900 Subject: [PATCH 19/25] =?UTF-8?q?refactor=20:=20Money=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=ED=95=98=EB=8A=94=20=EB=B0=A9=EC=8B=9D?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/CoinStore.java | 8 ++--- src/main/java/vendingmachine/Money.java | 35 +++++++++++++++++++ .../java/vendingmachine/VendingMachine.java | 25 +++++-------- .../VendingMachineController.java | 7 ++-- .../vendingmachine/message/ViewMessage.java | 7 ++++ .../java/vendingmachine/view/InputView.java | 29 +++++++++------ .../java/vendingmachine/view/OutputView.java | 5 +-- .../vendingmachine/VendingMachineTest.java | 10 +++--- 8 files changed, 85 insertions(+), 41 deletions(-) create mode 100644 src/main/java/vendingmachine/Money.java create mode 100644 src/main/java/vendingmachine/message/ViewMessage.java diff --git a/src/main/java/vendingmachine/CoinStore.java b/src/main/java/vendingmachine/CoinStore.java index 413a4b627..4dfb5e41b 100644 --- a/src/main/java/vendingmachine/CoinStore.java +++ b/src/main/java/vendingmachine/CoinStore.java @@ -11,13 +11,13 @@ public CoinStore(Map repository) { this.repository = repository; } - public void addCoinRandomly(int money) { - while (money >= Coin.COIN_10.getAmount()) { + public void addCoinRandomly(Money money) { + while (money.isMoreOrEqualThen(Coin.COIN_10.getAmount())) { Coin pickedCoin = Coin.getRandomCoin(); - if (money < pickedCoin.getAmount()) { + if (money.isLessThen(pickedCoin.getAmount())) { continue; } - money -= pickedCoin.getAmount(); + money.minus(pickedCoin.getAmount()); addCoin(pickedCoin); } } diff --git a/src/main/java/vendingmachine/Money.java b/src/main/java/vendingmachine/Money.java new file mode 100644 index 000000000..2ce5fbcb9 --- /dev/null +++ b/src/main/java/vendingmachine/Money.java @@ -0,0 +1,35 @@ +package vendingmachine; + +public class Money { + private int amount; + + public Money(int amount) { + validate(amount); + this.amount = amount; + } + + private void validate(int amount) { + if (amount < 0) { + throw new IllegalArgumentException("음수는 입력할 수 없습니다."); + } + } + + public boolean isMoreOrEqualThen(int amount) { + return this.amount >= amount; + } + + public boolean isLessThen(int amount) { + return this.amount < amount; + } + + public void minus(int amount) { + if (this.amount - amount < 0) { + throw new IllegalArgumentException("잔액이 부족합니다."); + } + this.amount -= amount; + } + + public int getAmount() { + return amount; + } +} diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index 46b662998..d65e539ef 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -6,47 +6,40 @@ public class VendingMachine { private ProductStore productStore; private CoinStore coinStore; - private int holdingMoney; + private Money holdingMoney; public VendingMachine() { productStore = new ProductStore(); coinStore = new CoinStore(new EnumMap<>(Coin.class)); - holdingMoney = 0; + holdingMoney = new Money(0); } public void initProducts(ProductStore repository) { this.productStore = repository; } - public void initMoney(int money) { - validateMoney(money); + public void initMoney(Money money) { coinStore.addCoinRandomly(money); } public boolean canPurchaseSomething() { - return productStore.canBuySomething(holdingMoney); + return productStore.canBuySomething(holdingMoney.getAmount()); } - public void initInputMoney(int inputMoney) { - validateMoney(inputMoney); + public void initInputMoney(Money inputMoney) { holdingMoney = inputMoney; } - private static void validateMoney(int money) { - if (money < 0) { - throw new IllegalArgumentException("음수는 입력할 수 없습니다."); - } - } public void purchaseProduct(String productName) { Product product = productStore.findProductByName(productName); validatePurchase(product); productStore.purchaseProduct(product); - holdingMoney -= product.getPrice(); + holdingMoney.minus(product.getPrice()); } private void validatePurchase(Product product) { - if (product.getPrice() > holdingMoney) { + if (holdingMoney.isLessThen(product.getPrice())) { throw new IllegalArgumentException("잔액이 부족합니다."); } if (productStore.getLeftProductCount(product) <= 0) { @@ -54,7 +47,7 @@ private void validatePurchase(Product product) { } } - public int getHoldingMoney() { + public Money getHoldingMoney() { return holdingMoney; } @@ -63,7 +56,7 @@ public Map getCoinMap() { } public Map getChange() { - return coinStore.getChange(holdingMoney); + return coinStore.getChange(holdingMoney.getAmount()); } } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index 8a620608f..667bc9658 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -1,5 +1,6 @@ package vendingmachine; +import vendingmachine.message.ViewMessage; import vendingmachine.view.InputView; import vendingmachine.view.OutputView; @@ -16,8 +17,8 @@ public static void run() { private static void initVendingMachineMoney(VendingMachine vendingMachine) { try { - Integer money = InputView.readHoldingMoney(); - vendingMachine.initMoney(money); + Money holdingMoney = new Money(InputView.readInteger(ViewMessage.INPUT_HOLDING_MONEY)); + vendingMachine.initMoney(holdingMoney); OutputView.printHoldingCoins(vendingMachine.getCoinMap()); } catch (IllegalArgumentException error) { OutputView.printError(error); @@ -39,7 +40,7 @@ private static void initProducts(VendingMachine vendingMachine) { private static void initInputMoney(VendingMachine vendingMachine) { try { - int inputMoney = InputView.readInputMoney(); + Money inputMoney = new Money(InputView.readInteger(ViewMessage.INPUT_PURCHASE_MONEY)); vendingMachine.initInputMoney(inputMoney); } catch (IllegalArgumentException error) { OutputView.printError(error); diff --git a/src/main/java/vendingmachine/message/ViewMessage.java b/src/main/java/vendingmachine/message/ViewMessage.java new file mode 100644 index 000000000..66a1c8d98 --- /dev/null +++ b/src/main/java/vendingmachine/message/ViewMessage.java @@ -0,0 +1,7 @@ +package vendingmachine.message; + +public class ViewMessage { + public static final String INPUT_HOLDING_MONEY = "자판기가 보유하고 있는 금액을 입력해 주세요."; + public static final String INPUT_PURCHASE_MONEY = "투입 금액을 입력해 주세요."; + public static final String INPUT_PRODUCT = "상품명과 가격, 수량을 입력해 주세요."; +} diff --git a/src/main/java/vendingmachine/view/InputView.java b/src/main/java/vendingmachine/view/InputView.java index 130427bfe..2c648d213 100644 --- a/src/main/java/vendingmachine/view/InputView.java +++ b/src/main/java/vendingmachine/view/InputView.java @@ -1,14 +1,29 @@ package vendingmachine.view; import camp.nextstep.edu.missionutils.Console; +import vendingmachine.message.ViewMessage; public class InputView { - public static final String INPUT_MONEY = "자판기가 보유하고 있는 금액을 입력해 주세요."; - public static final String INPUT_PRODUCT = "상품명과 가격, 수량을 입력해 주세요."; + + + public static String readString(String message) { + System.out.println(message); + String input = Console.readLine().trim(); + validateBlank(input); + return input; + } + + public static int readInteger(String message) { + System.out.println(message); + String input = Console.readLine().trim(); + validateBlank(input); + validateInteger(input); + return Integer.parseInt(input); + } public static String readProduct() { - System.out.println(INPUT_PRODUCT); + System.out.println(ViewMessage.INPUT_PRODUCT); String input = Console.readLine().trim(); validateBlank(input); return input; @@ -19,14 +34,6 @@ private static void validateBlank(String input) { throw new IllegalArgumentException("입력값이 없습니다."); } } - // TODO 비즈니스 로직 분리 - public static Integer readHoldingMoney() { - System.out.println(INPUT_MONEY); - String input = Console.readLine().trim(); - validateBlank(input); - validateInteger(input); - return Integer.parseInt(input); - } private static void validateInteger(String input) { try { diff --git a/src/main/java/vendingmachine/view/OutputView.java b/src/main/java/vendingmachine/view/OutputView.java index 7e8e4dca8..8b87f4f71 100644 --- a/src/main/java/vendingmachine/view/OutputView.java +++ b/src/main/java/vendingmachine/view/OutputView.java @@ -2,6 +2,7 @@ import java.util.Map; import vendingmachine.Coin; +import vendingmachine.Money; public class OutputView { @@ -28,9 +29,9 @@ public static void printCoins(Map coinMap) { System.out.println(); } - public static void printLeftMoney(int money) { + public static void printLeftMoney(Money money) { System.out.println(); - System.out.printf("투입 금액: %d원\n", money); + System.out.printf("투입 금액: %d원\n", money.getAmount()); } diff --git a/src/test/java/vendingmachine/VendingMachineTest.java b/src/test/java/vendingmachine/VendingMachineTest.java index f2c832a61..37f7037b1 100644 --- a/src/test/java/vendingmachine/VendingMachineTest.java +++ b/src/test/java/vendingmachine/VendingMachineTest.java @@ -13,7 +13,7 @@ public class VendingMachineTest { void initMoneySuccess(int money) { Assertions.assertThatNoException().isThrownBy(() -> { VendingMachine vendingMachine = new VendingMachine(); - vendingMachine.initMoney(money); + vendingMachine.initMoney(new Money(money)); }); } @@ -22,13 +22,13 @@ void initMoneySuccess(int money) { @ValueSource(ints = {1500, 2000, 2999}) void purchaseProductFailWithLackMoney(int money) { VendingMachine vendingMachine = new VendingMachine(); - vendingMachine.initMoney(0); + vendingMachine.initMoney(new Money(0)); ProductStore productRepository = new ProductStore(); productRepository.initProductsByString("[콜라,1500,1]"); vendingMachine.initProducts(productRepository); - vendingMachine.initInputMoney(money); + vendingMachine.initInputMoney(new Money(money)); vendingMachine.purchaseProduct("콜라"); @@ -41,13 +41,13 @@ void purchaseProductFailWithLackMoney(int money) { @Test void purchaseProductFailWithQuantity() { VendingMachine vendingMachine = new VendingMachine(); - vendingMachine.initMoney(0); + vendingMachine.initMoney(new Money(0)); ProductStore productRepository = new ProductStore(); productRepository.initProductsByString("[콜라,1500,1]"); vendingMachine.initProducts(productRepository); - vendingMachine.initInputMoney(3000); + vendingMachine.initInputMoney(new Money(3000)); vendingMachine.purchaseProduct("콜라"); From 342980db166d0177427224056ccf408c3a0c2219 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 20:46:04 +0900 Subject: [PATCH 20/25] =?UTF-8?q?refactor=20:=20=EA=B0=80=EB=8F=85?= =?UTF-8?q?=EC=84=B1=20=EC=A2=8B=EA=B2=8C=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=88=9C=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/CoinStore.java | 2 +- .../java/vendingmachine/ProductStore.java | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/vendingmachine/CoinStore.java b/src/main/java/vendingmachine/CoinStore.java index 4dfb5e41b..066ffd37c 100644 --- a/src/main/java/vendingmachine/CoinStore.java +++ b/src/main/java/vendingmachine/CoinStore.java @@ -5,7 +5,7 @@ import java.util.Map; public class CoinStore { - private Map repository; + private final Map repository; public CoinStore(Map repository) { this.repository = repository; diff --git a/src/main/java/vendingmachine/ProductStore.java b/src/main/java/vendingmachine/ProductStore.java index 55fee9e4c..fb495c6be 100644 --- a/src/main/java/vendingmachine/ProductStore.java +++ b/src/main/java/vendingmachine/ProductStore.java @@ -45,18 +45,6 @@ public boolean canBuySomething(int money) { return getMinPrice() <= money && getLeftTotalProductCount() > 0; } - public Product findProductByName(String name) { - return repository.keySet() - .stream() - .filter((product) -> product.getName().equals(name)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("상품이 없습니다.")); - } - - public void purchaseProduct(Product product) { - repository.put(product, repository.get(product) - 1); - } - private int getMinPrice() { return repository.keySet() .stream() @@ -72,6 +60,18 @@ private int getLeftTotalProductCount() { .sum(); } + public Product findProductByName(String name) { + return repository.keySet() + .stream() + .filter((product) -> product.getName().equals(name)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("상품이 없습니다.")); + } + + public void purchaseProduct(Product product) { + repository.put(product, repository.get(product) - 1); + } + public int getLeftProductCount(Product product) { return repository.get(product); } From eec33d560dc8193eeba00b41395c0f5ceeb184d3 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 21:01:10 +0900 Subject: [PATCH 21/25] =?UTF-8?q?refactor=20:=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=20=EC=83=81=EC=88=98=ED=99=94=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/Coin.java | 4 +-- src/main/java/vendingmachine/Money.java | 6 ++-- src/main/java/vendingmachine/Product.java | 8 +++-- .../java/vendingmachine/ProductStore.java | 9 +++--- .../java/vendingmachine/VendingMachine.java | 5 +-- .../VendingMachineController.java | 10 +++--- .../message/ExceptionMessage.java | 13 ++++++++ .../vendingmachine/message/ViewMessage.java | 8 ++++- .../java/vendingmachine/view/InputView.java | 32 ++----------------- .../java/vendingmachine/view/OutputView.java | 17 ++++------ 10 files changed, 55 insertions(+), 57 deletions(-) create mode 100644 src/main/java/vendingmachine/message/ExceptionMessage.java diff --git a/src/main/java/vendingmachine/Coin.java b/src/main/java/vendingmachine/Coin.java index 29b854a9e..95a961278 100644 --- a/src/main/java/vendingmachine/Coin.java +++ b/src/main/java/vendingmachine/Coin.java @@ -4,13 +4,13 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import vendingmachine.message.ExceptionMessage; public enum Coin { COIN_500(500), COIN_100(100), COIN_50(50), COIN_10(10); - private final int amount; Coin(final int amount) { @@ -29,7 +29,7 @@ private static Coin findByAmount(int amount) { return Arrays.stream(Coin.values()) .filter(coin -> coin.amount == amount) .findFirst() - .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 동전입니다.")); + .orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.INVALID_COIN)); } public static List getCoinOrderedList() { diff --git a/src/main/java/vendingmachine/Money.java b/src/main/java/vendingmachine/Money.java index 2ce5fbcb9..e79fa7fea 100644 --- a/src/main/java/vendingmachine/Money.java +++ b/src/main/java/vendingmachine/Money.java @@ -1,5 +1,7 @@ package vendingmachine; +import vendingmachine.message.ExceptionMessage; + public class Money { private int amount; @@ -10,7 +12,7 @@ public Money(int amount) { private void validate(int amount) { if (amount < 0) { - throw new IllegalArgumentException("음수는 입력할 수 없습니다."); + throw new IllegalArgumentException(ExceptionMessage.NUMBER_FORMAT); } } @@ -24,7 +26,7 @@ public boolean isLessThen(int amount) { public void minus(int amount) { if (this.amount - amount < 0) { - throw new IllegalArgumentException("잔액이 부족합니다."); + throw new IllegalArgumentException(ExceptionMessage.LACK_MONEY); } this.amount -= amount; } diff --git a/src/main/java/vendingmachine/Product.java b/src/main/java/vendingmachine/Product.java index 00df9969d..d7e2d27c1 100644 --- a/src/main/java/vendingmachine/Product.java +++ b/src/main/java/vendingmachine/Product.java @@ -1,5 +1,7 @@ package vendingmachine; +import vendingmachine.message.ExceptionMessage; + public class Product { public static final int MIN_PRICE = 100; private String name; @@ -18,16 +20,16 @@ private void validate(String name, int price) { private void validateName(String name) { if (name == null || name.isEmpty()) { - throw new IllegalArgumentException("상품의 이름은 null이거나 빈 문자열일 수 없습니다."); + throw new IllegalArgumentException(ExceptionMessage.BLANK); } } private void validatePrice(int price) { if (price < MIN_PRICE) { - throw new IllegalArgumentException("상품의 가격은 100원 이상이어야 합니다."); + throw new IllegalArgumentException(ExceptionMessage.INVALID_PRODUCT_PRICE); } if (price % 10 != 0) { - throw new IllegalArgumentException("상품의 가격은 10원 단위여야 합니다."); + throw new IllegalArgumentException(ExceptionMessage.INVALID_PRODUCT_PRICE); } } diff --git a/src/main/java/vendingmachine/ProductStore.java b/src/main/java/vendingmachine/ProductStore.java index fb495c6be..46fc1c643 100644 --- a/src/main/java/vendingmachine/ProductStore.java +++ b/src/main/java/vendingmachine/ProductStore.java @@ -5,6 +5,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import vendingmachine.message.ExceptionMessage; public class ProductStore { private static final String PRODUCT_DELIMITER = ";"; @@ -32,12 +33,12 @@ private void handleProductByString(String value) { repository.put(product, quantity); return; } - throw new IllegalArgumentException("잘못된 상품 입력입니다."); + throw new IllegalArgumentException(ExceptionMessage.INVALID_PRODUCT_NAME); } private void validateQuantity(int quantity) { if (quantity <= 0) { - throw new IllegalArgumentException("잘못된 수량입니다."); + throw new IllegalArgumentException(ExceptionMessage.LACK_QUANTITY); } } @@ -50,7 +51,7 @@ private int getMinPrice() { .stream() .mapToInt(Product::getPrice) .min() - .orElseThrow(() -> new IllegalArgumentException("상품이 없습니다.")); + .orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.INVALID_PRODUCT_NAME)); } private int getLeftTotalProductCount() { @@ -65,7 +66,7 @@ public Product findProductByName(String name) { .stream() .filter((product) -> product.getName().equals(name)) .findFirst() - .orElseThrow(() -> new IllegalArgumentException("상품이 없습니다.")); + .orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.INVALID_PRODUCT_NAME)); } public void purchaseProduct(Product product) { diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index d65e539ef..75f23431b 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -2,6 +2,7 @@ import java.util.EnumMap; import java.util.Map; +import vendingmachine.message.ExceptionMessage; public class VendingMachine { private ProductStore productStore; @@ -40,10 +41,10 @@ public void purchaseProduct(String productName) { private void validatePurchase(Product product) { if (holdingMoney.isLessThen(product.getPrice())) { - throw new IllegalArgumentException("잔액이 부족합니다."); + throw new IllegalArgumentException(ExceptionMessage.LACK_MONEY); } if (productStore.getLeftProductCount(product) <= 0) { - throw new IllegalArgumentException("재고가 부족합니다."); + throw new IllegalArgumentException(ExceptionMessage.LACK_QUANTITY); } } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index 667bc9658..849f351f9 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -17,7 +17,8 @@ public static void run() { private static void initVendingMachineMoney(VendingMachine vendingMachine) { try { - Money holdingMoney = new Money(InputView.readInteger(ViewMessage.INPUT_HOLDING_MONEY)); + int holdMoneyAmount = InputView.readInteger(ViewMessage.INPUT_HOLDING_MONEY); + Money holdingMoney = new Money(holdMoneyAmount); vendingMachine.initMoney(holdingMoney); OutputView.printHoldingCoins(vendingMachine.getCoinMap()); } catch (IllegalArgumentException error) { @@ -28,7 +29,7 @@ private static void initVendingMachineMoney(VendingMachine vendingMachine) { private static void initProducts(VendingMachine vendingMachine) { try { - String readProduct = InputView.readProduct(); + String readProduct = InputView.readString(ViewMessage.INPUT_PRODUCT); ProductStore repository = new ProductStore(); repository.initProductsByString(readProduct); vendingMachine.initProducts(repository); @@ -40,7 +41,8 @@ private static void initProducts(VendingMachine vendingMachine) { private static void initInputMoney(VendingMachine vendingMachine) { try { - Money inputMoney = new Money(InputView.readInteger(ViewMessage.INPUT_PURCHASE_MONEY)); + int insertedMoneyAmount = InputView.readInteger(ViewMessage.INPUT_INSERTED_MONEY); + Money inputMoney = new Money(insertedMoneyAmount); vendingMachine.initInputMoney(inputMoney); } catch (IllegalArgumentException error) { OutputView.printError(error); @@ -51,7 +53,7 @@ private static void initInputMoney(VendingMachine vendingMachine) { private static void proceedPurchase(VendingMachine vendingMachine) { while (vendingMachine.canPurchaseSomething()) { OutputView.printLeftMoney(vendingMachine.getHoldingMoney()); - String product = InputView.readPurchaseProduct(); + String product = InputView.readString(ViewMessage.INPUT_PURCHASE_PRODUCT); vendingMachine.purchaseProduct(product); } OutputView.printLeftMoney(vendingMachine.getHoldingMoney()); diff --git a/src/main/java/vendingmachine/message/ExceptionMessage.java b/src/main/java/vendingmachine/message/ExceptionMessage.java new file mode 100644 index 000000000..f7711f5d8 --- /dev/null +++ b/src/main/java/vendingmachine/message/ExceptionMessage.java @@ -0,0 +1,13 @@ +package vendingmachine.message; + +public class ExceptionMessage { + public static final String ERROR_PREFIX = "[ERROR] : "; + + public static final String BLANK = "입력값이 없습니다."; + public static final String LACK_MONEY = "잔액이 부족합니다."; + public static final String LACK_QUANTITY = "재고가 부족합니다."; + public static final String NUMBER_FORMAT = "금액은 0 이상의 숫자여야 합니다."; + public static final String INVALID_COIN = "존재하지 않는 동전입니다."; + public static final String INVALID_PRODUCT_PRICE = "상품의 가격은 100원 이상이고 10원 단위여야 합니다."; + public static final String INVALID_PRODUCT_NAME = "잘못된 상품 입력입니다."; +} diff --git a/src/main/java/vendingmachine/message/ViewMessage.java b/src/main/java/vendingmachine/message/ViewMessage.java index 66a1c8d98..b259a9804 100644 --- a/src/main/java/vendingmachine/message/ViewMessage.java +++ b/src/main/java/vendingmachine/message/ViewMessage.java @@ -2,6 +2,12 @@ public class ViewMessage { public static final String INPUT_HOLDING_MONEY = "자판기가 보유하고 있는 금액을 입력해 주세요."; - public static final String INPUT_PURCHASE_MONEY = "투입 금액을 입력해 주세요."; + public static final String INPUT_INSERTED_MONEY = "투입 금액을 입력해 주세요."; public static final String INPUT_PRODUCT = "상품명과 가격, 수량을 입력해 주세요."; + public static final String INPUT_PURCHASE_PRODUCT = "구매할 상품명을 입력해 주세요."; + + public static final String OUTPUT_HOLDING_COIN_PRE_MESSAGE = "자판기가 보유한 동전"; + public static final String OUTPUT_CHANGE = "잔돈"; + public static final String OUTPUT_COIN_FORMAT = "%d원 - %d개\n"; + public static final String OUTPUT_MONEY_FORMAT = "투입 금액: %d원\n"; } diff --git a/src/main/java/vendingmachine/view/InputView.java b/src/main/java/vendingmachine/view/InputView.java index 2c648d213..a0669da9b 100644 --- a/src/main/java/vendingmachine/view/InputView.java +++ b/src/main/java/vendingmachine/view/InputView.java @@ -1,12 +1,9 @@ package vendingmachine.view; import camp.nextstep.edu.missionutils.Console; -import vendingmachine.message.ViewMessage; +import vendingmachine.message.ExceptionMessage; public class InputView { - - - public static String readString(String message) { System.out.println(message); String input = Console.readLine().trim(); @@ -22,16 +19,9 @@ public static int readInteger(String message) { return Integer.parseInt(input); } - public static String readProduct() { - System.out.println(ViewMessage.INPUT_PRODUCT); - String input = Console.readLine().trim(); - validateBlank(input); - return input; - } - private static void validateBlank(String input) { if (input == null || input.isEmpty()) { - throw new IllegalArgumentException("입력값이 없습니다."); + throw new IllegalArgumentException(ExceptionMessage.BLANK); } } @@ -39,23 +29,7 @@ private static void validateInteger(String input) { try { Integer.parseInt(input); } catch (NumberFormatException error) { - throw new IllegalArgumentException("금액은 숫자여야 합니다."); + throw new IllegalArgumentException(ExceptionMessage.NUMBER_FORMAT); } } - - public static Integer readInputMoney() { - System.out.println(); - System.out.println("투입할 금액을 입력해 주세요."); - String input = Console.readLine().trim(); - validateBlank(input); - validateInteger(input); - return Integer.parseInt(input); - } - - public static String readPurchaseProduct() { - System.out.println("구매할 상품명을 입력해 주세요."); - String input = Console.readLine().trim(); - validateBlank(input); - return input; - } } diff --git a/src/main/java/vendingmachine/view/OutputView.java b/src/main/java/vendingmachine/view/OutputView.java index 8b87f4f71..6a6a105bd 100644 --- a/src/main/java/vendingmachine/view/OutputView.java +++ b/src/main/java/vendingmachine/view/OutputView.java @@ -3,36 +3,33 @@ import java.util.Map; import vendingmachine.Coin; import vendingmachine.Money; +import vendingmachine.message.ExceptionMessage; +import vendingmachine.message.ViewMessage; public class OutputView { - - public static final String ERROR_PREFIX = "[ERROR] : "; - public static void printError(IllegalArgumentException error) { - System.out.println(ERROR_PREFIX + error.getMessage()); + System.out.println(ExceptionMessage.ERROR_PREFIX + error.getMessage()); } public static void printHoldingCoins(Map coinMap) { System.out.println(); - System.out.println("자판기가 보유한 동전"); + System.out.println(ViewMessage.OUTPUT_HOLDING_COIN_PRE_MESSAGE); printCoins(coinMap); } public static void printChangeCoins(Map coinMap) { - System.out.println("잔돈"); + System.out.println(ViewMessage.OUTPUT_CHANGE); printCoins(coinMap); } public static void printCoins(Map coinMap) { Coin.getCoinOrderedList().forEach((coin) -> { - System.out.println(coin.getAmount() + "원 - " + coinMap.getOrDefault(coin, 0) + "개"); + System.out.printf(ViewMessage.OUTPUT_COIN_FORMAT, coin.getAmount(), coinMap.getOrDefault(coin, 0)); }); System.out.println(); } public static void printLeftMoney(Money money) { System.out.println(); - System.out.printf("투입 금액: %d원\n", money.getAmount()); + System.out.printf(ViewMessage.OUTPUT_MONEY_FORMAT, money.getAmount()); } - - } From 40f93b20654a75d120a8ec5a66b65755fd313e13 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 21:04:42 +0900 Subject: [PATCH 22/25] =?UTF-8?q?refactor=20:=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/VendingMachine.java | 2 +- src/main/java/vendingmachine/VendingMachineController.java | 2 +- src/main/java/vendingmachine/message/ExceptionMessage.java | 2 +- src/test/java/vendingmachine/VendingMachineTest.java | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index 75f23431b..4186b75e6 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -19,7 +19,7 @@ public void initProducts(ProductStore repository) { this.productStore = repository; } - public void initMoney(Money money) { + public void initHoldingMoney(Money money) { coinStore.addCoinRandomly(money); } diff --git a/src/main/java/vendingmachine/VendingMachineController.java b/src/main/java/vendingmachine/VendingMachineController.java index 849f351f9..2405be3b7 100644 --- a/src/main/java/vendingmachine/VendingMachineController.java +++ b/src/main/java/vendingmachine/VendingMachineController.java @@ -19,7 +19,7 @@ private static void initVendingMachineMoney(VendingMachine vendingMachine) { try { int holdMoneyAmount = InputView.readInteger(ViewMessage.INPUT_HOLDING_MONEY); Money holdingMoney = new Money(holdMoneyAmount); - vendingMachine.initMoney(holdingMoney); + vendingMachine.initHoldingMoney(holdingMoney); OutputView.printHoldingCoins(vendingMachine.getCoinMap()); } catch (IllegalArgumentException error) { OutputView.printError(error); diff --git a/src/main/java/vendingmachine/message/ExceptionMessage.java b/src/main/java/vendingmachine/message/ExceptionMessage.java index f7711f5d8..d010367e1 100644 --- a/src/main/java/vendingmachine/message/ExceptionMessage.java +++ b/src/main/java/vendingmachine/message/ExceptionMessage.java @@ -6,7 +6,7 @@ public class ExceptionMessage { public static final String BLANK = "입력값이 없습니다."; public static final String LACK_MONEY = "잔액이 부족합니다."; public static final String LACK_QUANTITY = "재고가 부족합니다."; - public static final String NUMBER_FORMAT = "금액은 0 이상의 숫자여야 합니다."; + public static final String NUMBER_FORMAT = "금액은 숫자여야 합니다."; public static final String INVALID_COIN = "존재하지 않는 동전입니다."; public static final String INVALID_PRODUCT_PRICE = "상품의 가격은 100원 이상이고 10원 단위여야 합니다."; public static final String INVALID_PRODUCT_NAME = "잘못된 상품 입력입니다."; diff --git a/src/test/java/vendingmachine/VendingMachineTest.java b/src/test/java/vendingmachine/VendingMachineTest.java index 37f7037b1..eaa588fcd 100644 --- a/src/test/java/vendingmachine/VendingMachineTest.java +++ b/src/test/java/vendingmachine/VendingMachineTest.java @@ -13,7 +13,7 @@ public class VendingMachineTest { void initMoneySuccess(int money) { Assertions.assertThatNoException().isThrownBy(() -> { VendingMachine vendingMachine = new VendingMachine(); - vendingMachine.initMoney(new Money(money)); + vendingMachine.initHoldingMoney(new Money(money)); }); } @@ -22,7 +22,7 @@ void initMoneySuccess(int money) { @ValueSource(ints = {1500, 2000, 2999}) void purchaseProductFailWithLackMoney(int money) { VendingMachine vendingMachine = new VendingMachine(); - vendingMachine.initMoney(new Money(0)); + vendingMachine.initHoldingMoney(new Money(0)); ProductStore productRepository = new ProductStore(); productRepository.initProductsByString("[콜라,1500,1]"); @@ -41,7 +41,7 @@ void purchaseProductFailWithLackMoney(int money) { @Test void purchaseProductFailWithQuantity() { VendingMachine vendingMachine = new VendingMachine(); - vendingMachine.initMoney(new Money(0)); + vendingMachine.initHoldingMoney(new Money(0)); ProductStore productRepository = new ProductStore(); productRepository.initProductsByString("[콜라,1500,1]"); From 4e631d58d73b10e6044fafa8725b2d90b48639a9 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 21:23:10 +0900 Subject: [PATCH 23/25] =?UTF-8?q?fix=20:=20=EC=9E=94=EB=8F=88=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=EC=9D=B4=ED=9B=84=20=EB=8F=99=EC=A0=84=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98=20=EB=B0=8F=20=EB=B3=B4=EC=9C=A0=20=EA=B8=88=EC=95=A1?= =?UTF-8?q?=20=EB=B3=80=ED=99=94=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/CoinStore.java | 11 ++++++----- src/main/java/vendingmachine/VendingMachine.java | 2 +- src/test/java/vendingmachine/ApplicationTest.java | 14 ++++++++++++++ .../java/vendingmachine/VendingMachineTest.java | 2 +- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main/java/vendingmachine/CoinStore.java b/src/main/java/vendingmachine/CoinStore.java index 066ffd37c..9bc12e89a 100644 --- a/src/main/java/vendingmachine/CoinStore.java +++ b/src/main/java/vendingmachine/CoinStore.java @@ -26,21 +26,22 @@ private void addCoin(Coin coin) { repository.put(coin, repository.getOrDefault(coin, 0) + 1); } - public Map getChange(int holdingMoney) { + public Map getChange(Money holdingMoney) { Map change = new EnumMap<>(Coin.class); Coin.getCoinOrderedList() .forEach((coin) -> handleChange(change, coin, holdingMoney)); return change; } - private void handleChange(Map change, Coin coin, int holdingMoney) { + private void handleChange(Map change, Coin coin, Money holdingMoney) { if (repository.get(coin) == null || repository.get(coin) <= 0) { return; } - if (holdingMoney >= coin.getAmount()) { - int quantity = Math.min(holdingMoney / coin.getAmount(), repository.get(coin)); + if (holdingMoney.getAmount() >= coin.getAmount()) { + int quantity = Math.min(holdingMoney.getAmount() / coin.getAmount(), repository.get(coin)); change.put(coin, quantity); - holdingMoney -= coin.getAmount() * quantity; + repository.put(coin, repository.get(coin) - quantity); + holdingMoney.minus(coin.getAmount() * quantity); } } diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index 4186b75e6..fde87c6f6 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -57,7 +57,7 @@ public Map getCoinMap() { } public Map getChange() { - return coinStore.getChange(holdingMoney.getAmount()); + return coinStore.getChange(holdingMoney); } } diff --git a/src/test/java/vendingmachine/ApplicationTest.java b/src/test/java/vendingmachine/ApplicationTest.java index 4bec0f51e..ad2488075 100644 --- a/src/test/java/vendingmachine/ApplicationTest.java +++ b/src/test/java/vendingmachine/ApplicationTest.java @@ -24,6 +24,20 @@ class ApplicationTest extends NsTest { ); } + @Test + void 기능_테스트_구매_불가() { + assertRandomNumberInListTest( + () -> { + run("500", "[콜라,1500,20];[사이다,1000,10]", "900"); + assertThat(output()).contains( + "자판기가 보유한 동전", "500원 - 1개", "100원 - 0개", "50원 - 0개", "10원 - 0개", + "투입 금액: 900", "잔돈" + ); + }, + 500 + ); + } + @Test void 예외_테스트() { assertSimpleTest( diff --git a/src/test/java/vendingmachine/VendingMachineTest.java b/src/test/java/vendingmachine/VendingMachineTest.java index eaa588fcd..79fecbb97 100644 --- a/src/test/java/vendingmachine/VendingMachineTest.java +++ b/src/test/java/vendingmachine/VendingMachineTest.java @@ -41,7 +41,7 @@ void purchaseProductFailWithLackMoney(int money) { @Test void purchaseProductFailWithQuantity() { VendingMachine vendingMachine = new VendingMachine(); - vendingMachine.initHoldingMoney(new Money(0)); + vendingMachine.initHoldingMoney(new Money(100)); ProductStore productRepository = new ProductStore(); productRepository.initProductsByString("[콜라,1500,1]"); From 567a6ec37ef39d3791a9fdff9f7aea3399f94a33 Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 21:27:06 +0900 Subject: [PATCH 24/25] =?UTF-8?q?refactor=20:=20=EB=B3=80=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=9D=B8=EC=8A=A4=ED=84=B4?= =?UTF-8?q?=EC=8A=A4=20=EB=B3=80=EC=88=98=EB=8A=94=20final=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/Coin.java | 1 + src/main/java/vendingmachine/Product.java | 4 ++-- src/main/java/vendingmachine/VendingMachine.java | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/vendingmachine/Coin.java b/src/main/java/vendingmachine/Coin.java index 95a961278..c5b5ae362 100644 --- a/src/main/java/vendingmachine/Coin.java +++ b/src/main/java/vendingmachine/Coin.java @@ -11,6 +11,7 @@ public enum Coin { COIN_100(100), COIN_50(50), COIN_10(10); + private final int amount; Coin(final int amount) { diff --git a/src/main/java/vendingmachine/Product.java b/src/main/java/vendingmachine/Product.java index d7e2d27c1..e602536e7 100644 --- a/src/main/java/vendingmachine/Product.java +++ b/src/main/java/vendingmachine/Product.java @@ -4,8 +4,8 @@ public class Product { public static final int MIN_PRICE = 100; - private String name; - private int price; + private final String name; + private final int price; public Product(String name, int price) { validate(name, price); diff --git a/src/main/java/vendingmachine/VendingMachine.java b/src/main/java/vendingmachine/VendingMachine.java index fde87c6f6..4a361a329 100644 --- a/src/main/java/vendingmachine/VendingMachine.java +++ b/src/main/java/vendingmachine/VendingMachine.java @@ -5,8 +5,8 @@ import vendingmachine.message.ExceptionMessage; public class VendingMachine { + private final CoinStore coinStore; private ProductStore productStore; - private CoinStore coinStore; private Money holdingMoney; public VendingMachine() { From 20e116bfaefe82022a1b149c934638ffdf70794d Mon Sep 17 00:00:00 2001 From: jhon3242 Date: Mon, 20 Nov 2023 21:31:00 +0900 Subject: [PATCH 25/25] =?UTF-8?q?refactor=20:=20=EB=A7=A4=EC=A7=81?= =?UTF-8?q?=EB=84=98=EB=B2=84=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/vendingmachine/ProductStore.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/vendingmachine/ProductStore.java b/src/main/java/vendingmachine/ProductStore.java index 46fc1c643..fd18f0038 100644 --- a/src/main/java/vendingmachine/ProductStore.java +++ b/src/main/java/vendingmachine/ProductStore.java @@ -11,6 +11,10 @@ public class ProductStore { private static final String PRODUCT_DELIMITER = ";"; private static final String PRODUCT_REGEX = "^\\[([^,]+),([0-9]+),([0-9]+)\\]$"; private static final Pattern PRODUCT_PATTERN = Pattern.compile(PRODUCT_REGEX); + private static final int NAME_INDEX = 1; + private static final int PRICE_INDEX = 2; + private static final int QUANTITY_INDEX = 3; + private final Map repository; public ProductStore() { @@ -25,9 +29,9 @@ public void initProductsByString(String input) { private void handleProductByString(String value) { Matcher matcher = PRODUCT_PATTERN.matcher(value); if (matcher.find()) { - String name = matcher.group(1); - int price = Integer.parseInt(matcher.group(2)); - int quantity = Integer.parseInt(matcher.group(3)); + String name = matcher.group(NAME_INDEX); + int price = Integer.parseInt(matcher.group(PRICE_INDEX)); + int quantity = Integer.parseInt(matcher.group(QUANTITY_INDEX)); Product product = new Product(name, price); validateQuantity(quantity); repository.put(product, quantity);