-
Notifications
You must be signed in to change notification settings - Fork 122
[완두콩] 한지수 로또 미션 제출합니다. #204
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
base: luzknar
Are you sure you want to change the base?
Changes from 26 commits
eb33467
25a7a6d
bb9a74e
4bcc236
183109c
9f16875
e66d10f
6791807
f0bb06e
16aad70
1925288
1fd4040
48c0c1d
6be5649
e17cd36
464b224
76711b0
9c82f14
63180a1
a2e257b
88edef5
a30b33a
2bb1f54
cdd23cf
a741178
05a9d3d
2f4ed32
1775991
d145916
c626494
5b8dde5
0b6a05b
d5f0598
023460d
7e26f3a
efe62fe
bd23cfb
ce67ece
2e6e6f1
f8ec6f5
1d02d5d
69140af
c6082f7
5624c34
143eb9f
28a0430
b1a420a
63db64c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # 로또 미션 | ||
|
|
||
| ---- | ||
|
|
||
| ### 기능 요구사항 | ||
|
|
||
| - 로또 구입 금액을 입력하면 구입 금액에 해당하는 로또를 발급해야한다. | ||
| - 로또 1장의 가격은 1000원 이다. | ||
| - 로또 당첨 번호를 받아 일치한 번호 수에 따라 당첨 결과를 보여준다. | ||
| - 로또 2등을 위한 보너스볼을 추첨한다. | ||
| - 당첨 통계에 2등을 추가한다.(2등 당첨 조건은 당첨 번호 5개 일치 + 보너스 볼 일치다.) | ||
| - 사용자가 수동으로 추첨 번호를 입력할 수 있도록 해야한다. | ||
| - 입력한 금액, 자동 생성 숫자, 수동 생성 번호를 입력하도록 해야한다. | ||
| --- | ||
|
|
||
| ### 프로그래밍 요구사항 | ||
|
|
||
| - 자바 코드 컨벤션을 지킨다. | ||
| - indent depth를 2를 넘지않도록 구현한다. | ||
| - 3항 연산자를 쓰지 않는다. | ||
| - else 예약어를 쓰지 않는다. | ||
| - 배열 대신 컬렉션을 사용한다. | ||
| - 축약 하지 않는다. | ||
| - 함수의 길이가 10라인을 넘지 않도록 구현한다. | ||
| - 모든 원시값과 문자열을 포장한다. | ||
| - 일급 컬렉션을 쓴다. | ||
| - Java Enum을 적용한다. | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import domain.*; | ||
| import view.InputView; | ||
| import view.ResultView; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| public class Main { | ||
| public static void main(String[] args) { | ||
| int price = InputView.getPurchaseAmount(); | ||
| int count = InputView.getManualPurchaseAmount(); | ||
| List<LottoNumber> manualLottos = new ArrayList<>(); | ||
| LottoParser lottoParser = new LottoParser(); | ||
| for (int i = 0; i < count; i++) { | ||
| String input = InputView.getManualPurchasedLottos(); | ||
|
|
||
| List<Integer> numbers = lottoParser.parseSingleLotto(input); | ||
| manualLottos.add(new LottoNumber(numbers)); | ||
| } | ||
| PurchaseManage purchaseManage = new PurchaseManage(); | ||
| Lottos lottos = purchaseManage.buyLottos(price, manualLottos); | ||
|
|
||
| ResultView.showNum(lottos); | ||
| String enteredWinningNumber = InputView.getWinningNumber(); | ||
| int bonusNumber = InputView.getBonusNumber(); | ||
|
|
||
| List<Integer> winningNumbers = lottoParser.setWinningNumber(enteredWinningNumber); | ||
| WinningStatistics winningStatistics = new WinningStatistics(); | ||
| winningStatistics.compareLottos(winningNumbers, lottos, bonusNumber); | ||
| ProfitRate profitRate = new ProfitRate(price, winningStatistics); | ||
| ResultView.showStatistics(profitRate, winningStatistics); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package domain; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| public class LottoNumber { | ||
| private static final List<Integer> NUMBERS = new ArrayList<>(); | ||
| static { | ||
| for (int i = 1; i <= 45; i++) { | ||
| NUMBERS.add(i); | ||
| } | ||
| } | ||
|
|
||
| private final List<Integer> lottoNumbers; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정말 사소하지만, lottoNumber이라는 이름의 클래스가 lottoNumbers를 필드로 가지고 있는 것이 어색해 보일 수 있을 것 같아요. |
||
|
|
||
| public LottoNumber() { | ||
| List<Integer> numbers = new ArrayList<>(NUMBERS); | ||
| Collections.shuffle(numbers); | ||
| this.lottoNumbers = new ArrayList<>(numbers.subList(0, 6)); | ||
| Collections.sort(this.lottoNumbers); | ||
| } | ||
|
|
||
| public LottoNumber(List<Integer> manualNumbers) { | ||
| validateLottoNumber(manualNumbers); | ||
| this.lottoNumbers = new ArrayList<>(manualNumbers); | ||
| Collections.sort(this.lottoNumbers); | ||
| } | ||
|
|
||
| private void validateLottoNumber(List<Integer> manualNumbers) { | ||
| for (int number : manualNumbers) { | ||
| validateNumber(number); | ||
| } | ||
| if (manualNumbers.size() != 6) { | ||
| throw new IllegalArgumentException("로또 번호는 6개여야 합니다."); | ||
| } | ||
| } | ||
|
|
||
| private void validateNumber(int number) { | ||
| if (number < 1 || number > 46) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 범위가 잘못된 것 같아요! |
||
| throw new IllegalArgumentException("로또 번호는 1부터 45까지여야 합니다."); | ||
| } | ||
| } | ||
|
|
||
| public List<Integer> getLottoNumbers() { | ||
| return lottoNumbers; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| package domain; | ||
|
|
||
| import java.util.*; | ||
|
|
||
| public class LottoParser { | ||
| public List<Integer> setWinningNumber(String enteredWinningNumber) { | ||
| List<Integer> winningNumber = new ArrayList<>(); | ||
| String[] item = enteredWinningNumber.split(","); | ||
| for (int i = 0; i < item.length; i++) { | ||
| item[i] = item[i].trim(); | ||
| winningNumber.add(Integer.parseInt(item[i])); | ||
| } | ||
| Collections.sort(winningNumber); | ||
|
|
||
| return winningNumber; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 당첨 숫자들은 Lotto Number 검증을 거치지 않고 있는 것 같아요🥲 |
||
|
|
||
| public List<Integer> parseSingleLotto(String input) { | ||
| List<Integer> lottoNumbers = new ArrayList<>(); | ||
| String[] items = input.split(","); | ||
| for (String item : items) { | ||
| lottoNumbers.add(Integer.parseInt(item.trim())); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이렇게 줄일 수 있겠군요! 추가로 |
||
| Collections.sort(lottoNumbers); | ||
| return lottoNumbers; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package domain; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class Lottos { | ||
| private final List<LottoNumber> lottos; | ||
|
|
||
| public Lottos(List<LottoNumber> lottos) { | ||
| this.lottos = lottos; | ||
| } | ||
|
|
||
| public int size() { | ||
| return lottos.size(); | ||
| } | ||
| public List<LottoNumber> getLottos() { | ||
| return lottos; | ||
| } | ||
| } |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 로또 일치 개수를 객체로 만드신 이유가 무엇인가요?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 당시에는 당첨 번호와 비교하여 일치 개수를 세는 기능이 비중있게 느껴져서 LottoParser 처럼 단일 역할을 하는 객체로 분리했습니다. 하지만 각 클래스의 역할과 책임을 정리해보니 이미 당첨번호를 필드값으로 가지고있는 당첨번호 객체에서 충분히 처리할 수 있는 로직이었고, 굳이 별도으 클래스로 분리할 필요까지는 없었던 것 같습니다. 해당 클래스는 제거하는 방향으로 개선했습니다! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| package domain; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class MatchCount { | ||
| int count = 0; | ||
| public void comparingLotto (List<Integer> lottoNumbers, List<Integer> winningNumbers) { | ||
| count = 0; | ||
| for (int i = 0; i < 6; i ++) { | ||
| compareNumbers(lottoNumbers, winningNumbers, i); | ||
| } | ||
| } | ||
|
|
||
| public void compareNumbers(List<Integer> lottoNumbers, List<Integer> winningNumbers, int i) { | ||
| if (lottoNumbers.contains(winningNumbers.get(i))) { | ||
| count++; | ||
| } | ||
| } | ||
|
|
||
| public int getCount() { | ||
| return count; | ||
| } | ||
|
|
||
| public boolean hasBonusNumber(List<Integer> lottoNumber, int bonusNumber) { | ||
| return lottoNumber.contains(bonusNumber); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package domain; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| public class ProfitRate { | ||
| private final int price; | ||
| private final WinningStatistics winningStatistics; | ||
|
|
||
| public ProfitRate(int price, WinningStatistics winningStatistics) { | ||
| this.price = price; | ||
| this.winningStatistics = winningStatistics; | ||
| } | ||
|
|
||
| public long getTotalProfit() { | ||
| long totalProfit = 0; | ||
| Map<Rank, WinnerNum> statistics = winningStatistics.getWinningStatistics(); | ||
|
|
||
| for (Rank rank : statistics.keySet()) { | ||
| int count = statistics.get(rank).getWinnerNum(); | ||
| totalProfit += (long) rank.getPrize() * count; | ||
| } | ||
| return totalProfit; | ||
| } | ||
|
|
||
| public double getProfitRate() { | ||
| return (double) getTotalProfit() / price; | ||
| } | ||
| } |
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 클래스의 역할에 대해서도 쭉 리스트업해보면 좋을 것같아요. 오히려 Lotto List를 필드로 가지고있는 Lottos가 가져야할 역할도 이 클래스가 가지고 있는 것 같은데 일단 리스트업 후 다른 여러 클래스들로 적절히 분리해보시죵 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package domain; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| public class PurchaseManage { | ||
| private static final int LOTTO_PRICE = 1000; | ||
|
|
||
| public Lottos buyLottos(int price, List<LottoNumber> manualLottos) { | ||
| int totalCount = price / LOTTO_PRICE; | ||
| int automaticLottoCount = totalCount - manualLottos.size(); | ||
|
|
||
| List<LottoNumber> purchaseLottos = new ArrayList<>(manualLottos); | ||
|
|
||
| for (int i = 0; i < automaticLottoCount; i++) { | ||
| purchaseLottos.add(new LottoNumber()); | ||
| } | ||
| return new Lottos(purchaseLottos); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package domain; | ||
|
|
||
| public enum Rank { | ||
| FIRST_PLACE(6, 2000000000, false), | ||
| SECOND_PLACE_BONUS(5, 30000000, true), | ||
| SECOND_PLACE(5, 1500000, false), | ||
| THIRD_PLACE(4, 50000, false), | ||
| FOURTH_PLACE(3, 5000, false), | ||
| MISS(0, 0, false); | ||
|
|
||
| private int matchBallNum; | ||
| private int prize; | ||
| private boolean hasBonusBall; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 필드들은 변하지 않는 값이네요! 어떤 키워드를 붙일 수 있을까요? |
||
|
|
||
| Rank(int matchBallNum, int prize, boolean hasBonusBall) { | ||
| this.matchBallNum = matchBallNum; | ||
| this.prize = prize; | ||
| this.hasBonusBall = hasBonusBall; | ||
| } | ||
|
|
||
| public static Rank getRank(int matchBallNum, boolean hasBonusBall) { | ||
| if (matchBallNum == FIRST_PLACE.getMatchBallNum()) { return FIRST_PLACE; } | ||
| if (matchBallNum == SECOND_PLACE_BONUS.getMatchBallNum() && hasBonusBall) { return SECOND_PLACE_BONUS; } | ||
| if (matchBallNum == SECOND_PLACE.getMatchBallNum() && !hasBonusBall) { return SECOND_PLACE; } | ||
| if (matchBallNum == THIRD_PLACE.getMatchBallNum()) { return THIRD_PLACE; } | ||
| if (matchBallNum == FOURTH_PLACE.getMatchBallNum()) { return FOURTH_PLACE; } | ||
| return MISS; | ||
| } | ||
|
|
||
| public int getMatchBallNum() { | ||
| return matchBallNum; | ||
| } | ||
|
|
||
| public int getPrize() { | ||
| return prize; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package domain; | ||
|
|
||
| public class WinnerNum { | ||
| private int winnerNum; | ||
| public WinnerNum(int winnerNum) { | ||
| this.winnerNum = winnerNum; | ||
| } | ||
|
|
||
| public int getWinnerNum() { | ||
| return winnerNum; | ||
| } | ||
|
|
||
| public void increase() { | ||
| winnerNum++; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package domain; | ||
|
|
||
| import java.util.*; | ||
|
|
||
| public class WinningStatistics { | ||
| Map<Rank, WinnerNum> winningStatistics = new HashMap<>(); | ||
|
|
||
| MatchCount matchCount = new MatchCount(); | ||
| public WinningStatistics() { | ||
| for (Rank rank : Rank.values()) { | ||
| winningStatistics.put(rank, new WinnerNum(0)); | ||
| } | ||
| } | ||
|
|
||
| public void compareLottos (List<Integer> winningNumbers, Lottos lottos, int bonusNumber) { | ||
| for (LottoNumber lottoNumber : lottos.getLottos()) { | ||
| matchCount.comparingLotto(lottoNumber.getLottoNumbers(), winningNumbers); | ||
| Rank rank = Rank.getRank(matchCount.getCount(), matchCount.hasBonusNumber(lottoNumber.getLottoNumbers(), bonusNumber)); | ||
| winningStatistics.get(rank).increase(); | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 구조가 조금 어색해보입니다ㅠㅠ 전체 코멘트에도 작성했지만 객체를 getter로 가져와서 계산은 다른 곳에서 하는 부분이 잘못된 책임 분리라고 느껴졌어요 캡슐화를 하는 것 까지는 잘 해주셨는데, 이 부분 뿐 만 아니라 다른 코드 전반에도 getter가 많이 사용되고 있어요🥲 공부할 부분을 염두하고 대략적으로 작성해보았는데, 구체적으로 학습해보시면 도움이 될 것 같아요! |
||
|
|
||
| public Map<Rank, WinnerNum> getWinningStatistics() { | ||
| return winningStatistics; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| package view; | ||
|
|
||
| import java.util.Scanner; | ||
|
|
||
| public class InputView { | ||
| private static Scanner scanner = new Scanner(System.in); | ||
|
|
||
| public static int getPurchaseAmount() { | ||
| System.out.println("구입금액을 입력해 주세요."); | ||
| int purchaseAmount = Integer.parseInt(scanner.nextLine()); | ||
| return purchaseAmount; | ||
| } | ||
|
Comment on lines
+12
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
추가로 입력값에 대한 검증을 할 수 있는 방법은 여러가지가 있습니다.
지수님은 어느 위치에서 검증하는 것이 적절하다 판단하셨나요?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3번으로 검증하는 것이 적절한 것 같습니다. 객체가 생성되는 시점에서 생성자 내부에서 스스로 유효성을 검증함으로써, 생성된 객체가 올바른 상태라는 것을 보장할 수 있기 때문입니다. |
||
|
|
||
| public static int getManualPurchaseAmount() { | ||
| System.out.println("수동으로 구매할 로또 수를 입력해 주세요."); | ||
| int manualPurchaseLottos = Integer.parseInt(scanner.nextLine()); | ||
| return manualPurchaseLottos; | ||
| } | ||
|
|
||
| public static String getManualPurchasedLottos() { | ||
| System.out.println("수동으로 구매할 번호를 입력해 주세요."); | ||
| String manualPurchasedLotto = scanner.nextLine(); | ||
| return manualPurchasedLotto; | ||
| } | ||
|
|
||
| public static String getWinningNumber() { | ||
| System.out.println("지난 주 당첨 번호를 입력해주세요."); | ||
| String enteredWinningNumber = scanner.nextLine(); | ||
| return enteredWinningNumber; | ||
| } | ||
|
|
||
| public static int getBonusNumber() { | ||
| System.out.println("보너스 볼을 입력해 주세요."); | ||
| int bonusNumber = Integer.parseInt(scanner.nextLine()); | ||
| return bonusNumber; | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package view; | ||
|
|
||
| import domain.*; | ||
|
|
||
| public class ResultView { | ||
| public static void showNum(Lottos lottos) { | ||
| System.out.printf("%d개를 구매했습니다.", lottos.size()); | ||
| System.out.println(); | ||
| for (LottoNumber lottoNumber : lottos.getLottos()) { | ||
| System.out.println(lottoNumber.getLottoNumbers()); | ||
| } | ||
| } | ||
|
|
||
| public static void showStatistics(ProfitRate profitRate, WinningStatistics winningStatistics) { | ||
| System.out.println("당첨 통계"); | ||
| System.out.println("---------"); | ||
| System.out.println("3개 일치 (5000원)-" + winningStatistics.getWinningStatistics().get(Rank.FOURTH_PLACE).getWinnerNum()); | ||
| System.out.println("4개 일치 (50000원)-" +winningStatistics.getWinningStatistics().get(Rank.THIRD_PLACE).getWinnerNum()); | ||
| System.out.println("5개 일치 (1500000원)-" + winningStatistics.getWinningStatistics().get(Rank.SECOND_PLACE).getWinnerNum()); | ||
| System.out.println("5개 일치, 보너스 볼 일치(30000000원)-" + winningStatistics.getWinningStatistics().get(Rank.SECOND_PLACE_BONUS).getWinnerNum()); | ||
| System.out.println("6개 일치 (2000000000원)-" + winningStatistics.getWinningStatistics().get(Rank.FIRST_PLACE).getWinnerNum()); | ||
| System.out.println("총 수익률은 " + profitRate.getProfitRate() + "입니다."); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 수익률 계산 시 % 단위로 나타내려면 100을 곱해야할 것 같은데, 미션 내용을 확인해보지 못해서 😅... |
||
| } | ||
| } | ||
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.
하나의 메서드에 쭉 로직이 작성되어있네요 🥲
메서드 분리를 통해 가독성도 높이고, 책임별로 로직을 묶어볼까요?