Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[자판기] 드디어 완료했다!!!! 햄볶~!! #188

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
### 기능 요구사항

[ ✅ ] 사용자는 자판기가 보유하고 있는 금액을 입력한다.

[ ✅ ] 자판기가 보유하고 있는 금액으로 동전을 무작위로 생성한다.

- 투입금액으로 동전을 생성하지 않는다. == Coin클래스로 동전을 생성한다.

[ ✅ ] 상품명, 가격, 수량을 입력하여 상품을 추가할 수 있다.

- 상품 가격은 100원부터 시작하며, 10원으로 나누어떨어져야 한다.

[ ✅ ] 사용자는 금액을 투입할 수 있다.

[ ✅ ] 사용자가 입력한 투입금액을 기반으로 현재 투입금액을 출력한다.

[ ✅ ] 사용자는 구매할 상품명을 입력한다.

[ ✅ ] 잔돈을 돌려줄 때 현재 보유한 최소 개수의 동전으로 잔돈을 돌려준다.

[ ✅ ] 남은 금액이 상품의 최저 가격보다 적거나, 모든 상품이 소진된 경우 바로 잔돈을 돌려준다.

[ ✅ ] 잔돈을 반환할 수 없는 경우 잔돈으로 반환할 수 있는 금액만 반환한다.

- 반환되지 않은 금액은 자판기에 남는다.


## Getter지양 방법 이후 적용하기
쉽게 말해, getter를 통해 얻은 상태값으로 하려고 했던 '행동'을 그 상태값을 가진 객체가 하도록 '행동'의 주체를 옮기는 것이다.
74 changes: 74 additions & 0 deletions src/main/java/controller/ProductsController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package controller;

import domain.Payment;
import domain.Products;
import dto.ProductNameDto;
import service.ProductsService;
import service.UserPaymentService;
import view.InputView;
import view.OutputView;

import static util.message.InputMessage.INPUT_PRODUCT_DETAIL;
import static util.message.InputMessage.INPUT_SELECTED_PRODUCT;
import static view.OutputView.printCurrentUserBalance;

public class ProductsController {
private final ProductsService productsService;
private final UserPaymentService userPaymentService;
private Products products;

public ProductsController(){
productsService = new ProductsService();
userPaymentService = new UserPaymentService();
}

public void generateProductInfo(){
String productInfo = getProductInfo();
try{
products = createProducts(productInfo);
} catch (IllegalArgumentException e){
OutputView.printMessage(e.getMessage());
generateProductInfo();
}
}

private String getProductInfo(){
return InputView.readConsole();
}

private Products createProducts(String productInfo){
return productsService.createProducts(productInfo);
}

public void buyProduct(){
String wantedProduct = getSelectedProduct();
ProductNameDto productNameDto = createSelectedProduct(wantedProduct);
try{
productsService.buyProduct(productNameDto);
Payment payment = userPaymentService.getUserPayment();
OutputView.printCurrentUserBalance(payment.getPayment());
} catch(IllegalArgumentException e){
OutputView.printMessage(e.getMessage());
buyProduct();
}
}

private ProductNameDto createSelectedProduct(String wantedProduct){
return ProductNameDto.create(wantedProduct);
}

private String getSelectedProduct(){
OutputView.printMessage(INPUT_SELECTED_PRODUCT.getValue());
return InputView.readConsole();
}

public boolean checkAvailableToPurchase() {
Payment payment = userPaymentService.getUserPayment();

boolean isSoldOutOfItemAvailableForBuy = productsService.checkSoldOutOfItemAvailableForBuy();
boolean isUserBalanceNotEnough = payment.getPayment() < productsService.getMinItemPrice();

return !isSoldOutOfItemAvailableForBuy && !isUserBalanceNotEnough;
}
}

39 changes: 39 additions & 0 deletions src/main/java/controller/UserPaymentController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package controller;

import domain.Payment;
import dto.PaymentStatusDto;
import service.UserPaymentService;
import view.InputView;
import view.OutputView;

import static util.message.InputMessage.INPUT_PAYMENT;

public class UserPaymentController {
private final UserPaymentService userPaymentService;

public UserPaymentController(){
userPaymentService = new UserPaymentService();
}

public void generateUserBalance() {
String paymentAmount = getPayment();
try {
Payment payment = createPayment(paymentAmount);
PaymentStatusDto paymentStatusDto = userPaymentService.createPaymentStatusDto(payment);
OutputView.printPaymentStatus(paymentStatusDto);
} catch (IllegalArgumentException e) {
OutputView.printMessage(e.getMessage());
generateUserBalance();
}
}

private String getPayment(){
OutputView.printMessage(INPUT_PAYMENT.getValue());
return InputView.readConsole();
}

private Payment createPayment(String paymentAmount){
return userPaymentService.createPayment(paymentAmount);
}
}

58 changes: 58 additions & 0 deletions src/main/java/controller/VendingMachineController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package controller;

import domain.*;
import dto.CoinsDto;
import dto.VendingMachineStatusDto;
import service.*;
import view.InputView;
import view.OutputView;

import java.util.List;

import static util.message.InputMessage.*;

