Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 🥫 Flow
1. 자판기가 보유하고 있는 금액 입력
- 입력받은 금액으로 무작위하게 동전 생성
- **10원 단위로 입력을 받으며, 아닐 경우에 예외 발생**
- **숫자가 아닌 입력인 경우, 예외 발생**
</br></br>
2. 자판기가 보유한 동전 출력
</br></br>
3. 상품 입력
- **상품 가격은 100원부터 시작하며, 10원 단위가 아닐 경우 예외 발생**
- **중복된 상품이 있을 경우 예외 발생**
- **형식이 맞지 않을 경우 예외 발생**
</br></br>
4. 투입 금액 입력
- 남은 금액이 상품의 최저 가격보다 적거나, 모든 상품이 소진된 경우 잔돈을 출력하고 종료
- 잔돈을 반환할 수 없는 경우 잔돈으로 반환할 수 있는 금액을 출력하고 종료

# 📋 요구사항 분석
- 자판기 보유 금액 입력
- [X] 금액 입력받기
- [X] 입력받은 금액으로 무작위하게 동전 생성
- [X] 10원 단위 입력이 아닌 경우, 예외 처리
- [X] 숫자가 아닌 입력인 경우, 예외 처리
- [X] 0 또는 음수인 경우, 예외 발생
</br></br>
- 자판기가 보유한 동전 출력
- [X] 자판기기 보유한 동전 출력
</br></br>
- 상품 입력받기
- [X] 상품 입력받기
- [X] 상품 가격이 100원 이상이 아닌 경우, 예외 발생
- [X] 10원 단위가 아닌 경우, 예외 발생
- [X] 중복된 상품이 있는 경우, 예외 발생
- [X] 형식이 맞지 않는 경우, 예외 발생
- [X] 0 또는 음수인 경우, 예외 발생
</br></br>
- 투입 금액 입력
- [X] 투입 금액 입력받기
- [X] 0 또는 음수인 경우, 예외 발생
- [X] 남은 금액이 최저 가격보다 적은 경우, 출력하기
- [X] 모든 상품이 소진된 경우, 출력하기
- [X] 잔돈을 반환할 수 없는 경우, 잔돈으로 반환할 수 있는 금액을 출력하기

# 📢 변경점
- 0 또는 음수의 입력인 경우 예외 발생 추가
- 0원이나 음수의 입력이 들어오는 경우는 존재하지 않기 때문에 입력으로 들어올 경우, 예외를 발생시킨다.

# ❌문제점
- 기존에 Randoms에 있는 메서드 pickNumberInList가 아닌 pickNumberInRange를 사용했으나, 테스트 코드가 돌아가지 않는 문제점 발생
- pickNumberInList 메서드를 사용하려 했으나, 10원이 생성되지 않는 문제점 발생
11 changes: 10 additions & 1 deletion src/main/java/vendingmachine/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package vendingmachine;

import vendingmachine.controller.InputManager;
import vendingmachine.controller.MachineController;
import vendingmachine.view.InputView;
import vendingmachine.view.OutputView;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
InputView inputView = new InputView();
OutputView outputView = new OutputView();
InputManager inputManager = new InputManager(inputView, outputView);
MachineController machineController = new MachineController(inputManager, outputView);
machineController.run();
}
}
5 changes: 4 additions & 1 deletion src/main/java/vendingmachine/Coin.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ public enum Coin {
this.amount = amount;
}

// 추가 기능 구현

public int getAmount() {
return amount;
}
}
83 changes: 83 additions & 0 deletions src/main/java/vendingmachine/controller/InputManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package vendingmachine.controller;

import java.util.ArrayList;
import java.util.List;
import vendingmachine.domain.Machine;
import vendingmachine.domain.Product;
import vendingmachine.utils.Parser;
import vendingmachine.validator.InputMoneyValidator;
import vendingmachine.view.InputView;
import vendingmachine.view.OutputView;

public class InputManager {

private final InputView inputView;
private final OutputView outputView;

public InputManager(InputView inputView, OutputView outputView) {
this.inputView = inputView;
this.outputView = outputView;
}

public int inputMachineMoney() {
boolean flag = false;
String money = "";
while (!flag) {
try {
money = inputView.inputMachineMoney();
InputMoneyValidator.validateInputMoney(money);
flag = true;
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e);
}
}
return Parser.inputMoneyParser(money);
}

public List<Product> inputMachineProduct() {
boolean flag = false;
List<Product> machineProducts = new ArrayList<>();
while (!flag) {
try {
String products = inputView.inputMachineProduct();
machineProducts = Parser.productsParser(products);
flag = true;
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e);
}
}
return machineProducts;
}

public int inputUserAmount() {
boolean flag = false;
String money = "";
while (!flag) {
try {
money = inputView.inputUserAmount();
;
InputMoneyValidator.validateInputMoney(money);
flag = true;
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e);
}
}
return Parser.inputMoneyParser(money);
}

public String inputBuyProduct(Machine machine) {
boolean flag = false;
String product = "";
while (!flag) {
try {
product = inputView.inputBuyProduct();
machine.isExistsProduct(product);
machine.isExistsQuantity(product);
flag = true;
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e);
}
}
return product;
}
}
48 changes: 48 additions & 0 deletions src/main/java/vendingmachine/controller/MachineController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package vendingmachine.controller;

import java.util.List;
import java.util.Map;
import vendingmachine.Coin;
import vendingmachine.domain.CoinGenerator;
import vendingmachine.domain.Machine;
import vendingmachine.domain.Product;
import vendingmachine.view.OutputView;

