-
Notifications
You must be signed in to change notification settings - Fork 3
[기현]로또 구현 #10
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: master
Are you sure you want to change the base?
[기현]로또 구현 #10
Changes from all commits
7da1a2c
40ec650
5e8c6cd
a131665
cfe2066
c4364e1
90fb157
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 |
|---|---|---|
| @@ -1,7 +1,39 @@ | ||
| package com.javabom.lotto; | ||
|
|
||
| import com.javabom.lotto.domain.Customer; | ||
| import com.javabom.lotto.domain.shop.AutoLottoNumberGenerator; | ||
| import com.javabom.lotto.domain.shop.LottoShop; | ||
| import com.javabom.lotto.domain.shop.LottoMachine; | ||
| import com.javabom.lotto.domain.number.PrizeNumbersBundle; | ||
| import com.javabom.lotto.domain.result.LottoResultBundle; | ||
| import com.javabom.lotto.domain.ticket.LottoTicketBundle; | ||
| import com.javabom.lotto.view.InputView; | ||
| import com.javabom.lotto.view.OutputView; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Scanner; | ||
|
|
||
| public class LottoApplication { | ||
| private static final InputView inputView = new InputView(new Scanner(System.in)); | ||
|
|
||
| public static void main(String[] args) { | ||
|
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. 지금 메인 로직을 보면 전체 비지니스 플로우의 흐름을 알기 어렵습니다. 내부로 숨겨야할 구현들이 main에 너무 노출되어있어요 예를들어 MyLottoBundle은 LottoFactory의 createLotto를 호출해 로또를 주입받아 생성되는데, LottoShop lottoShop = new LottoShop(new RandomMachine());
MyLottoBundle bundle = lottoShop.buyLotto(money);랜덤 로또 머신을 가진 로또가게에 돈을 주면 로또를 살 수 있다. 굳이 money.getLottoCount()가 외부에 노출될 필요가 있을까요? 기본 문맥에 방해되는 세부 구현내용은 안쪽으로 감추는 연습을 하는게 좋을거같아요 밑에 내용들도 좀더 자연스러운 문맥으로 바꿔보세요
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. 오 맞습니다. 자연스러운 문맥흐름과 세부 구현내용을 안쪽으로 감춘다에 초점을 맞춰서 바꿔보겠습니다! 감사합니다! |
||
|
|
||
| int amount = inputView.inputMoney(); | ||
| int manualLottoTicketCount = inputView.inputManualLottoTicketCount(); | ||
| List<List<String>> manualLottoNumbers = inputView.inputManualLottoNumbers(manualLottoTicketCount); | ||
| Customer customer = new Customer(amount, manualLottoNumbers); | ||
|
|
||
| LottoShop lottoShop = new LottoShop(new LottoMachine(new AutoLottoNumberGenerator())); | ||
| LottoTicketBundle lottoTicketBundle = lottoShop.buy(customer); | ||
|
|
||
| OutputView.printLottoCount(manualLottoNumbers.size(), customer.getAutoLottoTicketCount()); | ||
| OutputView.printLottoBundle(lottoTicketBundle); | ||
|
|
||
| PrizeNumbersBundle prizeNumberBundle = new PrizeNumbersBundle( | ||
| inputView.inputPrizeNumbers(), inputView.inputBonusNumber()); | ||
|
|
||
| LottoResultBundle lottoResultBundle = lottoTicketBundle.getLottoResults(prizeNumberBundle); | ||
|
|
||
| OutputView.printResults(lottoResultBundle, amount); | ||
|
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. 구입 금액을 그대로 수익률 계산에서 사용하시는 거 같은데, 투입금액이 6500 이렇게 들어가면 수익률 계산이 올바르게 되지 않습니다! 그래서 LottoResultBundle에서 amount 값을 입력 받지 않고(입력을 받는다면 구매한 금액을 받아야합니다!), 구입한 티켓 개수로 수익률을 계산하면 올바르게 계산이 될 거 같습니다:) |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| package com.javabom.lotto.domain; | ||
|
|
||
| import com.javabom.lotto.domain.ticket.LottoTicket; | ||
| import com.javabom.lotto.domain.number.OrderGameNumber; | ||
| import com.javabom.lotto.domain.utils.GameNumberConverter; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| public class Customer { | ||
| private final int amount; | ||
| private final List<List<OrderGameNumber>> manualLottoNumbers; | ||
|
|
||
| public Customer(int amount, List<List<String>> strManualLottoNumbers) { | ||
| checkPositive(amount); | ||
| checkBuyManualLottoTicket(amount, strManualLottoNumbers.size()); | ||
| this.amount = amount; | ||
| this.manualLottoNumbers = collet(strManualLottoNumbers); | ||
| } | ||
|
|
||
| private void checkPositive(int amount) { | ||
| if (amount <= 0) { | ||
| throw new IllegalArgumentException(String.format("%d, 0원 이상의 돈을 입력해 주세요.", amount)); | ||
| } | ||
| } | ||
|
|
||
| private void checkBuyManualLottoTicket(int amount, int ticketCount) { | ||
| int requiredAmount = ticketCount * LottoTicket.PRICE; | ||
| if (amount < requiredAmount) { | ||
| throw new IllegalArgumentException(String.format("현재 보유 금액:%d, 필요한 금액:%d, 금액이 부족합니다.", amount, requiredAmount)); | ||
| } | ||
| } | ||
|
|
||
| private List<List<OrderGameNumber>> collet(List<List<String>> strManualLottoNumbers) { | ||
| List<List<OrderGameNumber>> manualLottoNumbers = new ArrayList<>(); | ||
| for (List<String> eachManualLottoNumbers : strManualLottoNumbers) { | ||
| checkCount(eachManualLottoNumbers.size()); | ||
|
|
||
| List<OrderGameNumber> orderGameNumbers = GameNumberConverter.convert(eachManualLottoNumbers); | ||
| checkDuplicate(orderGameNumbers.size()); | ||
|
|
||
| manualLottoNumbers.add(GameNumberConverter.convert(eachManualLottoNumbers)); | ||
|
|
||
| } | ||
| return manualLottoNumbers; | ||
| } | ||
|
|
||
| private void checkCount(int numberCount) { | ||
| if (numberCount != LottoTicket.COUNT) { | ||
| throw new IllegalArgumentException(String.format("%d개의 수동 로또 번호를 입력하셨습니다. 수동 로또 번호는 총 6개여야 합니다.", numberCount)); | ||
| } | ||
| } | ||
|
|
||
| private void checkDuplicate(int gameNumbersSize) { | ||
| if (gameNumbersSize != LottoTicket.COUNT) { | ||
| throw new IllegalArgumentException("수동 로또 번호는 모두 달라야 합니다."); | ||
| } | ||
| } | ||
|
|
||
| public int getAutoLottoTicketCount() { | ||
| int curAmount = amount - (manualLottoNumbers.size() * LottoTicket.PRICE); | ||
| if (curAmount < LottoTicket.PRICE) { | ||
| return 0; | ||
| } | ||
| return curAmount / LottoTicket.PRICE; | ||
| } | ||
|
|
||
| public List<List<OrderGameNumber>> getManualLottoNumbers() { | ||
| return Collections.unmodifiableList(this.manualLottoNumbers); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| package com.javabom.lotto.domain.number; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Objects; | ||
|
|
||
| public class GameNumber { | ||
| public static final int MIN_NUMBER = 1; | ||
| public static final int MAX_NUMBER = 45; | ||
|
|
||
| private final int gameNumber; | ||
|
|
||
| private GameNumber(int gameNumber) { | ||
| this.gameNumber = gameNumber; | ||
| } | ||
|
|
||
| public static GameNumber valueOf(int number) { | ||
| checkRange(number); | ||
| return GameNumberCache.cache.get(number); | ||
| } | ||
|
|
||
| public static GameNumber valueOf(String strNumber) { | ||
| return GameNumber.valueOf(Integer.parseInt(strNumber)); | ||
| } | ||
|
|
||
| private static void checkRange(int number) { | ||
| if (number < MIN_NUMBER || number > MAX_NUMBER) { | ||
| throw new IllegalArgumentException(String.format("입력값: %d, 당첨 번호는 1-45 숫자만 가능합니다.", number)); | ||
| } | ||
| } | ||
|
|
||
| public int value() { | ||
| return this.gameNumber; | ||
| } | ||
|
|
||
| private static class GameNumberCache { | ||
| static final List<GameNumber> cache; | ||
|
|
||
| static { | ||
| cache = new ArrayList<>(); | ||
|
|
||
| for (int idx = MIN_NUMBER - 1; idx <= MAX_NUMBER; idx++) { | ||
| cache.add(new GameNumber(idx)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (!(o instanceof GameNumber)) return false; | ||
| GameNumber that = (GameNumber) o; | ||
| return gameNumber == that.gameNumber; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(gameNumber); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| package com.javabom.lotto.domain.number; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class OrderGameNumber { | ||
| private static final int MIN_ORDER_NUMBER = 1; | ||
| private static final int MAX_ORDER_NUMBER = 7; | ||
|
|
||
| private final int order; | ||
| private final GameNumber gameNumber; | ||
|
|
||
| private OrderGameNumber(final int order, final GameNumber gameNumber) { | ||
| this.order = order; | ||
| this.gameNumber = gameNumber; | ||
| } | ||
|
|
||
| public static OrderGameNumber of(int order, final GameNumber gameNumber) { | ||
| checkOrderRange(order); | ||
| return new OrderGameNumber(order, gameNumber); | ||
| } | ||
|
|
||
| public static OrderGameNumber of(int order, final String strGameNumber) { | ||
| return OrderGameNumber.of(order, GameNumber.valueOf(strGameNumber)); | ||
| } | ||
|
|
||
| private static void checkOrderRange(final int order) { | ||
| if (order < MIN_ORDER_NUMBER || order > MAX_ORDER_NUMBER) { | ||
| throw new IllegalArgumentException(String.format("%d, 게임 숫자의 인덱스 범위는 1-6 이어야 합니다.", order)); | ||
| } | ||
| } | ||
|
|
||
| public boolean equalsOfNumber(final OrderGameNumber orderGameNumber) { | ||
| return this.gameNumber.equals(orderGameNumber.gameNumber); | ||
| } | ||
|
|
||
| public GameNumber numberValue() { | ||
| return this.gameNumber; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(final Object o) { | ||
| if (this == o) return true; | ||
| if (!(o instanceof OrderGameNumber)) return false; | ||
| final OrderGameNumber that = (OrderGameNumber) o; | ||
| return order == that.order && | ||
| Objects.equals(gameNumber, that.gameNumber); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(order, gameNumber); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| package com.javabom.lotto.domain.number; | ||
|
|
||
| import com.javabom.lotto.domain.ticket.LottoTicket; | ||
| import com.javabom.lotto.domain.utils.GameNumberConverter; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class PrizeNumbers { | ||
|
|
||
| private final List<OrderGameNumber> prizeNumbers; | ||
|
|
||
| public PrizeNumbers(List<String> strPrizeNumbers) { | ||
| this.prizeNumbers = collect(strPrizeNumbers); | ||
| } | ||
|
|
||
| private List<OrderGameNumber> collect(final List<String> strPrizeNumbers) { | ||
| checkCount(strPrizeNumbers.size()); | ||
| List<OrderGameNumber> prizeNumbers = GameNumberConverter.convert(strPrizeNumbers); | ||
| checkDuplicate(prizeNumbers.size()); | ||
| return prizeNumbers; | ||
| } | ||
|
|
||
| private static void checkCount(int numberCount) { | ||
| if (numberCount != LottoTicket.COUNT) { | ||
| throw new IllegalArgumentException(String.format("%d개의 당첨 번호를 입력하셨습니다. 당첨 번호는 총 6개여야 합니다.", numberCount)); | ||
| } | ||
| } | ||
|
|
||
| private static void checkDuplicate(int gameNumbersSize) { | ||
| if (gameNumbersSize != LottoTicket.COUNT) { | ||
| throw new IllegalArgumentException("당첨 번호는 모두 달라야 합니다."); | ||
| } | ||
| } | ||
|
|
||
| public boolean contains(OrderGameNumber orderGameNumber) { | ||
| return prizeNumbers.stream() | ||
| .anyMatch(number -> number.equalsOfNumber(orderGameNumber)); | ||
| } | ||
|
|
||
| public int getMatchedCount(final LottoTicket lottoTicket) { | ||
| return (int) prizeNumbers.stream() | ||
| .filter(lottoTicket::contains) | ||
| .count(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package com.javabom.lotto.domain.number; | ||
|
|
||
| import com.javabom.lotto.domain.result.LottoResult; | ||
| import com.javabom.lotto.domain.ticket.LottoTicket; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class PrizeNumbersBundle { | ||
| private static final int BONUS_ORDER = 7; | ||
|
|
||
| private final PrizeNumbers prizeNumbers; | ||
| private final OrderGameNumber bonusNumber; | ||
|
|
||
| public PrizeNumbersBundle(List<String> prizeNumbers, String bonusNumber) { | ||
| this.prizeNumbers = new PrizeNumbers(prizeNumbers); | ||
| this.bonusNumber = OrderGameNumber.of(BONUS_ORDER, bonusNumber); | ||
| checkDuplicate(); | ||
| } | ||
|
|
||
| private void checkDuplicate() { | ||
| if (prizeNumbers.contains(bonusNumber)) { | ||
| throw new IllegalArgumentException("입력하신 보너스 번호는 당첨 번호와 겹칩니다."); | ||
| } | ||
| } | ||
|
|
||
| public LottoResult getLottoResult(LottoTicket lottoTicket) { | ||
| int matchedCount = prizeNumbers.getMatchedCount(lottoTicket); | ||
| boolean bonusStatus = lottoTicket.containsBonus(bonusNumber); | ||
| return LottoResult.findLottoResult(matchedCount, bonusStatus); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| package com.javabom.lotto.domain.result; | ||
|
|
||
| import java.util.Arrays; | ||
|
|
||
| public enum LottoResult { | ||
| FIRST(6, 2_000_000_000), | ||
| SECOND(5, 30_000_000), | ||
| THIRD(5, 1_500_000), | ||
| FOURTH(4, 50_000), | ||
| FIFTH(3, 5_000), | ||
| FAIL(0, 0); | ||
|
|
||
| LottoResult(int matchedCount, int prize) { | ||
| this.matchedCount = matchedCount; | ||
| this.prize = prize; | ||
| } | ||
|
|
||
| public final int matchedCount; | ||
| public final int prize; | ||
|
|
||
| public static LottoResult findLottoResult(int matchedCount, boolean bonusStatus) { | ||
| if (matchedCount == 5) { | ||
| return findBonus(bonusStatus); | ||
| } | ||
| return valueOf(matchedCount); | ||
| } | ||
|
|
||
| private static LottoResult findBonus(boolean bonusStatus) { | ||
| if (bonusStatus) { | ||
| return SECOND; | ||
| } | ||
| return THIRD; | ||
| } | ||
|
|
||
| public static LottoResult valueOf(int matchedCount){ | ||
| return Arrays.stream(LottoResult.values()) | ||
| .filter(lottoResult -> lottoResult.getMatchedCount() == matchedCount) | ||
| .filter(lottoResult -> !lottoResult.equals(SECOND)) | ||
| .findFirst() | ||
| .orElse(FAIL); | ||
| } | ||
|
|
||
| private int getMatchedCount(){ | ||
| return this.matchedCount; | ||
| } | ||
|
|
||
| public int getPrize() { | ||
| return this.prize; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package com.javabom.lotto.domain.result; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class LottoResultBundle { | ||
| private final int PERCENT = 100; | ||
|
|
||
| private final List<LottoResult> lottoResultBundle; | ||
|
|
||
| public LottoResultBundle(List<LottoResult> lottoResultBundle) { | ||
| this.lottoResultBundle = lottoResultBundle; | ||
| } | ||
|
|
||
| public long calculatePrize() { | ||
| long prize = 0; | ||
| for (LottoResult lottoResult : lottoResultBundle) { | ||
| prize += lottoResult.getPrize(); | ||
| } | ||
| return prize; | ||
| } | ||
|
|
||
| public long getRateOfProfit(int amount) { | ||
| long profit = calculatePrize() - amount; | ||
| if (profit < 0) { | ||
| return 0; | ||
| } | ||
| return (profit / amount) * PERCENT; | ||
| } | ||
|
|
||
| public int getCountOfPrize(LottoResult lottoResult) { | ||
| return (int) lottoResultBundle.stream() | ||
| .filter(result -> result.equals(lottoResult)) | ||
| .count(); | ||
| } | ||
|
|
||
| public LottoResult valueOf(int idx){ | ||
| return lottoResultBundle.get(idx); | ||
| } | ||
| } |
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.
구입 금액이 수동으로 구매할 로또 금액보다 적은데, 수동 번호를 입력 받아요!
수동 번호 입력 전에 구입 금액이랑 수동 번호 구매 금액을 검증하는 부분이 추가되면 좋을 거 같습니다!