public class VendingMachineController {
private final PossessionAmountService possesionAmountService;
private final VendingMachineService vendingMachineService;

public VendingMachineController(){
possesionAmountService = new PossessionAmountService();
vendingMachineService = new VendingMachineService();
}

public void generateCoins() {
String amount = getPossessionAmount();

try {
PossessionAmount possessionAmount = createPossessionAmount(amount);
initCoins(possessionAmount);
} catch (IllegalArgumentException e) {
OutputView.printMessage(e.getMessage());
generateCoins();
}
}

public void initCoins(PossessionAmount possessionAmount){
vendingMachineService.generateRandomCoins(possessionAmount.getPossessionAmount());
}

private String getPossessionAmount(){
OutputView.printMessage(INPUT_POSSESSION_AMOUNT_MESSAGE.getValue());
return InputView.readConsole();
}

private PossessionAmount createPossessionAmount(String possessionAmount){
return possesionAmountService.createPossessionAmount(possessionAmount);
}

public void printChange() {
CoinsDto coinsDto = vendingMachineService.getChange();
OutputView.printChange(coinsDto);
}

public void printGeneratedCoins() {
CoinsDto coinsDto = vendingMachineService.getCurrentCoins();
OutputView.printVendingMachineHoldingCoins(coinsDto);
}

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

import camp.nextstep.edu.missionutils.Randoms;
import util.exception.NoMatchingCoinException;
import util.message.ExceptionMessage;

import java.util.Arrays;
import java.util.stream.Collectors;

public enum Coin {
COIN_500(500),
COIN_100(100),
COIN_50(50),
COIN_10(10);

private final int amount;

Coin(final int amount) {
this.amount = amount;
}

public static Coin from(int amount) {
try {
return Arrays.stream(Coin.values())
.filter(coin -> coin.getAmount() == amount)
.findFirst()
.orElseThrow(() -> new NoMatchingCoinException(ExceptionMessage.NOT_COIN_MESSAGE.getValue()));
} catch (NoMatchingCoinException ex) {
throw new NoMatchingCoinException(String.format(ExceptionMessage.NOT_COIN_MESSAGE.getValue(), amount));
}
}


public static Coin pickRandomWithLimit(int balanceLimit) {
Coin randomCoin = Coin.pickRandom();
if (randomCoin.getAmount() > balanceLimit) {
return pickRandomWithLimit(balanceLimit);
}

return randomCoin;
}

private static Coin pickRandom() {
int pickedAmount = Randoms.pickNumberInList(
Arrays.stream(values())
.map(Coin::getAmount)
.collect(Collectors.toList())
);

return Coin.from(pickedAmount);
}

public int getAmount() {
return amount;
}

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

import domain.wrapper.PaymentAmount;
import domain.wrapper.Price;
import domain.wrapper.VendingMachineAmount;

public class Payment {
private final PaymentAmount payment;
private Payment(final String payment){
this.payment = PaymentAmount.create(payment);
}

private Payment(int payment){
this.payment = PaymentAmount.create(payment);
}

public static Payment create(final String payment){
return new Payment(payment);
}

public int getPayment(){
return payment.getPaymentAmount();
}

public boolean canBuy(Product product) {
return payment.getPaymentAmount() >= product.getPrice();
}

public Payment subtract(int price) {
return new Payment(payment.getPaymentAmount() - price);
}
}
19 changes: 19 additions & 0 deletions src/main/java/domain/PossessionAmount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package domain;

import domain.wrapper.VendingMachineAmount;

public class PossessionAmount {

private final VendingMachineAmount vendingMachineAmount;
private PossessionAmount(final String possessionAmount){
this.vendingMachineAmount = VendingMachineAmount.create(possessionAmount);
}

public static PossessionAmount create(final String possessionAmount){
return new PossessionAmount(possessionAmount);
}

public int getPossessionAmount(){
return vendingMachineAmount.getVendingMachineAmount();
}
}
83 changes: 83 additions & 0 deletions src/main/java/domain/Product.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package domain;

import domain.wrapper.Name;
import domain.wrapper.Price;
import domain.wrapper.Quantity;

import java.util.Objects;

import static domain.constant.ProductConstant.SPLIT_DELIMITER_COMMA;
import static util.message.ExceptionMessage.BLANK_MESSAGE;

public class Product {
private final Name name;
private final Price price;
private final Quantity quantity;
private static final int SOLD_OUT_QUANTITY = 0;

private Product(final String productDetail){
validateBlank(productDetail);
String[] product = splitProduct(productDetail);
this.name = Name.create(product[0]);
this.price = Price.create(product[1]);
this.quantity = Quantity.create(product[2]);
}

public static Product create(final String productDetail){
return new Product(productDetail);
}

private Product(Name name, Price price, Quantity quantity){
this.name = name;
this.price = price;
this.quantity = quantity;
}

private String[] splitProduct(final String productDetail){
return productDetail.split(SPLIT_DELIMITER_COMMA.getValue());
}

private void validateBlank(final String productDetail){
if (productDetail == null || productDetail.trim().isEmpty()) {
throw new IllegalArgumentException(String.format(BLANK_MESSAGE.getValue(), "상품명, 가격, 수량"));
}
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Objects.equals(name, product.name) &&
Objects.equals(price, product.price) &&
Objects.equals(quantity, product.quantity);
}

@Override
public int hashCode() {
return Objects.hash(name, price, quantity);
}

public String getName() {
return name.getName();
}

public int getPrice() {
return price.getPrice();
}

public int getQuantity() {
return quantity.getQuantity();
}

public boolean isSoldOut() {
return quantity.getQuantity() <= SOLD_OUT_QUANTITY;
}

public Product decreaseQuantity() {
Quantity subtractedQuantity = quantity.subtract();
return new Product(name, price, subtractedQuantity);
}

}

Loading