public class MachineController {
private final OutputView outputView;
private final InputManager inputManager;

public MachineController(InputManager inputManager, OutputView outputView) {
this.inputManager = inputManager;
this.outputView = outputView;
}

public void run() {
Map<Coin, Integer> coins = makeMachineCoins();
outputView.printCoins(coins);
List<Product> products = inputManager.inputMachineProduct();
Machine machine = new Machine(coins, products);
int userAmount = inputManager.inputUserAmount();
buyProduct(machine, userAmount);
}

private void buyProduct(Machine machine, int userAmount) {
while (true) {
outputView.printUserAmount(userAmount);
if (!machine.canBuyWithMoney(userAmount) || !machine.canBuyWithQuantity()) {
outputView.printChange(machine.calculateChange(userAmount));
break;
}
String product = inputManager.inputBuyProduct(machine);
int change = machine.buy(product);
userAmount -= change;
}
}

private Map<Coin, Integer> makeMachineCoins() {
int money = inputManager.inputMachineMoney();
CoinGenerator coinGenerator = new CoinGenerator(money);
return coinGenerator.getCoins();
}

}
43 changes: 43 additions & 0 deletions src/main/java/vendingmachine/domain/CoinGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package vendingmachine.domain;

import camp.nextstep.edu.missionutils.Randoms;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import vendingmachine.Coin;

public class CoinGenerator {
private final Map<Coin, Integer> coins;

public CoinGenerator(int money) {
this.coins = generate(money);
}

private Map<Coin, Integer> generate(int money) {
Map<Coin, Integer> coins = new HashMap<>();
List<Integer> coinList = Arrays.asList(1, 2, 3, 4);
//List<Integer> coinList = Arrays.asList(1, 2, 3, 4, 5, 6);

while (money > 0) {
Coin randomCoin = Coin.values()[Randoms.pickNumberInList(coinList) % 3];
//Coin randomCoin = Coin.values()[Randoms.pickNumberInList(coinList) % 4];

if (randomCoin.getAmount() <= money) {
coins.put(randomCoin, coins.getOrDefault(randomCoin, 0) + 1);
money -= randomCoin.getAmount();
}
}

Map<Coin, Integer> sortedCoins = new TreeMap<>(Comparator.comparing(Coin::getAmount).reversed());
sortedCoins.putAll(coins);

return sortedCoins;
}

public Map<Coin, Integer> getCoins() {
return coins;
}
}
75 changes: 75 additions & 0 deletions src/main/java/vendingmachine/domain/Machine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package vendingmachine.domain;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import vendingmachine.Coin;

public class Machine {
private Map<Coin, Integer> coins;
private List<Product> products;

public Machine(Map<Coin, Integer> coins, List<Product> products) {
this.coins = coins;
this.products = products;
}


public int buy(String productName) {
for (Product product : products) {
if (productName.equals(product.getName())) {
product.soldProduct();
return product.getPrice();
}
}
return 0;
}

public boolean canBuyWithMoney(int userAmount) {
return products.stream().anyMatch(product -> userAmount >= product.getPrice());
}

public boolean canBuyWithQuantity() {
return products.stream().anyMatch(product -> product.getQuantity() > 0);
}

public void isExistsQuantity(String productName) {
boolean productAvailable = products.stream()
.filter(product -> product.getName().equals(productName))
.anyMatch(product -> product.getQuantity() > 0);

if (!productAvailable) {
throw new IllegalArgumentException("[ERROR] 주문하려는 상품이 소진되었습니다. 다른 상품을 주문해 주세요.");
}
}

public void isExistsProduct(String productName) {
boolean productExists = products.stream()
.anyMatch(product -> productName.equals(product.getName()));

if (!productExists) {
throw new IllegalArgumentException("[ERROR] 존재하지 않는 상품입니다.");
}
}

public Map<Coin, Integer> calculateChange(int userAmount) {
Map<Coin, Integer> sortedCoins = new TreeMap<>(Comparator.comparing(Coin::getAmount).reversed());

for (Entry<Coin, Integer> entry : coins.entrySet()) {
Coin change = entry.getKey();
int count = entry.getValue();

while (userAmount >= change.getAmount() && count > 0) {
userAmount -= change.getAmount();
count--;
sortedCoins.merge(change, 1, Integer::sum);
}
coins.put(change, count);
}

return sortedCoins;
}

}
30 changes: 30 additions & 0 deletions src/main/java/vendingmachine/domain/Product.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package vendingmachine.domain;

public class Product {
private final String name;
private final int price;

private int quantity;

public Product(String name, int price, int quantity) {
this.name = name;
this.price = price;
this.quantity = quantity;
}

public String getName() {
return name;
}

public int getPrice() {
return price;
}

public int getQuantity() {
return quantity;
}

public void soldProduct(){
this.quantity--;
}
}
29 changes: 29 additions & 0 deletions src/main/java/vendingmachine/utils/Parser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package vendingmachine.utils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import vendingmachine.domain.Product;
import vendingmachine.validator.InputProductValidator;

public class Parser {
public static int inputMoneyParser(String money) {
return Integer.parseInt(money);
}

public static List<Product> productsParser(String inputProducts) {
String[] products = inputProducts.split(";");
Set<String> productNames = new HashSet<>();
List<Product> machineProducts = new ArrayList<>();
for (String product : products) {
Product parsedProduct = InputProductValidator.validateProduct(product);
if (!productNames.add(parsedProduct.getName())) {
throw new IllegalArgumentException("[ERROR] 중복된 상품이 존재합니다.");
}
machineProducts.add(parsedProduct);
}

return machineProducts;
}
}
Loading