-
Notifications
You must be signed in to change notification settings - Fork 107
[SCG] 손희창 로또 1-2단계 미션 제출합니다. #161
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
Changes from all commits
98a1b03
6a3ca76
3a7f998
c23b07b
a883c16
0d08c93
408b4ce
d470a88
c796209
d7805a2
021a3f1
2f79b40
59d3178
ffb852a
baf39a6
8545419
b7b010e
7210ab1
862dfe6
e466fce
4448e93
282d716
3906648
ed4b505
b1e595d
412cb11
97ab632
e4e62f4
7d25314
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,121 @@ | ||
| # 1단계 요구사항 정리 | ||
|
|
||
| --- | ||
|
|
||
| ## 기능 요구사항 | ||
|
|
||
| - [x] 로또 구입 금액을 입력하면 구입 금액에 해당하는 로또를 발급해야 한다. | ||
| - [x] 로또 1장의 가격은 1000원이다. | ||
| - [x] 로또 당첨 번호를 받아 일치한 번호 수에 따라 당첨 결과를 보여준다. | ||
|
|
||
| ## 새로운 프로그래밍 요구사항 | ||
|
|
||
| - [x] 배열 대신 컬렉션을 사용한다. | ||
| - [x] 줄여 쓰지 않는다(축약 금지). | ||
| - [x] 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다. | ||
| - [x] 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라. | ||
|
Comment on lines
+13
to
+16
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. 앗 프로그래밍요구사항이 섞였네요😅 |
||
| - [x] 모든 원시 값과 문자열을 포장한다. | ||
| - [x] 일급 컬렉션을 쓴다. | ||
|
|
||
| ## 기존 프로그래밍 요구사항 | ||
|
|
||
| 자바 코드 컨벤션을 지키면서 프로그래밍한다. | ||
| 기본적으로 Java Style Guide을 원칙으로 한다. | ||
| indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다. | ||
| 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. | ||
| 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. | ||
| 3항 연산자를 쓰지 않는다. | ||
| else 예약어를 쓰지 않는다. | ||
| else 예약어를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. | ||
|
|
||
| --- | ||
|
|
||
| ## 사용할 클래스의 종류 및 특징 정리 | ||
|
|
||
| ### 도메인 | ||
|
|
||
| #### Money | ||
|
|
||
| 1. 입력금액을 저장한다. | ||
| 2. 로또 횟수정보를 환산하여 저장한다. | ||
| 3. 입력과정에서 예외처리를 수행한다. | ||
|
|
||
| #### RandomLottoGenerator | ||
|
|
||
| 원소가 6개인 중복 없는 랜덤 ArrayList를 생성하여 반환한다. | ||
|
|
||
| #### Lotto | ||
|
|
||
| 리스트 형태의 로또 일급 클래스 | ||
|
|
||
| #### LottoCalculator | ||
|
|
||
| 겹침 횟수를 환산하고 Rank와 매핑하고 전체 상금액을 구하여 수익률을 구한다. | ||
|
|
||
| #### LottoNumber | ||
|
|
||
| 자료형 형태의 로또 숫자 클래스 | ||
|
|
||
| #### Lottos | ||
|
|
||
| 리스트 형태의 로또 일급 클래스를 담는 일급 클래스 | ||
|
|
||
| #### Rank(Enum) | ||
|
|
||
| 겹침 횟수와 해당 금액을 저장한다. | ||
| 겹침 횟수를 받으면 겹침 횟수와 해당 금액을 함께 반환한다. | ||
|
|
||
| ### 뷰 | ||
|
|
||
| #### InputView | ||
|
|
||
| 금액을 입력받는다. | ||
| 이후 입력받은 금액을 return함. | ||
|
|
||
| ### ResultView | ||
|
|
||
| 횟수를 출력하고, | ||
| 이 횟수만큼 반복하여 ArrayList를 출력한다. | ||
| 통계와 수익률을 출력한다. | ||
|
|
||
| ### 컨트롤러 | ||
|
|
||
| #### Application | ||
|
|
||
| 도메인과 뷰를 실행한다. | ||
|
|
||
| # 예외 처리 | ||
|
|
||
| - 구입금액에서 빈값을 받았을 때 | ||
| - 구입금액이 숫자가 아닐 때 | ||
| - 구입금액이 1000원보다 작을 때 | ||
| - 구입금액이 1000원 단위가 아닐 때 | ||
| - 지난 주 당첨번호가 적절한 형식이 아닐 때 | ||
| - 지난 주 당첨번호들 중 중복된 번호가 있을 때 | ||
| - 로또 번호가 1~45 범위가 아닐때 | ||
| - 지난 주 당첨번호 개수가 6개가 아닐 때 | ||
|
|
||
| # 테스트 케이스 | ||
|
|
||
| ```text | ||
| 구입금액을 입력해 주세요. | ||
| 5000 | ||
|
|
||
| 5개를 구매했습니다. | ||
| [3, 14, 16, 18, 22, 40] | ||
| [4, 18, 19, 30, 31, 36] | ||
| [7, 9, 20, 22, 30, 41] | ||
| [6, 18, 20, 28, 35, 39] | ||
| [5, 13, 14, 37, 44, 45] | ||
|
|
||
| 지난 주 당첨번호를 입력해 주세요. | ||
| 3, 14, 20, 22, 30, 40 | ||
|
|
||
| 당첨 통계 | ||
| --------- | ||
| 6개 일치 (2000000000)- 0개 | ||
| 5개 일치 (1500000)- 0개 | ||
| 4개 일치 (50000)- 1개 | ||
| 3개 일치 (5000)- 1개 | ||
| 총 수익률은 11.00입니다.(기준이 1이기 때문에 결과적으로 이득이라 더 뽑아도 된다는 의미임) | ||
| ``` | ||
|
Comment on lines
+98
to
+121
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. 지난 주 당첨번호를 다양한 경우로 입력해보며 테스트 가능합니다 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. 직접 입력하는 것보다 더 좋은 방법이 있을까요 ? 희창님도 매번 직접 실행해서 눈으로 확인하면 번거롭지 않으신가요? |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import domain.Lotto; | ||
| import domain.LottoCalculator; | ||
| import domain.LottoMachine; | ||
| import domain.Lottos; | ||
| import domain.Money; | ||
| import domain.RandomLottoGenerator; | ||
| import domain.Rank; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import view.InputView; | ||
| import view.ResultView; | ||
|
|
||
| public class Application { | ||
| private final InputView inputView = new InputView(); | ||
| private final ResultView resultView = new ResultView(); | ||
| private final RandomLottoGenerator random = new RandomLottoGenerator(); | ||
|
|
||
| public void run() { | ||
| final int amount = inputView.getMoney(); //돈 받기 | ||
| Money money = new Money(amount); // 돈 저장 | ||
| final int number = LottoMachine.calculateTicketCount(money); // 로또 뽑는 횟수 | ||
| resultView.printPurchaseCount(number); | ||
| Lottos lottos = purchaseLotto(number); | ||
| Lotto winnerNumbers = inputView.getWinnerNumbers(); //당첨번호 로또 입력 | ||
| LottoCalculator calculator = calculatorResult(lottos, winnerNumbers); //당첨 결과 계산 | ||
| printStatistics(calculator, money);//최종 통계 및 수익률 출력 | ||
| } | ||
|
|
||
|
|
||
| public Lottos purchaseLotto(int count) { | ||
| List<Lotto> purchased = new ArrayList<>(); | ||
| for (int i = 0; i < count; i++) { | ||
| Lotto lotto = random.generate(); | ||
| printLotto(lotto); | ||
| purchased.add(lotto); | ||
| } | ||
| return new Lottos(purchased); | ||
| } | ||
|
|
||
| public void printLotto(Lotto lotto) { | ||
| resultView.printLottoNumbers(lotto); | ||
| } | ||
|
|
||
| private LottoCalculator calculatorResult(Lottos lottos, Lotto winnerNumbers) { | ||
| LottoCalculator calculator = new LottoCalculator(); | ||
| for (Lotto lotto : lottos.getLottos()) { | ||
| int matchCount = lotto.getMatchNumbers(winnerNumbers); | ||
| Rank rank = Rank.MISS.valueOf(matchCount); | ||
| calculator.valueAdd(rank); | ||
| } | ||
| return calculator; | ||
| } | ||
|
|
||
| public void printStatistics(LottoCalculator calculator, Money money) { | ||
| resultView.printStatics(); | ||
| for (Rank rank : Rank.values()) { | ||
| AddWinningMoney(calculator, rank); | ||
| } | ||
| double yield = calculator.calculateYield(money); | ||
| resultView.printYield(yield, yield >= 1.0); | ||
| } | ||
|
|
||
| public void AddWinningMoney(LottoCalculator calculator, Rank rank) { | ||
| if (rank != Rank.MISS) { | ||
| resultView.printWinningStatics( | ||
| rank.getMatchnumbers(), | ||
| rank.getPrizemoney(), | ||
| calculator.getResult().get(rank) | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| public static void main(String[] args) { | ||
| Application lotto = new Application(); | ||
| lotto.run(); | ||
|
|
||
| } | ||
|
|
||
|
Comment on lines
+76
to
+78
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. 넵넵 |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package domain; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class Lotto { | ||
| public static final int LOTTO_NUMBER_COUNT = 6; | ||
| private final List<LottoNumber> lottoNumbers; | ||
|
|
||
| public Lotto(List<LottoNumber> lottoNumbers) { | ||
| validate(lottoNumbers); | ||
| this.lottoNumbers = lottoNumbers; | ||
| } | ||
|
|
||
| private void validate(List<LottoNumber> numbers) { | ||
| validateSize(numbers); | ||
| validateDuplicate(numbers); | ||
| } | ||
|
|
||
| private void validateSize(List<LottoNumber> numbers) { | ||
| if (numbers.size() != LOTTO_NUMBER_COUNT) { | ||
| throw new IllegalArgumentException("로또 숫자 개수가 " + LOTTO_NUMBER_COUNT + "개여야 합니다."); | ||
| } | ||
| } | ||
|
|
||
| private void validateDuplicate(List<LottoNumber> numbers) { | ||
| long distinctCount = numbers.stream() | ||
| .distinct() | ||
| .count(); | ||
|
|
||
| if (distinctCount != numbers.size()) { | ||
| throw new IllegalArgumentException("중복된 로또 숫자가 존재합니다."); | ||
| } | ||
| } | ||
|
|
||
| public List<LottoNumber> getLotto() { | ||
| return lottoNumbers; | ||
| } | ||
|
Comment on lines
+35
to
+37
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. 로또를 get하는데, 왜 로또 넘버가 나올까요?
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. 여기서 Lotto는 클래스 명을 따르며 6개 숫자를 묶은 로또 한개를 의미했고 변수설정을 위에서 numbers로 했는데 이것도 6개 숫자를 묶은 로또 한개를 의미했습니다. 다른 사람이 보기에 너무 헷갈릴 것 같아 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. 아하 제 질문 의도는 취향 차이이긴 한데, 저는 클래스 이름이 이미 문맥을 설명하고 있다면 필드명이나 메서드명에서 그 이름을 반복하지 않는 편이 더 좋더라고요~ 그래서 getNumbers가 가장 좋다고 생각해요!
Comment on lines
+35
to
+37
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.getLotto()를 호출하고, 로또 넘버를 바꿀 수 있는 상황에 대해서 어떻게 생각하시나요?
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. (현재 numbers를 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. final은 이 변수가 가리키는 주소를 바꿀 수 없다는 뜻입니다! 그래서 리스트를 바라보는 참조를 변경할 수는 없어요. 이런 동작을 막기 위해서는 어떻게 해야할까요? 학습해보시면 좋을 것 같습니다! |
||
|
|
||
| public int getMatchNumbers(Lotto winnerNumbers) { | ||
| return (int) lottoNumbers.stream() | ||
| .filter(winnerNumbers::contains) | ||
| .count(); | ||
| } | ||
|
|
||
| public boolean contains(LottoNumber number) { | ||
| return lottoNumbers.contains(number); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| package domain; | ||
|
|
||
| import java.util.LinkedHashMap; | ||
| import java.util.Map; | ||
|
|
||
| public class LottoCalculator { | ||
|
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. 겹침 횟수에 따라 상금을 누적하는 역할을 합니다. 이부분도 저에게 생소한 Enum관련된 로직이 있어 설명이 안되네요... |
||
| private final Map<Rank, Integer> result; | ||
|
|
||
| public LottoCalculator() { | ||
| result = new LinkedHashMap<>(); | ||
| for (Rank rank : Rank.values()) { | ||
| result.put(rank, 0); | ||
| } | ||
| } | ||
|
|
||
| public void valueAdd(Rank rank) { | ||
| result.put(rank, result.get(rank) + 1); | ||
|
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. +1 이 없으면 가독성이 더 좋아지지 않을까요 ?
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. 앗 제가 Enum부분을 처음 다뤄봐 마땅한 해결책은 모르겠네요.. 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. 이후 ENUM 관련 학습을 진행하면서 수정해봐도 좋을 것 같아요~ |
||
| } | ||
|
|
||
| public double calculateYield(Money money) { | ||
| double totalPrize = 0; | ||
| for (Rank rank : Rank.values()) { | ||
| totalPrize += rank.getPrizemoney() * result.get(rank); | ||
| } | ||
| return totalPrize / money.getAmount(); | ||
| } | ||
|
|
||
| public Map<Rank, Integer> getResult() { | ||
| return result; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package domain; | ||
|
|
||
| public class LottoMachine { | ||
| private static final int LOTTO_PRICE = 1000; | ||
|
|
||
| public static int calculateTicketCount(Money money) { | ||
| int amount = money.getAmount(); | ||
| validateLottoUnit(amount); | ||
| return amount / LOTTO_PRICE; | ||
| } | ||
|
|
||
| private static void validateLottoUnit(int amount) { | ||
| if (amount < LOTTO_PRICE || amount % LOTTO_PRICE != 0) { | ||
| throw new IllegalArgumentException("로또는 1000원 단위로만 구매 가능합니다."); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package domain; | ||
|
|
||
| public class LottoNumber { | ||
| public static final int MAX_NUMBER = 45; | ||
| public static final int MIN_NUMBER = 1; | ||
| private final int number; | ||
|
|
||
| public LottoNumber(int number) { | ||
| validatorNumber(number); | ||
| this.number = number; | ||
| } | ||
|
|
||
| public void validatorNumber(int number) { | ||
| if (number < MIN_NUMBER || number > MAX_NUMBER) { | ||
| throw new IllegalArgumentException("로또 번호가 범위를 벗어났습니다."); | ||
| } | ||
| } | ||
|
|
||
| public int getNumber() { | ||
| return number; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return String.valueOf(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 java.util.Objects.hash(number); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package domain; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class 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. Lottos 클래스가 더 많은 일을 할 수 있을 것 같아요! 30줄 이상으로 만들어보는 미션을 드리고 싶어요~
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. 아앗.. 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. 음... 사용자가 돈을 내면 로또가 하나 이상 생성되잖아요? 그 생성부터 결과 확인까지, 여러 장의 로또를 가지고 해야 하는 일들을 생각해보세요. 기존 클래스를 삭제해도 좋습니다! |
||
| private final List<Lotto> lottos; | ||
|
|
||
| public Lottos(List<Lotto> lottos) { | ||
| this.lottos = lottos; | ||
| } | ||
|
|
||
| public List<Lotto> getLottos(){ | ||
| return lottos; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| package domain; | ||
|
|
||
| public class Money { | ||
| private final int amount; | ||
|
|
||
| public Money(int amount) { | ||
| validatePositive(amount); | ||
| this.amount = amount; | ||
| } | ||
|
|
||
| private void validatePositive(int amount) { | ||
| if (amount < 0) { | ||
| throw new IllegalArgumentException("금액은 음수일 수 없습니다."); | ||
| } | ||
| } | ||
|
|
||
| public int getAmount() { | ||
| return amount; | ||
| } | ||
| } |
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.
사실 리드미가 없어도 됩니다! 😄
코드의 의도와 동작을 문서 없이 표현하는 방법이 있을까요?
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.
깊게 생각해주셨군요!
실제로 기대한 동작을 하고 있다는 것을 한 눈에 볼 수 있는 방법도 있을텐데, 그것은 무엇일까요 ㅎㅎㅎㅎㅎ