Skip to content
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
7 changes: 0 additions & 7 deletions src/main/java/Main.java

This file was deleted.

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

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class Lotto {
private List<LottoNo> lottoNos;

public Lotto(List<Integer> lottoNos) {
Collections.sort(lottoNos);
this.lottoNos = lottoNos.stream().map(number -> new LottoNo(number)).collect(Collectors.toList());
}

public List<LottoNo> getLottoNos() {
return lottoNos;
}

public boolean contains(LottoNo lottoNo) {
return lottoNos.contains(lottoNo);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Lotto lotto = (Lotto) o;
return Objects.equals(lottoNos, lotto.lottoNos);
}
}

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

import java.util.List;
import java.util.stream.Collectors;

public class LottoAnalyzer {
private static final int PRICE_PER_LOTTO = 1000;
private static final int PERCENTAGE = 100;

private List<Lotto> lottos;
private List<WinningLotto> winningLottos;

public LottoAnalyzer(List<Lotto> lottos, WinningNos winningNos) {
this.lottos = lottos;
winningLottos = lottos.stream().map(lotto -> new WinningLotto(lotto, calculateRankOfLotto(lotto, winningNos)))
.collect(Collectors.toList());
}

public Rank calculateRankOfLotto(Lotto lotto, WinningNos winningNos) {
int countOfMatch = winningNos.countMatchOf(lotto);
boolean matchBonus = winningNos.isBonus(lotto);
return Rank.valueOf(countOfMatch, matchBonus);
}

public double calculateEarningRate() {
int inputMoney = lottos.size() * PRICE_PER_LOTTO;
double earnedMoney = calculateEarnedMoney();
return Math.round(earnedMoney / inputMoney * PERCENTAGE * 10) / 10.0;
}

public int calculateEarnedMoney() {
List<Integer> winningMoneys = winningLottos.stream()
.map(winningLotto -> winningLotto.getLottoPrize().getWinningMoney())
.collect(Collectors.toList());
return winningMoneys.stream().reduce(0, (accumulation, current) -> accumulation + current);
}

public int countRank(Rank findingRank) {
return (int) winningLottos.stream().map(WinningLotto::getLottoPrize)
.filter(rank -> rank.equals(findingRank)).count();
}
}
46 changes: 46 additions & 0 deletions src/main/java/lottodomain/LottoGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package lottodomain;

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

public class LottoGame {
private static final int PRICE_PER_LOTTO = 1000;

private List<Lotto> allLotto;
private int numberOfAllLotto;

public LottoGame(int inputMoney, List<List<Integer>> manualLottoNos) {
numberOfAllLotto = inputMoney / PRICE_PER_LOTTO;
allLotto = issueLottos(manualLottoNos);
}

public LottoAnalyzer getLottoAnalyzer(WinningNos winningNos) {
return new LottoAnalyzer(allLotto, winningNos);
}

public List<Lotto> getAllLotto() {
return allLotto;
}

private List<Lotto> issueLottos(List<List<Integer>> manualLottoNos) {
List<Lotto> lottos = issueManualLottos(manualLottoNos);
lottos.addAll(issueAutoLottos(numberOfAllLotto - lottos.size()));
return lottos;
}

private List<Lotto> issueManualLottos(List<List<Integer>> manualLottoNos) {
List<Lotto> ManualLottos = new ArrayList<>();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

변수명이 대문자로 시작하네요 ~

for (int i = 0; i < manualLottoNos.size(); i++) {
ManualLottos.add(LottoGenerator.generateLottoWithNos(manualLottoNos.get(i)));
}
return ManualLottos;
}

private List<Lotto> issueAutoLottos(int numberOfAutoLottos) {
List<Lotto> autoLottos = new ArrayList<>();
for (int i = 0; i < numberOfAutoLottos; i++) {
autoLottos.add(LottoGenerator.generateAutoLotto());
}
return autoLottos;
}
}
25 changes: 25 additions & 0 deletions src/main/java/lottodomain/LottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package lottodomain;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class LottoGenerator {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lotto 에 factory method 을 추가하여 생성해보면 어떨까요?
ex> Lotto.ofAuto(), Lotto.ofManual("1,2,3,4,5,6)

private static final List<Integer> LOTTO_NO_POOLS = IntStream.rangeClosed(1, 45).boxed().collect(Collectors.toList());
;

public static Lotto generateLottoWithNos(List<Integer> lottoNos) {
return new Lotto(lottoNos);
}

public static Lotto generateAutoLotto() {
return generateLottoWithNos(getRandomNos());
}


private static List<Integer> getRandomNos() {
Collections.shuffle(LOTTO_NO_POOLS);
return LOTTO_NO_POOLS.subList(0, 6);
}
}
25 changes: 25 additions & 0 deletions src/main/java/lottodomain/LottoNo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package lottodomain;

public class LottoNo {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

문제 :
"모든 원시값과 문자열을 포장한다." 원칙에 따라 인스턴스를 생성하다보니 너무 많은 객체가 생성되고, GC가 되어 성능상 문제가 발생한다.
특히 로또 번호 하나까지 객체로 포장할 경우 생성되는 인스턴스의 수는 상당히 늘어나는 문제가 발생한다.

위와 같은 문제는 어떻게 해결할 수 있을까요? (키워드 : static, map)

private Integer value;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

불변의 값을 wrapping 한 클래스이므로 final int value; 로 선언해보면 어떨까요?


public LottoNo(int number) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LottoNo 를 생성할 때 range 에 대한 조건을 검증하면 좀 더 의미 있는 wrapping class 가 되지 않을까요?

value = number;
}

public Integer getValue() {
return value;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LottoNo lottoNo = (LottoNo) o;
return value == lottoNo.value;
}
}
28 changes: 28 additions & 0 deletions src/main/java/lottodomain/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package lottodomain;

