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

Step4 - 로또(수동) #3238

Open
wants to merge 10 commits into
base: gisungpark
Choose a base branch
from
74 changes: 58 additions & 16 deletions src/main/java/step2/controller/LottoGameController.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,83 @@
package step2.controller;

import step2.domain.LottoTicket;
import step2.domain.LottoGames;
import step2.domain.LottoResultReport;
import step2.domain.*;
import step2.view.InputView;
import step2.view.ResultView;

import java.util.ArrayList;
import java.util.List;

public class LottoGameController {

private static final int LOTTO_TICKET_PRICE = 1000;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로또 금액은 비즈니스 영역에 해당하는 값으로 보여지는데 현재 Controller에서 상수로 관리되고 있어요! 적절한 도메인 객체에서 해당 값을 관리하는 것이 어떨까요?

private LottoGames lottoGames = new LottoGames();

public void playLottoGame() {
lxxjn0 marked this conversation as resolved.
Show resolved Hide resolved
Money balance = new Money(InputView.readMoney());

int money = InputView.readAmountOfPurchase();
int gameCount = lottoGames.calculateBuyingTicketCount(money);
ResultView.printMessage(gameCount + "개를 구매했습니다.");
if (gameCount == 0) {
List<LottoTicket> manualLottoTickets = buyManualTickets(balance);
List<LottoTicket> automaticLottoTickets = getBuyAutomaticTickets(balance);

ResultView.printNumberOfTickets(manualLottoTickets.size(), automaticLottoTickets.size());
if (manualLottoTickets.size() == 0 && automaticLottoTickets.size() == 0) {
return;
}
ResultView.printLottoTicket(automaticLottoTickets);
LottoTicket winningTicket = readWinningTicket();
LottoNo bonusNumber = LottoNo.of(InputView.readBonusNumber());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

축약어는 최대한 지양하면 좋을 것 같아요!! LottoNumber라는 이름이 좀 더 직관적이고 가독성이 더 좋을 것 같아요!!


printResultStatistic(getLottoResultReport(manualLottoTickets, automaticLottoTickets, winningTicket, bonusNumber));
}

private List<LottoTicket> buyManualTickets(Money money) {
int manualTicketCount = getManualTicketCount(money);
money.pay(manualTicketCount * LOTTO_TICKET_PRICE);

ResultView.printMessage("수동으로 구매할 번호를 입력해 주세요");
List<LottoTicket> manualLottoTickets = new ArrayList<>(manualTicketCount);
for (int i = 0; i < manualTicketCount; i++) {
LottoTicket lottoTicket = lottoGames.toLottoTicket(InputView.readManualTicketNumbers());
manualLottoTickets.add(lottoTicket);
}
return manualLottoTickets;
}

List<LottoTicket> lottoTickets = lottoGames.buyLottoGame(gameCount);
ResultView.printLottoTicket(lottoTickets);
LottoTicket winningTicket = lottoGames.readWinningNumber(InputView.readWinningNumbers());
int bonusNumber = InputView.readBonusNumber();
private int getManualTicketCount(Money money) {
int manualTicketCount = InputView.readCountOfManualTicket();
int cost = manualTicketCount * LottoCommonValue.DEFAULT_LOTTO_NUMBER_COUNT.value();
money.pay(cost);
return manualTicketCount;
}

private List<LottoTicket> getBuyAutomaticTickets(Money money) {
int automaticTicketCount = money.balance() / LOTTO_TICKET_PRICE;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 로직은 getter를 사용해서 값을 가져와서 계산을 하고 있어요!! 이렇게 된다면 값을 객체로 감싼 의미가 조금은 퇴색될 수 있는데 어떻게 바꾸면 좋을까요?

money.pay(automaticTicketCount * LOTTO_TICKET_PRICE);
return lottoGames.buyAutomaticLottoTickets(automaticTicketCount);
}

private LottoTicket readWinningTicket() {
ResultView.printMessage("지난 주 당첨 번호를 입력해 주세요");
return lottoGames.toLottoTicket(InputView.readWinningNumbers());
}

private void printResultStatistic(LottoResultReport lottoResultReport) {
ResultView.printBlankLine();
ResultView.printMessage("당첨 통계");
ResultView.printResultReport(lottoResultReport);
ResultView.printMessage("총 수익률은 " + lottoResultReport.calculateProfit() + "입니다.");
}

private LottoResultReport getLottoResultReport(List<LottoTicket> manualLottoTickets,
List<LottoTicket> automaticLottoTickets,
LottoTicket winningTicket, LottoNo bonusNumber) {

LottoResultReport lottoResultReport = new LottoResultReport();
for (LottoTicket lottoTicket : lottoTickets) {
for (LottoTicket lottoTicket : manualLottoTickets) {
lottoResultReport.recordRank(lottoTicket.checkLottoTicket(winningTicket, bonusNumber));
}

ResultView.printResultReport(lottoResultReport);
double profit = lottoResultReport.calculateProfit(gameCount);
ResultView.printMessage("총 수익률은 " + profit + "입니다.");
for (LottoTicket lottoTicket : automaticLottoTickets) {
lottoResultReport.recordRank(lottoTicket.checkLottoTicket(winningTicket, bonusNumber));
}
return lottoResultReport;
}
}
5 changes: 0 additions & 5 deletions src/main/java/step2/domain/LottoCommonValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,4 @@ public enum LottoCommonValue {
public int value() {
return value;
}





}
33 changes: 12 additions & 21 deletions src/main/java/step2/domain/LottoGames.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package step2.domain;

import java.util.*;
import java.util.stream.Collectors;

public class LottoGames {

public LottoGames() {
}

public int calculateBuyingTicketCount(int money) {
return new Integer(money / LottoCommonValue.DEFAULT_LOTTO_PRICE.value());
}

public List<LottoTicket> buyLottoGame(int gameCount) {
public List<LottoTicket> buyAutomaticLottoTickets(int gameCount) {
List<LottoTicket> lottoTickets = new ArrayList<>(gameCount);
for (int i = 0; i < gameCount; i++) {
lottoTickets.add(createLottoGame());
Expand All @@ -20,32 +17,26 @@ public List<LottoTicket> buyLottoGame(int gameCount) {
}

private LottoTicket createLottoGame() {
return new LottoTicket(RandomIntegersGenerator.createNumberList());
}

public LottoTicket readWinningNumber(String stringNumber) {
String[] numbers = splitByDelimiter(stringNumber);
Set<Integer> integers = toSet(numbers);
if (integers.size() != LottoCommonValue.DEFAULT_LOTTO_NUMBER_COUNT.value()) {
throw new IllegalArgumentException(stringNumber + " : 입력한 숫자를 확인해 주세요");
}
return new LottoTicket(integers);
List<LottoNo> lottoNumbers = RandomIntegersGenerator.createNumberList().stream()
.map(i -> LottoNo.of(i))
.collect(Collectors.toList());
return new LottoTicket(lottoNumbers);
}

private String[] splitByDelimiter(String stringNumber) {
stringNumber = stringNumber.replaceAll(" ", "");
return stringNumber.split(",");
public LottoTicket toLottoTicket(String[] splits) {
return new LottoTicket(toSet(splits));
}

private Set<Integer> toSet(String[] numbers) {
HashSet<Integer> hashSet = new HashSet<>();
private Set<LottoNo> toSet(String[] numbers) {
Set<LottoNo> hashSet = new HashSet<>();
for (String number : numbers) {
hashSet.add(toInt(number));
hashSet.add(LottoNo.of(toInt(number)));
}
return hashSet;
}

private Integer toInt(String element) {
element = element.trim();
try {
return Integer.parseInt(element);
} catch (NumberFormatException e) {
Expand Down
52 changes: 52 additions & 0 deletions src/main/java/step2/domain/LottoNo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package step2.domain;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.IntStream;

public class LottoNo {
lxxjn0 marked this conversation as resolved.
Show resolved Hide resolved
private static final int MIN_LOTTO_NUMBER = 1;
private static final int MAX_LOTTO_NUMBER = 45;

private static final Map<Integer, LottoNo> lottoNumberCache = new HashMap<>();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네이밍도 상수 컨벤션에 맞게 바꾸면 좋을 것 같아요!!


static {
IntStream.range(MIN_LOTTO_NUMBER, MAX_LOTTO_NUMBER + 1)
.forEach(i -> lottoNumberCache.put(i, new LottoNo(i)));
}

private int number;

private LottoNo(int number) {
this.number = number;
}

public static LottoNo of(int number) {
if (isInvalidNumber(number)) {
throw new IllegalArgumentException("잘못 입력하셨습니다.");
}
return lottoNumberCache.get(number);
}

private static boolean isInvalidNumber(int number) {
return number < MIN_LOTTO_NUMBER || number > MAX_LOTTO_NUMBER;
}

public int number() {
return number;
}
lxxjn0 marked this conversation as resolved.
Show resolved Hide resolved

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LottoNo lottoNo = (LottoNo) o;
return number == lottoNo.number;
}

@Override
public int hashCode() {
return Objects.hash(number);
}
}
18 changes: 13 additions & 5 deletions src/main/java/step2/domain/LottoResultReport.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,32 @@
public class LottoResultReport {

private Map<Rank, Integer> lottoResultReport;
private int ticketCount;

public LottoResultReport() {
lottoResultReport = new HashMap<>();
ticketCount = 0;
}

public int recordRank(Rank rank) {
Integer value = lottoResultReport.getOrDefault(rank, 0);
lottoResultReport.put(rank, value + 1);
return lottoResultReport.get(rank);
ticketCount += 1;
return lottoResultReport.compute(rank, (key, value) -> getNextValue(value));
}

private int getNextValue(Integer value) {
if(value == null) {
return 1;
}
return value + 1;
}

public int findReportByMatchCount(Rank rank) {
return lottoResultReport.getOrDefault(rank, 0);
}

public double calculateProfit(int gameCount) {
public double calculateProfit() {
long profit = sum();
long cost = gameCount * LottoCommonValue.DEFAULT_LOTTO_PRICE.value();
long cost = ticketCount * LottoCommonValue.DEFAULT_LOTTO_PRICE.value();
return calculateProfitRate(profit, cost);
}

Expand Down
36 changes: 17 additions & 19 deletions src/main/java/step2/domain/LottoTicket.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,43 @@
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class LottoTicket {

private final List<Integer> lottoTicket;
private final List<LottoNo> lottoTicket;

public LottoTicket(List<Integer> lottoTicket) {
validInputNumber(lottoTicket);
this.lottoTicket = lottoTicket;
public LottoTicket(List<LottoNo> lottoNumbers) {
validInputNumber(lottoNumbers);
this.lottoTicket = new ArrayList<>(lottoNumbers);
}

public LottoTicket(Set<Integer> numbers) {
validInputNumber(numbers);
lottoTicket = new ArrayList<>(numbers);
public LottoTicket(Set<LottoNo> lottoNumbers) {
validInputNumber(lottoNumbers);
lottoTicket = new ArrayList<>(lottoNumbers);
}

private static void validInputNumber(Collection<Integer> numbers) {
if (numbers.size() != LottoCommonValue.DEFAULT_LOTTO_NUMBER_COUNT.value()) {
throw new IllegalArgumentException(numbers + " : 입력한 숫자를 확인해 주세요");
private static void validInputNumber(Collection<LottoNo> lottoNos) {
if (lottoNos.size() != LottoCommonValue.DEFAULT_LOTTO_NUMBER_COUNT.value()) {
throw new IllegalArgumentException(lottoNos + " : 입력한 숫자를 확인해 주세요");
}
}

public boolean isContain(Integer number) {
public boolean isContain(LottoNo number) {
return this.lottoTicket.contains(number);
}

public Rank checkLottoTicket(LottoTicket winningTicket, int bonusNumber) {
public Rank checkLottoTicket(LottoTicket winningTicket, LottoNo bonusNumber) {
int count = (int) lottoTicket.stream()
.filter(i -> winningTicket.isContain(i))
.count();

if(count == 5 && isContain(bonusNumber)) {
return Rank.SECOND;
}

return Rank.toPrizeMoney(count);
return Rank.rank(count, isContain(bonusNumber));
}

public String printTicket() {
return lottoTicket.toString();
return lottoTicket.stream()
.map(i -> String.valueOf(i.number()))
.collect(Collectors.joining(","));
Comment on lines +42 to +44
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로또 번호들을 리스트로 반환해주고 뷰에서 출력 형식에 맞게 joining을 해서 출력하는 것이 어떨까요?? 이렇게 되면 출력 형식이 바뀔 때 LottoTicket 도메인도 영향을 받을 것 같아요

}

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

import java.util.Objects;

public class Money {
private int money;

public Money(int money) {
if (money < 0) {
throw new IllegalArgumentException("잔액은 음수를 가질 수 없습니다.");
}
this.money = money;
}

public int pay(int cost) {
if (cost > this.money) {
throw new IllegalArgumentException("잔액을 초과하셨습니다.");
}
this.money -= cost;
return 0;
}
Comment on lines +15 to +21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0이라는 반환 값이 별다른 의미가 없어보이는데 void 메서드로 만드는 것이 어떨까요?


public int balance() {
return money;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Money money1 = (Money) o;
return money == money1.money;
}

@Override
public int hashCode() {
return Objects.hash(money);
}
}
Loading