-
Notifications
You must be signed in to change notification settings - Fork 3
[혁] 로또게임 #8
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?
[혁] 로또게임 #8
Changes from 7 commits
c7c6eff
f61cab6
339f14c
41e7fa3
dd38b73
6eee120
bfb1a47
40b2369
efe0fa1
97bf6f1
1cd3d44
9fb8981
a8c5835
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,28 @@ | ||
| package com.javabom.lotto; | ||
|
|
||
| import com.javabom.lotto.domain.compare.LottoBasicLuckyNumbers; | ||
| import com.javabom.lotto.domain.compare.LottoLuckyNumbers; | ||
| import com.javabom.lotto.domain.compare.LottoResults; | ||
| import com.javabom.lotto.domain.compare.LottoTicketComparator; | ||
| import com.javabom.lotto.domain.ticket.*; | ||
| import com.javabom.lotto.view.InputView; | ||
| import com.javabom.lotto.view.OutputView; | ||
|
|
||
| public class LottoApplication { | ||
| public static void main(String[] args) { | ||
| Money inputMoney = new Money(InputView.getMoneyToBuyTicket()); | ||
|
|
||
| LottoTicketDispenser lottoTicketDispenser = new LottoTicketDispenser(new RandomLottoNumberGenerator()); | ||
| LottoTickets lottoTickets = lottoTicketDispenser.getAutoTickets(inputMoney); | ||
| OutputView.printLottoTickets(lottoTickets); | ||
|
|
||
| LottoBasicLuckyNumbers basicLuckyNumbers = new LottoBasicLuckyNumbers(InputView.getLottoBasicLuckyNumbers()); | ||
| LottoNumber bonusNumber = new LottoNumber(InputView.getBonusNumber()); | ||
| LottoLuckyNumbers LuckyNumbers = new LottoLuckyNumbers(basicLuckyNumbers, bonusNumber); | ||
|
|
||
| LottoTicketComparator lottoTicketComparator = new LottoTicketComparator(LuckyNumbers); | ||
| LottoResults lottoResults = lottoTicketComparator.getLottoResults(lottoTickets); | ||
| OutputView.printLottoResults(lottoResults); | ||
| OutputView.printEarningRate(inputMoney, lottoResults.getTotalPrizeMoney()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| package com.javabom.lotto.domain.compare; | ||
|
|
||
| import com.javabom.lotto.domain.ticket.LottoNumber; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| public class LottoBasicLuckyNumbers { | ||
|
|
||
| private static final int LUCKY_LOTTO_NUM_SIZE = 6; | ||
|
|
||
| private final List<LottoNumber> numbers; | ||
|
|
||
| public LottoBasicLuckyNumbers(List<Integer> numbers) { | ||
| validateLottoNumbersSize(numbers); | ||
| this.numbers = convertToLottoNumbers(numbers); | ||
| } | ||
| // 로또 당첨번호가 로또 번호를 변환하는 코드를 가진다? 뭔가 이상해보입니다. | ||
| // 차라리 외부에서 LottoNumberConverter 라는 클래스를 만든뒤, 거기에서 List<LottoNumber>를 반환받는게 | ||
|
Member
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. 둘다 나쁘지 않아보임 |
||
| // 좀더 나아보일까요? | ||
|
|
||
| private void validateLottoNumbersSize(List<Integer> numbers) { | ||
| if (numbers.size() != LUCKY_LOTTO_NUM_SIZE) { | ||
| throw new IllegalArgumentException("당첨 번호는 반드시 6개입니다."); | ||
| } | ||
| } | ||
|
|
||
| private List<LottoNumber> convertToLottoNumbers(List<Integer> numbers) { | ||
| return numbers.stream() | ||
| .map(LottoNumber::new) | ||
| .collect(Collectors.toList()); | ||
| } | ||
|
|
||
| public List<LottoNumber> get() { | ||
| return Collections.unmodifiableList(numbers); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package com.javabom.lotto.domain.compare; | ||
|
|
||
| import com.javabom.lotto.domain.ticket.LottoNumber; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| public class LottoLuckyNumbers { | ||
|
Member
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. 이 객체도 너무 하는일이 없음
Member
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. 음 나는 티켓자체에 번호를 비교하는 책임이 있어야되는지를 잘 모르겠어서 |
||
|
|
||
| private final LottoBasicLuckyNumbers basicNumbers; | ||
| private final LottoNumber bonusNumber; | ||
|
|
||
| public LottoLuckyNumbers(LottoBasicLuckyNumbers basicNumbers, LottoNumber bonusNumber) { | ||
| this.basicNumbers = basicNumbers; | ||
| this.bonusNumber = bonusNumber; | ||
| } | ||
|
|
||
| // 이미 basicNumbers.get() 내부에서 unmodifiableList로 감싸서 던져주는것을 | ||
| // 한 번더 감싸는 것이 안전하다고 판단하였습니다. | ||
|
Member
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. 굳굳 이제 주석 제거해도 될듯 |
||
| public List<LottoNumber> getBasicNumbers() { | ||
| return Collections.unmodifiableList(basicNumbers.get()); | ||
| } | ||
|
|
||
| // 이 LottoNumber는 불변객체라고 생각해서 그냥 반환하였는데, | ||
| // LottoNumber 내부에 copy해주는 메소드를 추가하여 복사본을 반환하는게 더 나은가요? | ||
| public LottoNumber getBonusNumber() { | ||
| return bonusNumber; | ||
| } | ||
|
Contributor
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 안에도 변경하는 메서드가 없기도하고 그내부 필드값도 final로 되어있어서 불변입니다. |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| package com.javabom.lotto.domain.compare; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| public enum LottoResult { | ||
|
|
||
| FIRST_PRIZE(6, 2_000_000_000), | ||
| SECOND_PRIZE(5, 30_000_000), | ||
| THIRD_PRIZE(5, 1_500_000), | ||
| FOURTH_PRIZE(4, 50_000), | ||
| FIFTH_PRIZE(3, 5_000), | ||
| LOSE(-1, 0); | ||
|
|
||
| private final int matchCount; | ||
| private final long price; | ||
|
|
||
| LottoResult(int matchCount, long price) { | ||
| this.matchCount = matchCount; | ||
| this.price = price; | ||
| } | ||
|
|
||
| public static LottoResult find(int matchCount, boolean isBonusMatched) { | ||
| validateMatchCount(matchCount); | ||
| if (matchCount == SECOND_PRIZE.matchCount && isBonusMatched) { | ||
| return SECOND_PRIZE; | ||
| } | ||
| return valuesWithoutSecond().stream() | ||
| .filter(result -> result.matchCount == matchCount) | ||
| .findFirst() | ||
| .orElse(LOSE); | ||
| } | ||
|
|
||
| private static void validateMatchCount(int matchCount) { | ||
| if (matchCount < 0 || matchCount > 6) { | ||
| throw new IllegalArgumentException("로또번호 매치 수는 0~6 사이입니다."); | ||
| } | ||
| } | ||
|
|
||
| private static List<LottoResult> valuesWithoutSecond() { | ||
| return Arrays.stream(values()) | ||
| .filter(result -> result != SECOND_PRIZE) | ||
| .collect(Collectors.toList()); | ||
| } | ||
|
|
||
| public long getPrice() { | ||
| return price; | ||
| } | ||
|
|
||
| public int getMatchCount() { | ||
| return matchCount; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package com.javabom.lotto.domain.compare; | ||
|
|
||
| import com.javabom.lotto.domain.ticket.Money; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Objects; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| public class LottoResults { | ||
|
|
||
| private final List<LottoResult> lottoResults; | ||
|
|
||
| public LottoResults(List<LottoResult> lottoResults) { | ||
| this.lottoResults = lottoResults; | ||
| } | ||
|
|
||
| public List<LottoResult> findResultsOf(LottoResult lottoResult) { | ||
| return lottoResults.stream() | ||
| .filter(result -> result == lottoResult) | ||
| .collect(Collectors.toList()); | ||
| } | ||
|
|
||
| public Money getTotalPrizeMoney() { | ||
| long sum = lottoResults.stream() | ||
| .mapToLong(LottoResult::getPrice) | ||
| .sum(); | ||
| return new Money(sum); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| LottoResults that = (LottoResults) o; | ||
| return Objects.equals(lottoResults, that.lottoResults); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(lottoResults); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package com.javabom.lotto.domain.compare; | ||
|
|
||
| import com.javabom.lotto.domain.ticket.LottoTicket; | ||
| import com.javabom.lotto.domain.ticket.LottoTickets; | ||
|
|
||
| import java.util.ArrayList; | ||
|
|
||
| public class LottoTicketComparator { | ||
|
|
||
| private final LottoLuckyNumbers luckyNumbers; | ||
|
|
||
| public LottoTicketComparator(LottoLuckyNumbers luckyNumbers) { | ||
| this.luckyNumbers = luckyNumbers; | ||
| } | ||
|
|
||
| public LottoResults getLottoResults(LottoTickets lottoTickets) { | ||
| ArrayList<LottoResult> lottoResults = new ArrayList<>(); | ||
| for (LottoTicket ticket : lottoTickets.get()) { | ||
| lottoResults.add(getLottoResult(ticket)); | ||
| } | ||
| return new LottoResults(lottoResults); | ||
| } | ||
|
|
||
| private LottoResult getLottoResult(LottoTicket lottoTicket) { | ||
| int count = countMatchingNumbers(lottoTicket); | ||
| boolean isBonusMatched = lottoTicket.isContain(luckyNumbers.getBonusNumber()); | ||
| return LottoResult.find(count, isBonusMatched); | ||
| } | ||
|
|
||
| private int countMatchingNumbers(LottoTicket lottoTicket) { | ||
| return (int) luckyNumbers.getBasicNumbers().stream() | ||
| .map(lottoTicket::isContain) | ||
| .filter(isContain -> isContain) | ||
| .count(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| package com.javabom.lotto.domain.ticket; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| public class LottoNumber { | ||
|
Contributor
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. 감싼거 아주 좋습니다b |
||
| public static final int MIN_LOTTO_NUM = 1; | ||
| public static final int MAX_LOTTO_NUM = 45; | ||
|
|
||
| private final int number; | ||
|
|
||
| public LottoNumber(int number) { | ||
| validateNumber(number); | ||
| this.number = number; | ||
| } | ||
|
|
||
| private void validateNumber(int number) { | ||
| if (number < MIN_LOTTO_NUM || number > MAX_LOTTO_NUM) { | ||
| throw new IllegalArgumentException("로또 번호는 1~45 입니다."); | ||
|
Member
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.
|
||
| } | ||
| } | ||
|
|
||
| public int get() { | ||
| return number; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| LottoNumber that = (LottoNumber) o; | ||
| return number == that.number; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(number); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package com.javabom.lotto.domain.ticket; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public interface LottoNumberGenerator { | ||
|
|
||
| List<LottoNumber> getLottoNumbers(); | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package com.javabom.lotto.domain.ticket; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Objects; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| public class LottoTicket { | ||
|
|
||
| private static final int LOTTO_NUM_PICK_SIZE = 6; | ||
|
|
||
| private final List<LottoNumber> numbers; | ||
|
|
||
| public LottoTicket(List<LottoNumber> numbers) { | ||
| validateListSize(numbers); | ||
| this.numbers = numbers; | ||
| } | ||
|
|
||
| private void validateListSize(List<LottoNumber> numbers) { | ||
| if (numbers.size() != LOTTO_NUM_PICK_SIZE) { | ||
| throw new IllegalArgumentException("로또 티켓에 6개 숫자를 넣어야 합니다."); | ||
| } | ||
| } | ||
|
|
||
| public List<Integer> getNumbers() { | ||
| return numbers.stream() | ||
| .map(LottoNumber::get) | ||
| .collect(Collectors.toList()); | ||
| } | ||
|
|
||
| public boolean isContain(LottoNumber number) { | ||
| return numbers.contains(number); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
|
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. 이 LottoTicket의 equals는 어디에서 사용하는 거야?? 일단 실제 코드에는 사용하지않는 것 같고 사용한다면 테스트 코드에서 사용할 것 같은데 내 생각은 equals는 조심해서 사용해야 한다고 생각해. LottoTicket이 같은 경우가 코드대로라면은 티켓이 들고있는 LottoNumber들이 같을 때 같다고 하게 되는데, 그렇게 되면 똑같은 번호로 산 로또 2개는 같은 Ticket 이라는 의미가 될것같아. Set은 중복을 허용하지 않는데, Ticket을 Set에 넣는다고 가정했을때 같은 번호를 가지고있는 Ticket 2개를 넣게되면 Set에는 1개만 들어가게 될것같아.
Member
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. 내생각에는 같은 번호의 로또 티켓이라면 같은 티켓이 맞다고 봐. |
||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| LottoTicket that = (LottoTicket) o; | ||
| return Objects.equals(numbers, that.numbers); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(numbers); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package com.javabom.lotto.domain.ticket; | ||
|
|
||
| import java.util.ArrayList; | ||
|
|
||
| public class LottoTicketDispenser { | ||
|
|
||
| private static final int LOTTO_TICKET_PRICE = 1_000; | ||
|
|
||
| private final LottoNumberGenerator lottoNumberGenerator; | ||
|
|
||
| public LottoTicketDispenser(LottoNumberGenerator lottoNumberGenerator) { | ||
| this.lottoNumberGenerator = lottoNumberGenerator; | ||
| } | ||
|
|
||
| public LottoTickets getAutoTickets(Money inputMoney) { | ||
| int quantity = (int) inputMoney.get() / LOTTO_TICKET_PRICE; | ||
|
Member
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. Money가 해줄수 있는 일
Member
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. 뭔가 돈이 개수를 반환하는게 이상하다고 생각해서 여기다가 나누었었어 |
||
| ArrayList<LottoTicket> tickets = new ArrayList<>(); | ||
|
Member
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. 구현체에 의존하지 말고 인터페이스에 의존하자! |
||
| for (int i = 0; i < quantity; i++) { | ||
| tickets.add(new LottoTicket(lottoNumberGenerator.getLottoNumbers())); | ||
| } | ||
| return new LottoTickets(tickets); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package com.javabom.lotto.domain.ticket; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.Objects; | ||
|
|
||
| public class LottoTickets { | ||
|
|
||
| private final List<LottoTicket> tickets; | ||
|
|
||
| public LottoTickets(List<LottoTicket> tickets) { | ||
| this.tickets = tickets; | ||
| } | ||
|
|
||
| public List<LottoTicket> get() { | ||
| return Collections.unmodifiableList(tickets); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| LottoTickets that = (LottoTickets) o; | ||
| return Objects.equals(tickets, that.tickets); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(tickets); | ||
| } | ||
| } |
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.
이건 그냥 갑자기 혁님 코드 보고 떠오른 건데 한번 토론해보세요ㅋㅋ 이 방법은 어떤가 싶어서 코멘트 답니다.
지금 LottoTicketComparator를 보면 luckyNumbers와 LottoTicket모두 LottoNumber 리스트를 꺼내서 카운팅하고있는데,
만약 추상클래스로 LottoNumbers를 파고,
그아래 자식클래스로 이 LottoBasicLuckyNumbers / 그리고 사용자들의 티켓을 받는 자식클래스인 LottoUserNumbers
이렇게 분리하는건 어떤가 싶어요.
왜냐면 둘다 똑같은 List numbers 의 기능을 갖고있어서 겹치는 부분이 있다고 판단하기 때문입니다.
이때 둘이 다른 서브 클래스로 나누는 이유는 validation로직이 다르지 않나 싶어서 입니다..!!
그리고 나서 부모 클래스인 LottoNumbers에, compare method를 두어서 LottoNumbers 클래스끼리 비교하는 메서드를 만드는건 어떤가 싶어요.
그러면 LottoTicektComparator에서 List 레벨까지 꺼내지 않아도, 그저
luckyNumbers.compare(lottoTicket);
으로 끝낼 수 있지 않을까 싶어서 입니다.
같은 성질을 가진 티켓에 대한 비교를 LottoTicketcomparator가 책임을 갖고있는게 아니라,
LottoTicket 자체가 갖고있는거죠.
음 근데 이렇게 하면 혁님 코드에서는 comparator 패키지를 새로 땃으니 조금 이상해 보일수도 있겠네요ㅋㅋ
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.
아 그러네요 둘다 똑같이 List 를 들고있다는점이 공통점이네요.
추상클래스 파서 서브클래스 둘 때 네이밍이 직관적이지 않을까 걱정이 되긴합니다. 근데 의견 동의합니다! 좋은 방법인거같아요
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.
구현하다가 막힌점들이 있습니다.
기본 로또 숫자 6개를 비교하는건 가능하나, 나머지 보너스 숫자를 어떻게 비교해서 결과를 내줘야할지 모르겠습니다.
그리고 티켓이든 BasicLuckyNumbers든 한곳에서만 compare 메소드를 호출할 텐데, 다른 한곳에 열려있어도 괜찮은건지 모르겠습니다.
또, 여러 티켓들을 비교하려면 외부에서 compare를 여러번 호출해주어야하는데 이 때에 결국 다른 클래스가 일을 맡게되지 않나 라는 생각이 들었습니다.
역량이 부족해서 구현하기 어렵습니다 ㅠㅠ