import lottoview.InputView;
import lottoview.OutputView;
import java.util.List;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
int payment = InputView.askPayment(scanner);
int numberOfManualLottos = InputView.askNumberOfManualLottos(scanner);
List<List<Integer>> manualNumbers = InputView.askManualLottoNos(scanner, numberOfManualLottos);

LottoGame lottoGame = new LottoGame(payment, manualNumbers);
OutputView.showAllLottos(lottoGame.getAllLotto(), numberOfManualLottos);

WinningNos winningNos = new WinningNos(
InputView.askWinningNos(scanner), InputView.askBonusNo(scanner)
);
LottoAnalyzer lottoAnalyzer = lottoGame.getLottoAnalyzer(winningNos);
OutputView.showAnalysis(lottoAnalyzer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
44 changes: 44 additions & 0 deletions src/main/java/lottodomain/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package lottodomain;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public enum Rank {
FIRST(6, 2000000000),
SECOND(5, 30000000),
THIRD(5, 1500000),
FOURTH(4, 50000),
FIFTH(3, 5000),
MISS(0, 0);

private int countOfMatch;
private int winningMoney;

private Rank(int countOfMatch, int winningMoney) {
this.countOfMatch = countOfMatch;
this.winningMoney = winningMoney;
}

public int getCountOfMatch() {
return countOfMatch;
}

public int getWinningMoney() {
return winningMoney;
}

public static Rank valueOf(int countOfMatch, boolean matchBonus) {
if (countOfMatch == 5 && matchBonus) {
return SECOND;
}
Map<Integer, Rank> countOfMatchRankMapWithoutSecond = Stream.of(values()).filter(rank -> rank != SECOND)
.collect(Collectors.toMap(Rank::getCountOfMatch, Function.identity()));
Rank result = countOfMatchRankMapWithoutSecond.get(countOfMatch);
if (result == null) {
result = MISS;
}
return result;
}
}
21 changes: 21 additions & 0 deletions src/main/java/lottodomain/WinningLotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package lottodomain;

import java.util.List;

public class WinningLotto {
private List<LottoNo> lottoNos;
private Rank lottoPrize;

public WinningLotto(Lotto lotto, Rank lottoPrize) {
lottoNos = lotto.getLottoNos();
this.lottoPrize = lottoPrize;
}

public List<LottoNo> getLottoNos() {
return lottoNos;
}

public Rank getLottoPrize() {
return lottoPrize;
}
}
23 changes: 23 additions & 0 deletions src/main/java/lottodomain/WinningNos.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package lottodomain;

import java.util.List;
import java.util.stream.Collectors;

public class WinningNos {
private List<LottoNo> winningNos;
private LottoNo bonusNo;

public WinningNos(List<Integer> winningNos, int bonusNo) {
this.winningNos = winningNos.stream().map(number -> new LottoNo(number))
.collect(Collectors.toList());
this.bonusNo = new LottoNo(bonusNo);
}

public int countMatchOf(Lotto lotto) {
return winningNos.stream().filter(lotto::contains).collect(Collectors.toList()).size();
}

public boolean isBonus(Lotto lotto) {
return lotto.contains(bonusNo);
}
}
44 changes: 44 additions & 0 deletions src/main/java/lottoview/InputValidation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package lottoview;

import java.util.List;

public class InputValidation {
private final static int NUMBER_OF_LOTTO_NOS = 6;
private final static int PRICE_PER_LOTTO = 1000;

public static void validatePayment(int payment) throws ViewException {
if (payment < PRICE_PER_LOTTO) {
throw new ViewException("[ViewException] 구입금액은 1000원 이상이어야 합니다");
}
if (payment % PRICE_PER_LOTTO != 0) {
throw new ViewException("[ViewException] 구입금액은 1000원단위로 입력해주세요");
}
}

public static void validateNumberOfLottos(int numberOfLottos) throws ViewException {
if (numberOfLottos < 0) {
throw new ViewException("[ViewException] 로또의 수는 0이상이어야 합니다");
}
}

public static void validateAllLottoNos(List<List<Integer>> lottoNos) throws ViewException {
for (List<Integer> lottoNo : lottoNos) {
validateLottoNos(lottoNo);
}
}

public static void validateLottoNos(List<Integer> lottoNos) throws ViewException {
if (lottoNos.size() != NUMBER_OF_LOTTO_NOS) {
throw new ViewException("[ViewException] 로또 번호는 6자리 입니다");
}
for (int number : lottoNos) {
validateNoRange(number);
}
}

public static void validateNoRange(int number) throws ViewException {
if (number <= 0 || number > 45) {
throw new ViewException("[ViewException] 로또 번호는 1 ~ 45 범위 내의 숫자입니다");
}
}
}
Loading