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

코드 리뷰 PR #2103

Open
wants to merge 20 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
98 changes: 98 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
## ✏️ 구현할 기능 목록

___

## 입력

- [X] `로또 구입 금액` 입력

- 비기능적 요구사항
- null 값이거나 빈 값인지 확인한다.
- 구입 금액은 정수만 가능하다.
- 구입 금액은 1이상의 자연수이다.

- 기능적 요구사항
- 구입 금액은 `1,000원 단위`이다.


- [X] `당첨 번호` 입력 (번호는 쉼표(,)를 기준으로 구분한다.)

- 비기능적 요구사항
```
1,2,3,4,5,6
```
- null 값이거나 빈 값인지 확인한다.
- 당첨 번호는 정수만 가능하다.
- 당첨 번호은 1이상의 자연수이다.
- `,,` 와 같은 잘못된 입력 값 검증
- 가장 앞과 가장 뒤 입력 값은 숫자여야 한다.

- 기능적 요구사항
- 당첨 번호는 6개여야 합니다.
- 중복된 숫자는 입력 불가하다.
- 1 ~ 45 사이 숫자만 입력 가능하다.

- [X] `보너스 번호` 입력

- 비기능적 요구사항
- null 값이거나 빈 값인지 확인한다.
- 보너스 번호는 정수만 가능하다.
- 보너스 번호은 1이상의 자연수이다.

- 기능적 요구사항
- 1 ~ 45 사이 숫자만 입력 가능하다.
- 당첨 번호와 중복 불가하다.

## 로또 번호

- [X] 로또 구입 금액을 입력하면 구입 금액에 해당하는 만큼 로또를 발행해야 한다.
- 로또 번호는 랜덤이다.
- 로또 번호는 중복되면 안된다.
- 로또 번호는 오름차순 정렬되어 출력된다.

## 당첨 통계

- [X] 당첨 통계는 다음과 같다.

```
3개 일치 (5,000원) - 1개
4개 일치 (50,000원) - 0개
5개 일치 (1,500,000원) - 0개
5개 일치, 보너스 볼 일치 (30,000,000원) - 0개
6개 일치 (2,000,000,000원) - 0개
총 수익률은 62.5%입니다.

```

- [X] 수익률 계산
- 수익률은 소수점 둘째 자리에서 반올림한다.

## 출력

- [X] `구입금액을 입력해 주세요.` 출력

- [X] `?개를 구매했습니다.` 출력
- 로또 번호 출력 (랜덤)

- [X] `당첨 번호를 입력해 주세요.` 출력

- [X] `보너스 번호를 입력해 주세요.` 출력

- [X] `당첨 통계` 출력
```
---
3개 일치 (5,000원) - 1개
4개 일치 (50,000원) - 0개
5개 일치 (1,500,000원) - 0개
5개 일치, 보너스 볼 일치 (30,000,000원) - 0개
6개 일치 (2,000,000,000원) - 0개
총 수익률은 62.5%입니다.

```

---

## 공통 검증

- [X] 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 해당 부분부터 다시 입력을 받는다.
- [X] 1,000단위마다 콤마를 찍기
15 changes: 14 additions & 1 deletion src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
package lotto;

import lotto.config.Configuration;
import lotto.controller.BuyLottoController;
import lotto.controller.LottoController;
import lotto.dto.BuyLottoDto;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
Configuration configuration = new Configuration();
LottoController lottoController = configuration.getLottoController();
BuyLottoController buyLottoController = configuration.getBuyLottoController();
executeControllers(buyLottoController, lottoController);
}

private static void executeControllers(BuyLottoController buyLottoController, LottoController lottoController) {
BuyLottoDto buyLottoDto = buyLottoController.buyLotto();
lottoController.getStatistics(buyLottoDto);
}
}
20 changes: 0 additions & 20 deletions src/main/java/lotto/Lotto.java

This file was deleted.

37 changes: 37 additions & 0 deletions src/main/java/lotto/config/Configuration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package lotto.config;

