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
10 changes: 9 additions & 1 deletion src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package lotto;

import lotto.controller.LottoController;
import lotto.domain.LottoFactory;
import lotto.domain.LottoMachine;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
LottoFactory lottoFactory = new LottoFactory();
LottoMachine lottoMachine = new LottoMachine(lottoFactory);
LottoController lottoController = new LottoController(lottoMachine);
Comment on lines +9 to +11
Copy link

Choose a reason for hiding this comment

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

오 의존성 주입을 구현하신 건가요??!?


lottoController.start();
}
}
31 changes: 31 additions & 0 deletions src/main/java/lotto/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package lotto.controller;

import lotto.domain.*;

import java.util.List;

import static lotto.view.Input.*;
import static lotto.view.Output.*;

public class LottoController {

private final LottoMachine lottoMachine;

public LottoController(LottoMachine lottoMachine) {
this.lottoMachine = lottoMachine;
}

public void start() {
try {
LottoMoney money = new LottoMoney(insertLottoMoney());
Lottos lottos = lottoMachine.createLottos(money, insertManualLottoCount());
printLottos(lottos);
List<WinningNumber> winningNumbers = lottoMachine.createWinningNumbers(insertNormalWinningNumbers(), insertBonusWinningNumber());
LottoResult lottoResult = lottoMachine.computeLottoResult(lottos, winningNumbers);
printLottoResult(lottoResult, money);
} catch (IllegalArgumentException error) {
printErrorMessage(error.getMessage());
}
Comment on lines +19 to +28

Choose a reason for hiding this comment

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

사용자가 잘못된 값을 입력할 경우 IllegalArgumentException를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 종료한다.

try-catch 때문에 해당 요구사항을 만족하지 못하는 것 같아요! try-catch는 삭제해도 될 것 같습니다!

}

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

import camp.nextstep.edu.missionutils.Randoms;

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

public class Lotto {
private final int MINIMUM_LOTTO_NUMBER = 1;
private final int MAXIMUM_LOTTO_NUMBER = 45;
private final int LOTTO_TOTAL_COUNT = 6;

private final List<Integer> numbers;

public Lotto(List<Integer> numbers) {
this.numbers = numbers.stream()
.sorted()
.collect(Collectors.toList());
}
Comment on lines +16 to +19
Copy link
Member

Choose a reason for hiding this comment

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

numbers 내부에 존재하는 값들이 모두 1 ~ 45라는 룰을 만족하나요?


public Lotto() {
this.numbers = Randoms.pickUniqueNumbersInRange(MINIMUM_LOTTO_NUMBER, MAXIMUM_LOTTO_NUMBER, LOTTO_TOTAL_COUNT)
.stream()
.sorted()
.collect(Collectors.toList());
}
Comment on lines +21 to +26
Copy link
Member

Choose a reason for hiding this comment

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

Lotto lotto = new Lotto()를 실행했다고 생각해볼게요.
lotto 내부에 어떤 값이 들어있는지 테스트할 수 있나요?
Random으로 값을 생성하는 로직을 직접적으로 의존하고 있어서 테스트할 수 없습니다.

며칠 전에 이동욱 개발자님이 하신 말씀이 생각나네요.
제어할 수 없는 영역에는 의존하지말라!


public List<Integer> getNumbers() {
return this.numbers;
}

public boolean checkContainWinningNumber(Integer winningNumber) {
return numbers.contains(winningNumber);
}
}
14 changes: 14 additions & 0 deletions src/main/java/lotto/domain/LottoFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package lotto.domain;

import java.util.List;

public class LottoFactory {

public Lotto createManualLotto(List<Integer> numbers) {
return new Lotto(numbers);
}

public Lotto createAutoLotto() {
return new Lotto();
}
}
123 changes: 123 additions & 0 deletions src/main/java/lotto/domain/LottoMachine.java
Copy link

Choose a reason for hiding this comment

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

다른 객체들의 역할들을 LottoMachine이 대신하고 있는 것 같아요

Lotto 생성은 Lotto 혹은 Lottos가,
WinningNumbers 생성은 WinningNumber가
결과 계산은 LottoResult가 직접 하도록 하면 어떨까요?

현실 속의 객체와 소프트웨어 객체 사이의 가장 큰 차이점은 무엇일까? 그것은 현실 속에서는 수동적인 존재가 소프트웨어 객체로 구현될 때는 능동적으로 변한다는 것이다.
...
스스로 판매 금액을 계산해서 종이에 기입하는 현실 속의 상품을 상상해 보라. 여러분이 객체지향 세계를 구축할 때 현실에서 가져온 객체들은 현실 속에서는 할 수 없는 어떤 일이라도 할 수 있는 전지전능한 존재가 된다.
<객체지향의 사실과 오해 p.55>

Copy link
Member Author

Choose a reason for hiding this comment

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

아 그렇네요
객체가 능동적으로 자신과 관련된 동작을 책임지도록 하는게 더 낫겠네요 감사합니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package lotto.domain;

import lotto.domain.enumeration.NumberType;
import lotto.domain.enumeration.Ranking;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static lotto.domain.enumeration.Ranking.*;
import static lotto.view.Input.insertLottoNumbers;
import static lotto.view.Output.printInsertManualLottoNumbersRequest;

public class LottoMachine {
private final LottoFactory lottoFactory;

public LottoMachine(LottoFactory lottoFactory) {
this.lottoFactory = lottoFactory;
}

public Lottos createLottos(LottoMoney money, int manualLottoCount) {
List<Lotto> manualLottos = createManualLottos(manualLottoCount);
List<Lotto> autoLottos = createAutoLottos(money.getTotalLottoCount() - manualLottos.size());

return new Lottos(manualLottos, autoLottos);
}

private List<Lotto> createManualLottos(int manualLottoCount) {
List<Lotto> manualLottos = new ArrayList<>();
printInsertManualLottoNumbersRequest();
for (int i = 0; i < manualLottoCount; i++) {
List<Integer> numbers = insertLottoNumbers();
Lotto manualLotto = lottoFactory.createManualLotto(numbers);
Comment on lines +31 to +34
Copy link

Choose a reason for hiding this comment

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

view 메소드들이 서비스로직 내에 있는 것이 좋지 않은 것 같아요! 컨트롤러에서 로또를 입력하고 리스트를 전달받는 게 어떨까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

다시 보니 컨트롤러에서 입력받고 생성은 서비스로직에서 해주면 더 좋을 것 같네요 감사합니다!

manualLottos.add(manualLotto);
}

return manualLottos;
}
Comment on lines +29 to +39

Choose a reason for hiding this comment

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

private List<Lotto> createManualLottos(int manualLottoCount) {
    printInsertManualLottoNumbersRequest();
    return Stream.generate(lottoFactory::createAutoLotto)
            .limit(manualLottoCount)
            .collect(Collectors.toList())
}

이렇게 Stream을 사용하면 가독성이 훨씬 좋아질 것 같아요!


private List<Lotto> createAutoLottos(int autoLottoCount) {
List<Lotto> autoLottos = new ArrayList<>();
for (int i = 0; i < autoLottoCount; i++) {
Lotto autoLotto = lottoFactory.createAutoLotto();
autoLottos.add(autoLotto);
}

return autoLottos;
}

public List<WinningNumber> createWinningNumbers(List<Integer> normalNumbers, Integer bonusNumber) {
List<WinningNumber> totalWinningNumbers = new ArrayList<>();
List<WinningNumber> normalWinningNumbers = createNormalWinningNumbers(normalNumbers);
WinningNumber bonusWinningNumber = createBonusNumber(bonusNumber);

totalWinningNumbers.addAll(normalWinningNumbers);
totalWinningNumbers.add(bonusWinningNumber);
Comment on lines +56 to +57
Copy link

Choose a reason for hiding this comment

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

bonusWinningNumber도 totalWinningNumbers에 포함되어 다음과 같이 에러가 나네요!

image

Copy link
Member Author

Choose a reason for hiding this comment

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

NumberType을 만들어서 WinningNumber 필드로 넣긴 했는데, 활용을 잘 못했네요
수정해보겠습니다!


return totalWinningNumbers;
}

private List<WinningNumber> createNormalWinningNumbers(List<Integer> normalNumbers) {
List<WinningNumber> result = new ArrayList<>();
for (Integer number : normalNumbers) {
WinningNumber normalNumber = new WinningNumber(number, NumberType.NORMAL);
result.add(normalNumber);
}
return result;
}

private WinningNumber createBonusNumber(Integer bonusNumber) {
return new WinningNumber(bonusNumber, NumberType.BOUNS);
}

public LottoResult computeLottoResult(Lottos lottos, List<WinningNumber> winningNumbers) {
Map<Ranking, Integer> winningInfo = new HashMap<>();
Copy link

Choose a reason for hiding this comment

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

key 가 Enum이라면 EnumMap도 추천합니다!


for (Lotto lotto : lottos.getLottos()) {
Ranking ranking = determineRanking(lotto, winningNumbers);
winningInfo.put(ranking, winningInfo.getOrDefault(ranking, 0) + 1);
}
return new LottoResult(winningInfo);
}

private Ranking determineRanking(Lotto lotto, List<WinningNumber> winningNumbers) {
int equalNormalNumberCount = getEqualCount(lotto, winningNumbers);
boolean isBonusEqual = checkBonusEqual(lotto, winningNumbers);

return Ranking.create(equalNormalNumberCount, isBonusEqual);
}

private int getEqualCount(Lotto lotto, List<WinningNumber> winningNumbers) {
return (int) winningNumbers.stream()
.map(WinningNumber::getNumber)
.filter(lotto::checkContainWinningNumber)
.count();
}

private boolean checkBonusEqual(Lotto lotto, List<WinningNumber> winningNumbers) {
return lotto.getNumbers()
.contains(
winningNumbers.stream()
.filter(WinningNumber::isBonus)
.map(WinningNumber::getNumber)
.findFirst().get()
);
}

public static Double calculateProfit(LottoResult lottoResult, LottoMoney money) {
Map<Ranking, Integer> winningInfo = lottoResult.getWinningInfo();
Long value = sum(winningInfo);

return (double) value / (double) money.getPrice();
}

private static Long sum(Map<Ranking, Integer> winningInfo) {
return winningInfo.getOrDefault(FIFTH,0) * FIFTH.getPrizeMoney()
+ winningInfo.getOrDefault(FORTH, 0) * FORTH.getPrizeMoney()
+ winningInfo.getOrDefault(THIRD, 0) * THIRD.getPrizeMoney()
+ winningInfo.getOrDefault(SECOND, 0) * SECOND.getPrizeMoney()
+ winningInfo.getOrDefault(FIRST, 0) * FIRST.getPrizeMoney();
}
}
30 changes: 30 additions & 0 deletions src/main/java/lotto/domain/LottoMoney.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package lotto.domain;

public class LottoMoney {
private final String MONEY_MUST_OVER_1000 = "구매 금액은 1000원 이상을 입력해주세요.";
private final String MONEY_UNIT_IS_1000 = "구매 금액은 1000원 단위로 입력해주세요.";
private final int LOTTO_PRICE_UNIT = 1000;
Comment on lines +4 to +6

Choose a reason for hiding this comment

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

Suggested change
private final String MONEY_MUST_OVER_1000 = "구매 금액은 1000원 이상을 입력해주세요.";
private final String MONEY_UNIT_IS_1000 = "구매 금액은 1000원 단위로 입력해주세요.";
private final int LOTTO_PRICE_UNIT = 1000;
private static final String MONEY_MUST_OVER_1000 = "구매 금액은 1000원 이상을 입력해주세요.";
private static final String MONEY_UNIT_IS_1000 = "구매 금액은 1000원 단위로 입력해주세요.";
private static final int LOTTO_PRICE_UNIT = 1000;

상수 선언은 보통 static final을 함께 사용합니다!

private final int price;

public LottoMoney(int price) {
validatePrice(price);
this.price = price;
}

private void validatePrice(int price) {
if (price < LOTTO_PRICE_UNIT) {
throw new IllegalArgumentException(MONEY_MUST_OVER_1000);
}
if (price % LOTTO_PRICE_UNIT != 0) {
throw new IllegalArgumentException(MONEY_UNIT_IS_1000);
}
}

public int getPrice() {
return price;
}

public int getTotalLottoCount() {
return price / LOTTO_PRICE_UNIT;
}
}
17 changes: 17 additions & 0 deletions src/main/java/lotto/domain/LottoResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lotto.domain;

import lotto.domain.enumeration.Ranking;

import java.util.Map;

public class LottoResult {
private final Map<Ranking, Integer> winningInfo;

public LottoResult(Map<Ranking, Integer> winningInfo) {
this.winningInfo = winningInfo;
}

public Map<Ranking, Integer> getWinningInfo() {
return this.winningInfo;
}
}
32 changes: 32 additions & 0 deletions src/main/java/lotto/domain/Lottos.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package lotto.domain;

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

public class Lottos {
private List<Lotto> lottos;
private Integer manualLottoCount;
private Integer autoLottoCount;
Comment on lines +8 to +9

Choose a reason for hiding this comment

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

자료형으로 int가 아닌 Integer를 사용하신 이유가 있으신가요?


public Lottos(List<Lotto> manualLottos, List<Lotto> autoLottos) {
List<Lotto> lottos = new ArrayList<>();
lottos.addAll(manualLottos);
lottos.addAll(autoLottos);
Comment on lines +12 to +14

Choose a reason for hiding this comment

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

List<Lotto> lottos = Stream.concat(manualLottos.stream(), autoLottos.stream())
                .collect(Collectors.toList());

이런 방식으로도 두 개의 리스트를 합칠 수 있습니다!


this.lottos = lottos;
this.manualLottoCount = manualLottos.size();
this.autoLottoCount = autoLottos.size();
}

public int getManualLottoCount() {
return manualLottoCount;
}

public int getAutoLottoCount() {
return autoLottoCount;
}

public List<Lotto> getLottos() {
return lottos;
}
}
22 changes: 22 additions & 0 deletions src/main/java/lotto/domain/WinningNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package lotto.domain;

import lotto.domain.enumeration.NumberType;

public class WinningNumber {
private final Integer number;
private final NumberType type;

public WinningNumber(Integer number, NumberType type) {
this.number = number;
this.type = type;
}

public Integer getNumber() {
return number;
}

public boolean isBonus() {
return type == NumberType.BOUNS;
}

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

public enum NumberType {
BOUNS,
NORMAL
}
46 changes: 46 additions & 0 deletions src/main/java/lotto/domain/enumeration/Ranking.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package lotto.domain.enumeration;

import java.util.Arrays;

public enum Ranking {

FIRST(2_000_000_000L,6,false),
SECOND(30_000_000L, 5, true),
THIRD(1_500_000L, 5, false),
FORTH(50_000L, 4, false),
FIFTH(5_000L, 3, false),
NON_WINNER(0L, 0, false);

private final Long prizeMoney;
private final int equalCount;
private final boolean containBonus;

Choose a reason for hiding this comment

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

해당 변수는 선언 후 사용되고 있지 않네요!

private static final int CHECK_SECOND_OR_THIRD_CONDITION = 5;

Ranking(Long prizeMoney, int equalCount, boolean containBonus) {
this.equalCount = equalCount;
this.prizeMoney = prizeMoney;
this.containBonus = containBonus;
}

public static Ranking create(int equalCount, boolean isBonusContain) {
if (equalCount == CHECK_SECOND_OR_THIRD_CONDITION) {
return getSecondOrThird(isBonusContain);
}

return Arrays.stream(Ranking.values())
.filter(ranking -> ranking.equalCount == equalCount)
.findFirst()
.orElse(NON_WINNER);
}

private static Ranking getSecondOrThird(boolean isBonusContain) {
if (isBonusContain){
return Ranking.SECOND;
}
return Ranking.THIRD;
}
Comment on lines +36 to +41
Copy link

Choose a reason for hiding this comment

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

만약 2,3등의 수상 조건이 변경된다면??


public Long getPrizeMoney() {
return this.prizeMoney;
}
}
Loading