-
Notifications
You must be signed in to change notification settings - Fork 2k
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
[로또] 이준섭 미션 제출합니다. #2112
Open
junseoplee
wants to merge
31
commits into
woowacourse-precourse:main
Choose a base branch
from
junseoplee:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
[로또] 이준섭 미션 제출합니다. #2112
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
6cbdbef
feat: 로또 구입금액을 입력받은 후 입력 금액을 검증하는 기능 구현
junseoplee 7276e90
경
junseoplee b6f34e0
Revert "경"
junseoplee 5fb75e0
refactor: 패키지, 클래스 구분 및 생성, 구입금액 입력 및 유효성 검사 기능 재구현
junseoplee 0bf4e6f
feat: 로또 번호를 생성 및 출력하는 기능 구현.
junseoplee 93faf63
fix: 정렬이 제대로 되지 않는 문제를 해결, 변수명을 명확하게 변경
junseoplee 14f83cd
fix: 실행결과를 양식에 맞게 수정
junseoplee c3ec26b
feat: 당첨 번호와 보너스 번호를 입력 받아 객체를 생성, 유효성 검사를 진행하는 기능 구현
junseoplee 96f6737
fix: 불필요한 import 삭제
junseoplee 0ccdc47
feat: 결과 출력 기능 구현
junseoplee e4cf662
feat: 구입금액이 숫자인지 검증하는 기능 구현
junseoplee c2c7bc9
feat: 수익률 계산 기능 구현
junseoplee 68d01e7
docs: 구현할 기능 목록 정리
junseoplee cb5e447
docs: 구현할 기능 목록 정리
junseoplee 177b560
refactor: 패키지와 클래스 구분 및 리팩토링, 보너스 번호 검사가 제대로 동작하지 않는 오류 수정
junseoplee c12be99
fix: getter의 위치 등 컨벤션 수정
junseoplee 2b5fd6f
fix: 변수명 수정
junseoplee c0fda34
fix: 구현 수정
junseoplee 1829f9c
docs: 구현할 기능 목록 정리
junseoplee 32f7bd4
fix: WinningCheck enum의 상금을 String에서 int로 변경
junseoplee d62f6cd
fix: 불필요한 변수 및 주석 제거
junseoplee e22152e
docs: 해결한 문제 항목 삭제
junseoplee 3e0d8fc
docs: 오타 수정
junseoplee 76224f2
fix: 단위 구분을 위해 '_' 삽입
junseoplee 58013f8
refactor: Calculator 클래스 책임 분리 및 수정
junseoplee c331b18
fix: 필요 없는 static 삭제와 안정성을 위한 final 추가
junseoplee ea0ea00
refactor: PurchaseAmount 클래스와 InputManager 리팩토링
junseoplee 71be87d
fix: 클래스명을 명사형으로 변경
junseoplee 9aa81c9
fix: 리팩토링된 항목들을 수정
junseoplee 3ae6d9e
refactor: 에러 메세지를 enum에서 관리
junseoplee 63bf89d
feat: 도메인 테스트 코드 구현
junseoplee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
Application과 동일 선상에 RunLotto 클래스 생성 | ||
|
||
LottoManager에 필요한 기능들을 패키지로 묶어보자 | ||
|
||
- 도메인 모델 패키지 (domain) | ||
- 사용자로부터 입력받은 구입금액을 저장하는 클래스 PurchaseAmount | ||
- 난수 생성된 로또 번호가 있는 클래스 Lotto | ||
- 사용자로부터 로또 번호 6개와 보너스 번호 1개를 입력받아 저장하는 클래스 UserInputNumbers | ||
- 상금과 당첨 수를 저장하는 열거형 enum WinningCheck | ||
- 비즈니스 로직을 수행하는 서비스 패키지 (service) | ||
- 당첨 결과를 계산하는 클래스 LottoResultCalculator | ||
- 수익률을 계산하는 클래스 LottoProfitRateCalculator | ||
- 구입금액만큼 로또를 발행하는 클래스 LottoGenerator | ||
- 각종 메서드가 있는 패키지 (util) | ||
- 사용자로부터 값들을 입력받는 클래스 InputManager | ||
- 결과들을 출력하는 클래스 OutputManager | ||
|
||
동작 구조 | ||
|
||
1. receivePurchaseAmount()로 구입금액을 입력받아 PurchaseAmount에 객체로 저장(유효성 검사) | ||
2. 생성된 PurchaseAmount를 받아 generateLottos(PurchaseAmount purchaseAmount) | ||
입력받은 양 만큼 Lotto 객체로 로또를 발행(유효성 검사) -> 리턴 값은 List<Lotto>로 generatedLottos를 리턴 | ||
3. generatedLottos를 매개변수로 받아 printGeneratedLottoNumbers(List<Lotto> lottos) 생성된 로또들을 출력 | ||
4. calculateWinningResult(List<Lotto> lottos, UserInputNumbers receivedLotto) | ||
Map<WinningCheck, Integer>을 이용해서 result를 생성 WinningCheck에 열거형으로 상금과 당첨 수를 저장 | ||
Lotto클래스에서 각 로또 당 matchCount와 bonusMatch를 가져온다 -> WinningCheck.getPrize(matchCount, bonusMatch) | ||
-> 각 로또 당 상금과 수를 result에 저장 후 리턴 | ||
5. calculateProfitRate(PurchaseAmount purchaseAmount, Map<WinningCheck, Integer> result) | ||
구입금액과 결과를 비교하여 수익률을 계산(소수 둘째에서 반올림) -> 리턴 값은 double profitRate | ||
6. printResults(Map<WinningCheck, Integer> result, double profitRate) 최종 결과 출력 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
package lotto; | ||
|
||
public class Application { | ||
public static void main(String[] args) { | ||
// TODO: 프로그램 구현 | ||
} | ||
|
||
public static void main(String[] args) { | ||
LottoManager lottoManager = new LottoManager(); | ||
lottoManager.runLotto(); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package lotto; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import lotto.domain.Lotto; | ||
import lotto.domain.PurchaseAmount; | ||
import lotto.domain.UserInputNumbers; | ||
import lotto.service.LottoProfitRateCalculator; | ||
import lotto.service.LottoResultCalculator; | ||
import lotto.util.InputManager; | ||
import lotto.service.LottoGenerator; | ||
import lotto.util.OutputManager; | ||
import lotto.domain.WinningCheck; | ||
|
||
public class LottoManager { | ||
|
||
private final InputManager inputManager = new InputManager(); | ||
private final LottoGenerator lottoGenerator = new LottoGenerator(); | ||
private final LottoResultCalculator lottoResultCalculator = new LottoResultCalculator(); | ||
private final LottoProfitRateCalculator lottoProfitRateCalculator = new LottoProfitRateCalculator(); | ||
private final OutputManager outputManager = new OutputManager(); | ||
|
||
public void runLotto() { | ||
PurchaseAmount purchaseAmount = inputManager.receivePurchaseAmount(); | ||
|
||
List<Lotto> generatedLottos = lottoGenerator.generateLottos(purchaseAmount); | ||
outputManager.printGeneratedLottoNumbers(generatedLottos); | ||
|
||
UserInputNumbers userInputNumbers = inputManager.receiveLottoNumber(); | ||
|
||
Map<WinningCheck, Integer> result = lottoResultCalculator | ||
.calculateWinningResult(generatedLottos, userInputNumbers); | ||
double profitRate = lottoProfitRateCalculator | ||
.calculateProfitRate(purchaseAmount, result); | ||
|
||
outputManager.printResults(result, profitRate); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package lotto.domain; | ||
|
||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import lotto.util.ErrorMessage; | ||
|
||
public class Lotto { | ||
|
||
public static final int MIN_LOTTO_NUMBER = 1; | ||
public static final int MAX_LOTTO_NUMBER = 45; | ||
public static final int SIZE_OF_LOTTO = 6; | ||
private final List<Integer> lottoNumbers; | ||
|
||
public Lotto(List<Integer> lottoNumbers) { | ||
validateLottoNumbers(lottoNumbers); | ||
this.lottoNumbers = lottoNumbers; | ||
} | ||
|
||
public int getMatchCount(UserInputNumbers receivedLotto) { | ||
return (int) lottoNumbers.stream() | ||
.filter(number -> receivedLotto.getReceivedLottoNumbers().contains(number)) | ||
.count(); | ||
} | ||
|
||
public boolean isBonusMatch(UserInputNumbers receivedLotto) { | ||
return lottoNumbers.contains(receivedLotto.getBonusNumber()); | ||
} | ||
|
||
private void validateLottoNumbers(List<Integer> lottoNumbers) { | ||
if (lottoNumbers.size() != SIZE_OF_LOTTO) { | ||
throw new IllegalArgumentException(ErrorMessage.NOT_SIX_NUMBERS.getMessage()); | ||
} | ||
|
||
for (int number : lottoNumbers) { | ||
if (number < MIN_LOTTO_NUMBER || number > MAX_LOTTO_NUMBER) { | ||
throw new IllegalArgumentException(ErrorMessage.NOT_IN_RANGE.getMessage()); | ||
} | ||
} | ||
|
||
Set<Integer> uniqueNumbers = new HashSet<>(lottoNumbers); | ||
if (uniqueNumbers.size() < lottoNumbers.size()) { | ||
throw new IllegalArgumentException(ErrorMessage.MUST_NOT_DUPLICATE.getMessage()); | ||
} | ||
} | ||
|
||
public List<Integer> getLottoNumbers() { | ||
return lottoNumbers; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package lotto.domain; | ||
|
||
import lotto.util.ErrorMessage; | ||
|
||
public class PurchaseAmount { | ||
|
||
public static final int LOTTO_PRICE = 1000; | ||
private final int purchaseAmount; | ||
|
||
public PurchaseAmount(int inputAmount) { | ||
validatePurchaseAmount(inputAmount); | ||
this.purchaseAmount = inputAmount; | ||
} | ||
|
||
private void validatePurchaseAmount(int inputAmount) { | ||
if (inputAmount % LOTTO_PRICE != 0) { | ||
throw new IllegalArgumentException(ErrorMessage.NOT_A_UNIT_OF_1000.getMessage()); | ||
} | ||
} | ||
|
||
public int getPurchaseAmount() { | ||
return purchaseAmount; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package lotto.domain; | ||
|
||
import static lotto.domain.Lotto.MIN_LOTTO_NUMBER; | ||
import static lotto.domain.Lotto.MAX_LOTTO_NUMBER; | ||
import static lotto.domain.Lotto.SIZE_OF_LOTTO; | ||
|
||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import lotto.util.ErrorMessage; | ||
|
||
public class UserInputNumbers { | ||
|
||
private final List<Integer> receivedLottoNumbers; | ||
private final int bonusNumber; | ||
|
||
public UserInputNumbers(List<Integer> receivedLottoNumbers, int bonusNumber) { | ||
validateLottoNumbers(receivedLottoNumbers); | ||
this.receivedLottoNumbers = receivedLottoNumbers; | ||
validateBonusNumbers(bonusNumber); | ||
this.bonusNumber = bonusNumber; | ||
} | ||
|
||
private void validateLottoNumbers(List<Integer> receivedLottoNumbers) { | ||
if (receivedLottoNumbers.size() != SIZE_OF_LOTTO) { | ||
throw new IllegalArgumentException(ErrorMessage.NOT_SIX_NUMBERS.getMessage()); | ||
} | ||
|
||
for (int number : receivedLottoNumbers) { | ||
if (number < MIN_LOTTO_NUMBER || number > MAX_LOTTO_NUMBER) { | ||
throw new IllegalArgumentException(ErrorMessage.NOT_IN_RANGE.getMessage()); | ||
} | ||
} | ||
|
||
Set<Integer> uniqueNumbers = new HashSet<>(receivedLottoNumbers); | ||
if (uniqueNumbers.size() < receivedLottoNumbers.size()) { | ||
throw new IllegalArgumentException(ErrorMessage.MUST_NOT_DUPLICATE.getMessage()); | ||
} | ||
} | ||
|
||
private void validateBonusNumbers(int bonusNumber) { | ||
if (bonusNumber < MIN_LOTTO_NUMBER || bonusNumber > MAX_LOTTO_NUMBER) { | ||
throw new IllegalArgumentException(ErrorMessage.NOT_IN_RANGE.getMessage()); | ||
} | ||
|
||
if (new HashSet<>(receivedLottoNumbers).contains(bonusNumber)) { | ||
throw new IllegalArgumentException(ErrorMessage.MUST_NOT_DUPLICATE.getMessage()); | ||
} | ||
} | ||
|
||
public List<Integer> getReceivedLottoNumbers() { // 결과 계산에 호출됨 | ||
return receivedLottoNumbers; | ||
} | ||
|
||
public int getBonusNumber() { | ||
return bonusNumber; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package lotto.domain; | ||
|
||
public enum WinningCheck { | ||
LOSE(0, 0), | ||
FIFTH_PRIZE(5_000, 3), | ||
FOURTH_PRIZE(50_000, 4), | ||
THIRD_PRIZE(1_500_000, 5, false), | ||
SECOND_PRIZE(30_000_000, 5, true), | ||
FIRST_PRIZE(2_000_000_000, 6); | ||
|
||
private final int prizeAmount; | ||
private final int matchingCount; | ||
private final boolean hasBonus; | ||
|
||
WinningCheck(int prizeAmount, int matchingCount) { | ||
this.prizeAmount = prizeAmount; | ||
this.matchingCount = matchingCount; | ||
this.hasBonus = false; | ||
} | ||
|
||
WinningCheck(int prizeAmount, int matchingCount, boolean hasBonus) { | ||
this.prizeAmount = prizeAmount; | ||
this.matchingCount = matchingCount; | ||
this.hasBonus = hasBonus; | ||
} | ||
|
||
public static WinningCheck getPrize(int matchCount, boolean bonusMatch) { | ||
if (matchCount == 6) { | ||
return FIRST_PRIZE; | ||
} | ||
if (matchCount == 5) { | ||
return bonusMatch ? SECOND_PRIZE : THIRD_PRIZE; | ||
} | ||
if (matchCount == 4) { | ||
return FOURTH_PRIZE; | ||
} | ||
if (matchCount == 3) { | ||
return FIFTH_PRIZE; | ||
} | ||
return LOSE; | ||
} | ||
|
||
public int getPrizeAmount() { | ||
return prizeAmount; | ||
} | ||
|
||
public int getMatchingCount() { | ||
return matchingCount; | ||
} | ||
|
||
public boolean hasBonus() { | ||
return hasBonus; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package lotto.service; | ||
|
||
import static lotto.domain.Lotto.MAX_LOTTO_NUMBER; | ||
import static lotto.domain.Lotto.MIN_LOTTO_NUMBER; | ||
import static lotto.domain.Lotto.SIZE_OF_LOTTO; | ||
import static lotto.domain.PurchaseAmount.LOTTO_PRICE; | ||
|
||
import camp.nextstep.edu.missionutils.Randoms; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import lotto.domain.Lotto; | ||
import lotto.domain.PurchaseAmount; | ||
|
||
public class LottoGenerator { | ||
|
||
public static List<Lotto> generateLottos(PurchaseAmount purchaseAmount) { | ||
int numberOfLotto = purchaseAmount.getPurchaseAmount() / LOTTO_PRICE; | ||
System.out.println("\n" + numberOfLotto + "개를 구매했습니다."); | ||
|
||
List<Lotto> generatedLottos = new ArrayList<>(); | ||
|
||
for (int i = 0; i < numberOfLotto; i++) { | ||
List<Integer> lottoNumbers = | ||
Randoms.pickUniqueNumbersInRange(MIN_LOTTO_NUMBER, MAX_LOTTO_NUMBER, SIZE_OF_LOTTO); | ||
|
||
try { | ||
Lotto lotto = new Lotto(lottoNumbers); | ||
generatedLottos.add(lotto); | ||
} catch (IllegalArgumentException e) { | ||
System.out.println(e.getMessage()); | ||
i--; | ||
} | ||
} | ||
|
||
return generatedLottos; | ||
} | ||
|
||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/lotto/service/LottoProfitRateCalculator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package lotto.service; | ||
|
||
import java.text.DecimalFormat; | ||
import java.util.Map; | ||
import lotto.domain.PurchaseAmount; | ||
import lotto.domain.WinningCheck; | ||
|
||
public class LottoProfitRateCalculator { | ||
|
||
private static final int PERCENTAGE_FACTOR = 100; | ||
|
||
public double calculateProfitRate(PurchaseAmount purchaseAmount, | ||
Map<WinningCheck, Integer> result) { | ||
double totalPrize = result.entrySet().stream() | ||
.mapToInt(entry -> entry.getKey().getPrizeAmount() * entry.getValue()) | ||
.sum(); | ||
|
||
double profitRate = (totalPrize / purchaseAmount.getPurchaseAmount()) * PERCENTAGE_FACTOR; | ||
DecimalFormat df = new DecimalFormat("#.##"); | ||
return Double.parseDouble(df.format(profitRate)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package lotto.service; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import lotto.domain.Lotto; | ||
import lotto.domain.UserInputNumbers; | ||
import lotto.domain.WinningCheck; | ||
|
||
public class LottoResultCalculator { | ||
|
||
public Map<WinningCheck, Integer> calculateWinningResult(List<Lotto> lottos, | ||
UserInputNumbers receivedLotto) { | ||
Map<WinningCheck, Integer> result = new HashMap<>(); // WinningCheck 객체 정수를 키와 값으로 Map에 저장 | ||
for (Lotto lotto : lottos) { | ||
int matchCount = lotto.getMatchCount(receivedLotto); | ||
boolean bonusMatch = lotto.isBonusMatch(receivedLotto); // receivedLotto는 bonus를 포함하고있음 | ||
|
||
WinningCheck prize = WinningCheck.getPrize(matchCount, bonusMatch); | ||
result.merge(prize, 1, Integer::sum); | ||
} | ||
return result; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 코드는 Validation 만 수행하고 있는 클래스네요🤔 이 클래스의 책임으로 줄 수 있는 건 뭘까요!?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
자신의 역할(유효성 검사, 저장, 제공)을 훌륭히 해내고 있는 클래스라고 생각합니다!
추가적인 책임을 주고싶지는 않습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋습니다ㅋㅋㅋㅋ 사실 저도 요구사항 자체가 간단해서 책임 할당은 이 정도로 충분하다고 생각해요 🧐