import lotto.controller.BuyLottoController;
import lotto.controller.LottoController;
import lotto.service.BuyLottoService;
import lotto.service.CalculateStatisticService;
import lotto.validation.BonusNumberValidator;
import lotto.validation.PurchasePriceValidator;
import lotto.validation.WinnerNumberValidator;
import lotto.view.input.InputView;
import lotto.view.input.template.InputValidatorTemplate;
import lotto.view.output.OutputView;

public class Configuration {
InputView inputView = createInputView();
OutputView outputView = new OutputView();
BuyLottoService buyLottoService = new BuyLottoService(outputView);
CalculateStatisticService calculateStatisticService = new CalculateStatisticService(outputView);
BuyLottoController buyLottoController = new BuyLottoController(inputView, outputView, buyLottoService);
LottoController lottoController = new LottoController(inputView, outputView, calculateStatisticService);

public BuyLottoController getBuyLottoController() {
return buyLottoController;
}

public LottoController getLottoController() {
return lottoController;
}

private InputView createInputView() {
PurchasePriceValidator purchasePriceValidator = new PurchasePriceValidator();
WinnerNumberValidator winnerNumberValidator = new WinnerNumberValidator();
BonusNumberValidator bonusNumberValidator = new BonusNumberValidator();
InputValidatorTemplate template = new InputValidatorTemplate();
return new InputView(purchasePriceValidator, winnerNumberValidator, bonusNumberValidator, template);
}
}
10 changes: 10 additions & 0 deletions src/main/java/lotto/constant/Constant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package lotto.constant;

public class Constant {
public static int MIN_LOTTO_NUMBER = 1;
public static int MAX_LOTTO_NUMBER = 45;
public static int LOTTO_SIZE = 6;
public static int THOUSAND = 1000;
public static int ZERO = 0;

}
42 changes: 42 additions & 0 deletions src/main/java/lotto/constant/PrintOutMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package lotto.constant;

import java.text.NumberFormat;
import lotto.model.PurchasePrice;

public enum PrintOutMessage {
PLZ_INPUT_PURCHASE_PRICE("구입금액을 입력해 주세요."),
LOTTO_COUNT("개를 구매했습니다."),
PLZ_INPUT_WINNER_NUMBER("당첨 번호를 입력해 주세요."),
PLZ_INPUT_BONUS_NUMBER("보너스 번호를 입력해 주세요."),
STATISTIC("당첨 통계"),
DIVISION_LINE("---"),
EARNING_POINT("총 수익률은 %s%%입니다."),
EMPTY_LINE("\n"),
COUNT("개");

public final String message;

PrintOutMessage(String message) {
this.message = message;
}

public String getMessage(String matchingCount) {
return String.format(message, matchingCount);
}

public static String printLottoCount(int count) {
return count + LOTTO_COUNT.message;
}


public static String calculateEarningRate(long totalPrize, PurchasePrice purchasePrice) {
double earningRate = (double) totalPrize / purchasePrice.getPrice() * 100;

String formattedRate = String.format("%.2f", earningRate);

NumberFormat nf = NumberFormat.getInstance();
String formattedNumber = nf.format(Double.parseDouble(formattedRate));

return EARNING_POINT.getMessage(formattedNumber);
}
}
44 changes: 44 additions & 0 deletions src/main/java/lotto/constant/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package lotto.constant;

import java.util.Arrays;

public enum Rank {
NO_MATCH(0, 0, false, "0개 일치 (0원) - "),
THREE_MATCH(3, 5000, false, "3개 일치 (5,000원) - "),
FOUR_MATCH(4, 50000, false, "4개 일치 (50,000원) - "),
FIVE_MATCH_NOT_BONUS(5, 1500000, false, "5개 일치 (1,500,000원) - "),
FIVE_MATCH_PLUS_BONUS(5, 30000000, true, "5개 일치, 보너스 볼 일치 (30,000,000원) - "),
SIX_MATCH(6, 2000000000, false, "6개 일치 (2,000,000,000원) - ");

public final int match;
public final int prizeMoney;
public final boolean needBonus;
public final String message;

Rank(int match, int prizeMoney, boolean needBonus, String message) {
this.match = match;
this.prizeMoney = prizeMoney;
this.needBonus = needBonus;
this.message = message;
}

private static Rank getInstance(long totalCount) {
return Arrays.stream(Rank.values())
.filter(rank -> rank.match == totalCount)
.findAny()
.orElse(NO_MATCH);
}

public static Rank findRank(long winnerMatch, boolean bonusMatch) {
Rank rank = getInstance(winnerMatch);

if (winnerMatch == FIVE_MATCH_NOT_BONUS.match) {
if (bonusMatch) {
return FIVE_MATCH_PLUS_BONUS;
}
return FIVE_MATCH_NOT_BONUS;
}
return rank;
}
}

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

