Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
95d4388
[refactor] private 인스턴스 변수로 변경
GunBros Dec 8, 2025
8f3eb6f
[refactor] LottoResult에서 수익률을 계산하도록 수정
GunBros Dec 8, 2025
5b24f98
[refactor] 인스턴스 변수 private final로 수정
GunBros Dec 8, 2025
2d03c79
[refactor] 위치 값은 같지 않고 포함 여부만 체크하도록 수정
GunBros Dec 8, 2025
015df32
[refactor] UI 수정
GunBros Dec 8, 2025
c5f098f
[feat] 가변 인자를 가지는 생성자 추가
GunBros Dec 8, 2025
2f009a1
[feat] 2등 보너스 추가
GunBros Dec 8, 2025
ca58738
[feat] 보너스 숫자 체크 로직 추가
GunBros Dec 8, 2025
4562f03
[feat] 생성자 추가
GunBros Dec 8, 2025
13f270f
[feat] 보너스 숫자 체크로직 추가
GunBros Dec 8, 2025
8adf298
[feat] 보너스 숫자 Print 구현
GunBros Dec 8, 2025
da9e76a
[refactor] 불필요한 함수 제거
GunBros Dec 11, 2025
6372c85
[refactor] 등수 구하는 책임 위임
GunBros Dec 11, 2025
7176377
[refactor] 등수 구하는 책임 위임에 따른 리팩토링
GunBros Dec 11, 2025
eb64ba1
[refactor] 등수 구하는 책임 위임에 따른 리팩토링
GunBros Dec 11, 2025
2fcceec
[feat] 로또 숫자를 캐시하는 유틸 추가
GunBros Dec 11, 2025
9ca7513
[feat] 유효성 검사 추가
GunBros Dec 11, 2025
e397223
[refactor 주생성자/부생성자 분리
GunBros Dec 11, 2025
b2a6e82
[refactor] 이름 변경
GunBros Dec 11, 2025
57d3d57
[refactor] LottoNumbers의 주/부 생성자 추가
GunBros Dec 12, 2025
9ceb94b
[refactor] LottoNumberParser를 통해 파싱 구현
GunBros Dec 12, 2025
0b17acb
[feat] get 오버로드 메소드 추가
GunBros Dec 12, 2025
aef4391
[test] LottoNumberParserTest 추가
GunBros Dec 12, 2025
b1aeb06
[test] 보너스 숫자 중복 테스트
GunBros Dec 12, 2025
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
18 changes: 12 additions & 6 deletions src/main/java/lotto/LottoApplication.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
package lotto;

import lotto.controller.LottoMachine;
import lotto.controller.WinningLotto;
import lotto.domain.WinningLotto;
import lotto.domain.Lotto;
import lotto.domain.LottoNumber;
import lotto.domain.LottoResult;
import lotto.ui.InputView;
import lotto.ui.ResultView;
import lotto.util.LottoNumberParser;

public class LottoApplication {
public static void main(String[] args) {
String purchaseAmount = InputView.getPurchaseAmount();

LottoMachine lottoMachine = new LottoMachine(purchaseAmount);
Lotto lotto = lottoMachine.generate();
ResultView.printLottoCount(lotto.count());
ResultView.printLottoNumbersList(lotto.toString());

ResultView.printLotto(lotto);

String winningNumbers = InputView.getWinningNumber();
WinningLotto winningLotto = new WinningLotto(LottoNumberParser.parse(winningNumbers));
String bonusNumber = InputView.getBonusNumber();

WinningLotto winningLotto = new WinningLotto(winningNumbers, bonusNumber);
LottoResult result = lotto.getMatchResult(winningLotto);

ResultView.printLottoResult(winningLotto.getResult(lotto));
ResultView.printProfit(winningLotto.getProfit(lotto));
ResultView.printLottoResult(result.toString());
ResultView.printProfit(result.getProfit());
}
}
3 changes: 2 additions & 1 deletion src/main/java/lotto/controller/LottoMachine.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lotto.domain.Lotto;
import lotto.domain.LottoNumbers;
import lotto.domain.LottoPrice;
import lotto.util.LottoNumberParser;
import lotto.util.RandomNumbersGenerator;

import java.util.ArrayList;
Expand All @@ -23,7 +24,7 @@ public Lotto generate() {
List<LottoNumbers> lottoNumbersList = new ArrayList<>();

for (int i = 0; i < lottoPrice.count(); i++) {
lottoNumbersList.add(new LottoNumbers(RandomNumbersGenerator.randomNumbers()));
lottoNumbersList.add(new LottoNumbers(LottoNumberParser.parse(RandomNumbersGenerator.randomNumbers())));
}

return new Lotto(lottoPrice, lottoNumbersList);
Expand Down
23 changes: 0 additions & 23 deletions src/main/java/lotto/controller/WinningLotto.java

This file was deleted.

12 changes: 4 additions & 8 deletions src/main/java/lotto/domain/Lotto.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,25 @@
import java.util.stream.Collectors;

public class Lotto {
LottoPrice price;
List<LottoNumbers> lottoNumbers;
private final LottoPrice price;
Copy link
Contributor

Choose a reason for hiding this comment

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

수익률 구하는 부분이 이동했으면 price 필드 값은 Lotto에서 제거해도 되지 않을까?

private final List<LottoNumbers> lottoNumbers;

public Lotto(LottoPrice price, List<LottoNumbers> lottoNumbers) {
this.price = price;
this.lottoNumbers = lottoNumbers;
}

public LottoResult getMatchResult(LottoNumbers winningNumbers) {
public LottoResult getMatchResult(WinningLotto winningLotto) {
LottoResult result = new LottoResult();

for (LottoNumbers lottoNumbers : lottoNumbers) {
LottoRank rank = lottoNumbers.getMatchedRank(winningNumbers);
LottoRank rank = winningLotto.getMatchedRank(lottoNumbers);
result.add(rank);
}

return result;
}

public double calculateProfit(int prize) {
return price.getProfit(prize);
}

public String count() {
return String.valueOf(price.count());
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/lotto/domain/LottoNumber.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
public class LottoNumber {
private final int number;
Copy link
Contributor

Choose a reason for hiding this comment

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

상황

  • 웹 백엔드 서버로 1만명의 사용자가 동시에 당첨 여부를 확인할 수 있어야 한다.
  • 1명의 사용자는 평균 5장의 로또를 구매한 상태이다.

위 요구사항을 서버에서 생성되는 LottoNumber의 인스턴스의 갯수는?
1 * 5장 * 6개 숫자/1장 * 1만명 = 30만개이다.

동시에 생성되는 인스턴스 갯수가 너무 많다.
인스턴스 갯수를 줄일 수 있는 방법은?
로또 숫자 값을 LottoNumber 객체로 래핑하는 경우 매번 인스턴스가 생성되기 때문에 인스턴스의 갯수가 너무 많아져 성능이 떨어질 수 있다.
LottoNumber 인스턴스를 생성한 후 재사용할 수 있도록 구현한다.

힌트 : Map과 같은 곳에 인스턴스를 생성한 후 재사용하는 방법을 찾아본다.****

Copy link
Contributor

Choose a reason for hiding this comment

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

지난 번에 피드백 남긴 이 부분 도전해 보면 어떨까?


public LottoNumber(String number) {
Copy link
Contributor

Choose a reason for hiding this comment

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

캐싱을 담당하는 기능을 LottoNumber 외부에서 구현하고 이와 같이 생성자를 public으로 구현하면 LottoNumberCache 존재를 모르는 개발자는 이 생성자를 통해 LottoNumber를 직접 생성할 수 있다.
다른 개발자가 캐싱된 LottoNumber만 사용할 수 있도록 강제해 볼 것으로 추천한다.

힌트: LottoNumber에 정적 팩터리 메서드 추가해 해결

this(Integer.parseInt(number));
}

public LottoNumber(int number) {
this.number = number;
}
Expand Down
32 changes: 17 additions & 15 deletions src/main/java/lotto/domain/LottoNumbers.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,43 @@
package lotto.domain;

import lotto.util.LottoNumberParser;

import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class LottoNumbers {
private final List<LottoNumber> numbers;

public LottoNumbers(List<Integer> numbers) {
this.numbers = toLottoNumber(numbers);
public LottoNumbers(int... numbers) {
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

this(LottoNumberParser.parse(numbers));
}

private static List<LottoNumber> toLottoNumber(List<Integer> numbers) {
List<LottoNumber> lottoNumbers = new ArrayList<>();

for (int number : numbers) {
lottoNumbers.add(new LottoNumber(number));
}
public LottoNumbers(String numbers) {
this(LottoNumberParser.parse(numbers));
}

return lottoNumbers;
public LottoNumbers(List<LottoNumber> numbers) {
this.numbers = numbers;
}

public LottoRank getMatchedRank(LottoNumbers other) {
public int getMatchCount(LottoNumbers other) {
int matchCount = 0;

for (int i = 0; i < numbers.size(); i++) {
if (matchesAtIndex(i, other)) {
for (LottoNumber number : numbers) {
if (other.contains(number)) {
matchCount++;
}
}

return LottoRank.of(matchCount);
return matchCount;
}

private boolean matchesAtIndex(int index, LottoNumbers other) {
return numbers.get(index).equals(other.numbers.get(index));
public boolean contains(LottoNumber number) {
return numbers.contains(number);
}

@Override
Expand Down
35 changes: 25 additions & 10 deletions src/main/java/lotto/domain/LottoRank.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,56 @@
package lotto.domain;

public enum LottoRank {
FIRST(6, 2_000_000_000),
SECOND(5, 30_000_000),
THIRD(4, 1_500_000),
FOURTH(3, 50_000),
NONE(0, 0);
FIRST(6, 2_000_000_000, false),
SECOND_BONUS(5, 30_000_000, true),
SECOND(5, 1_500_000, false),
THIRD(4, 50_000, false),
FOURTH(3, 5_000, false),
NONE(0, 0, false);


private final int matchCount;
private final int prize;
private final boolean requireBonus;

LottoRank(int matchCount, int prize) {
LottoRank(int matchCount, int prize, boolean requireBonus) {
this.matchCount = matchCount;
this.prize = prize;
this.requireBonus = requireBonus;
}

public static LottoRank of(int matchCount) {
public static LottoRank of(int matchCount, boolean bonusMatch) {
for (LottoRank rank : LottoRank.values()) {
if (isMatch(rank, matchCount)) {
if (isMatch(rank, matchCount, bonusMatch)) {
return rank;
}
}

return NONE;
}

public static boolean isMatch(LottoRank rank, int matchCount) {
public static boolean isMatch(LottoRank rank, int matchCount, boolean requireBonus) {
return isCountMatch(rank, matchCount) && isBonusRequireMatch(rank, requireBonus);
}

private static boolean isCountMatch(LottoRank rank, int matchCount) {
return rank.matchCount == matchCount;
}

private static boolean isBonusRequireMatch(LottoRank rank, boolean requireBonus) {
return rank.requireBonus == requireBonus;
}

public int getPrize(LottoRank rank, int count) {
return rank.prize * count;
}

@Override
public String toString() {
return String.format("%d개 일치 (%d원)", matchCount, prize);
return String.format("%d개%s(%d원)", matchCount, matchString(), prize);
}

private String matchString() {
return requireBonus ? ", 보너스 볼 일치" : " 일치";
}
}
16 changes: 15 additions & 1 deletion src/main/java/lotto/domain/LottoResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void add(LottoRank rank) {
matchResult.put(rank, matchResult.get(rank) + 1);
}

public int prize() {
private int prize() {
int prize = 0;
for (LottoRank rank : LottoRank.values()) {
prize += rank.getPrize(rank, matchResult.get(rank));
Expand All @@ -34,6 +34,20 @@ public int prize() {
return prize;
}

private LottoPrice getPrice() {
int count = 0;
for (LottoRank rank : LottoRank.values()) {
count += matchResult.get(rank);
}

return new LottoPrice(count);
}

public String getProfit() {
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

LottoPrice price = getPrice();
return String.valueOf(price.getProfit(prize()));
}

@Override
public String toString() {
return Arrays.stream(LottoRank.values())
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/lotto/domain/WinningLotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package lotto.domain;


import lotto.util.LottoNumberParser;

public class WinningLotto {
private final LottoNumbers winningNumbers;
private final LottoNumber bonusNumber;

public WinningLotto(String winningNumbers, String bonusNumber) {
this(new LottoNumbers(LottoNumberParser.parse(winningNumbers)), new LottoNumber(bonusNumber));
}

public WinningLotto(LottoNumbers winningNumbers, LottoNumber bonusNumber) {
if (winningNumbers.contains(bonusNumber)) {
throw new IllegalArgumentException(String.format("당첨 숫자와 보너스 숫자가 일치합니다. (%d)", bonusNumber));
}

this.winningNumbers = winningNumbers;
this.bonusNumber = bonusNumber;
}

public LottoRank getMatchedRank(LottoNumbers numbers) {
int matchCount = winningNumbers.getMatchCount(numbers);
return LottoRank.of(matchCount, numbers.contains(bonusNumber));
}
}
6 changes: 6 additions & 0 deletions src/main/java/lotto/ui/InputView.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class InputView {
private static final String WINNING_NUMBER_MESSAGE = "지난 주 당첨 번호 6개를 입력해 주세요.";

private static final Scanner scanner = new Scanner(System.in);
public static final String BONUS_BALL_MESSAGE = "보너스볼을 입력해주세요";

public static String getPurchaseAmount() {
System.out.println(PURCHASE_AMOUNT_MESSAGE);
Expand All @@ -18,5 +19,10 @@ public static String getWinningNumber() {
return scanner.nextLine();
}

public static String getBonusNumber() {
System.out.println(BONUS_BALL_MESSAGE);
return scanner.nextLine();
}


}
11 changes: 9 additions & 2 deletions src/main/java/lotto/ui/ResultView.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
package lotto.ui;

import lotto.domain.Lotto;

public class ResultView {
private static final String LOTTO_COUNT_MESSAGE = "%s개를 구매했습니다.\n";
private static final String LOTTO_RESULT_MESSSAGE = "당첨 통계\n-------";

public static void printLottoCount(String lottoCount) {
private static void printLottoCount(String lottoCount) {
System.out.printf(LOTTO_COUNT_MESSAGE, lottoCount);
}

public static void printLottoNumbersList(String lottoList) {
private static void printLottoNumbersList(String lottoList) {
System.out.println(lottoList);
}

public static void printLotto(Lotto lotto) {
printLottoCount(lotto.count());
printLottoNumbersList(lotto.toString());
}

public static void printLottoResult(String lottoResult) {
System.out.println(LOTTO_RESULT_MESSSAGE);
System.out.println(lottoResult);
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/lotto/util/LottoNumberCache.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package lotto.util;

import lotto.domain.LottoNumber;

import java.util.HashMap;
import java.util.Map;

public class LottoNumberCache {
private static final int MIN = 1;
private static final int MAX = 45;
private static final LottoNumber NONE = new LottoNumber(0);
private static final Map<Integer, LottoNumber> Cache = new HashMap<>();

static {
for (int i = MIN; i <= MAX; i++) {
Cache.put(i, new LottoNumber(i));
}
}

public static LottoNumber get(int value) {
LottoNumber lottoNumber = Cache.getOrDefault(value, NONE);
if (lottoNumber == NONE) {
throw new IllegalArgumentException("로또의 숫자는 1에서 45 사이여야합니다.");
}
return Cache.get(value);
}

public static LottoNumber get(String value) {
return get(Integer.parseInt(value));
}
}
Loading