import java.util.List;
import lotto.dto.BuyLottoDto;
import lotto.model.BonusNumber;
import lotto.model.LottoNumbers;
import lotto.model.PurchasePrice;
import lotto.model.WinnerNumber;
import lotto.service.BuyLottoService;
import lotto.view.input.InputView;
import lotto.view.output.OutputView;

public class BuyLottoController {
private final InputView inputView;
private final OutputView outputView;
private final BuyLottoService buyLottoService;

public BuyLottoController(InputView inputView, OutputView outputView, BuyLottoService buyLottoService) {
this.inputView = inputView;
this.outputView = outputView;
this.buyLottoService = buyLottoService;
}

public BuyLottoDto buyLotto() {
PurchasePrice purchasePrice = createPurchasePrice(); // 구입 금액 입력

LottoNumbers lottoNumbers = buyLottoService.buyLotto(purchasePrice); // 로또 구입

WinnerNumber winnerNumber = createWinnerNumber(); // 당첨 번호 입력

BonusNumber bonusNumber = createBonusNumber(winnerNumber); // 보너스 번호 입력

return BuyLottoDto.createBuyLottoDto(purchasePrice, lottoNumbers, winnerNumber, bonusNumber);
}

private BonusNumber createBonusNumber(WinnerNumber winnerNumber) {
while (true) {
try {
outputView.printBonusNumberMessage();
int bonus = inputView.inputBonusNumber();
return BonusNumber.createBonusNumber(winnerNumber.getWinnerNumbers(), bonus);
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e.getMessage());
}
}
}

private WinnerNumber createWinnerNumber() {
while (true) {
try {
outputView.printWinnerNumberMessage();
List<Integer> winners = inputView.inputWinnerNumber();
return WinnerNumber.createWinnerNumber(winners);
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e.getMessage());
}
}
}

private PurchasePrice createPurchasePrice() {
while (true) {
try {
outputView.printPurchasePriceMessage();
int price = inputView.readPrice();
PurchasePrice purchasePrice = PurchasePrice.createPurchasePrice(price);
return purchasePrice;
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e.getMessage());
}
}
}
}
34 changes: 34 additions & 0 deletions src/main/java/lotto/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package lotto.controller;

import lotto.dto.BuyLottoDto;
import lotto.dto.StatisticsDto;
import lotto.model.Statistics;
import lotto.service.CalculateStatisticService;
import lotto.view.input.InputView;
import lotto.view.output.OutputView;

public class LottoController {
private final InputView inputView;
private final OutputView outputView;
private final CalculateStatisticService calculateStatisticService;

public LottoController(InputView inputView, OutputView outputView,
CalculateStatisticService calculateStatisticService) {
this.inputView = inputView;
this.outputView = outputView;
this.calculateStatisticService = calculateStatisticService;
}

public void getStatistics(BuyLottoDto buyLottoDto) {
// 당첨, 보너스 번호 & 로또 번호 비교
Statistics statistics = buyLottoDto.calculateMatching();

StatisticsDto statisticsDto = StatisticsDto.createStatisticsDto(statistics);
outputView.printStatistic(statisticsDto.getStatistics().getResult());

long totalPrize = calculateStatisticService.calculatePrizeMoney(
statisticsDto.getStatistics().getResult());// 상금 계산
outputView.printEarningRate(totalPrize, buyLottoDto.getPurchasePrice());
}

}
Loading