Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
1756707
docs: 기능 구현 목록 작성
chae-heechan Mar 29, 2021
db1647d
docs: 입력 금액 예외 사항 정리
chae-heechan Mar 29, 2021
673ac2e
docs: 클래스 정리
chae-heechan Mar 31, 2021
5e62790
feat: 클래스 생성
chae-heechan Mar 31, 2021
73db742
feat: lotto 번호 생성 기능 추가
chae-heechan Apr 1, 2021
b74d509
refactor: 난수 생성 메소드 stream으로 수정
chae-heechan Apr 1, 2021
5863fc8
feat: 로또 발권 기능 추가
chae-heechan Apr 1, 2021
3406e4a
feat: 입력 타입 String으로 변경
chae-heechan Apr 1, 2021
1318d7a
feat: 로또 번호 출력 기능 추가
chae-heechan Apr 1, 2021
7fa1b41
docs: 기능 구현 목록 변경
chae-heechan Apr 1, 2021
380b00e
docs: 예외 사항 목록 변경
chae-heechan Apr 1, 2021
6aea022
docs: 클래스 목록 변경
chae-heechan Apr 1, 2021
2e761cf
refactor: LottoTicket 구조 변경
chae-heechan Apr 2, 2021
40543c8
feat: LottoApplication 구현
chae-heechan Apr 2, 2021
983c002
feat: Printer 구현
chae-heechan Apr 2, 2021
e1efbaf
refactor: 생성자 구현
chae-heechan Apr 2, 2021
b0db442
fix: language level 변경
chae-heechan Apr 2, 2021
f5c9577
feat: GameResult 구현
chae-heechan Apr 2, 2021
4b04a8b
refactor: LottoTickets 구조 변경
chae-heechan Apr 2, 2021
c0d6281
refactor: Issuer 구조 변경
chae-heechan Apr 2, 2021
60fc2a0
feat: Statistics 구현
chae-heechan Apr 2, 2021
a01c323
feat: MatchCount 구현
chae-heechan Apr 2, 2021
77cddd7
feat: LottoNumber 구현
chae-heechan Apr 2, 2021
f2068d1
feat: WinningNumber 구현
chae-heechan Apr 2, 2021
1e16e0d
feat: WinningResult 구현
chae-heechan Apr 2, 2021
f13151d
feat: GameResults 구현
chae-heechan Apr 2, 2021
0f8bc09
test: GameResultTest 작성
chae-heechan Apr 2, 2021
09c6fb4
test: IssuerTest 작성
chae-heechan Apr 2, 2021
eef113d
test: LottoNumberTest 작성
chae-heechan Apr 2, 2021
f9638c7
test: MatchCountTest 작성
chae-heechan Apr 2, 2021
13f3aac
test: StatisticsTest 작성
chae-heechan Apr 2, 2021
ac4f5f2
test: WinningNumberTest 작성
chae-heechan Apr 2, 2021
a87480f
test: WinningResultTest작성
chae-heechan Apr 2, 2021
7cfa859
feat: 코드 병합
chae-heechan Apr 2, 2021
2e40f10
feat: 수동 로또 생성 기능 추가
chae-heechan Apr 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,47 @@
# 🚀 로또 1단계 - 자동

## 📋기능 구현 목록

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기능 목록 👍🏻

* **UI 로직**
- [x] 구매 금액 입력
- [x] 당첨 번호 입력(보너스 볼)
- [x] 로또 번호 출력
- [x] 당첨 금액 출력
- [x] 수익률 출력

* **비지니스 로직**
- [x] 로또 번호는 45까지 허용
- [x] 로또 번호는 6개
- [x] 보너스 번호는 1개
- [x] 로또 한 장 당 가격은 1000원
- [x] 로또 티켓 갯수 계산
- [x] 로또 번호 생성
- [x] 일치 여부 확인
- [x] 당첨 금액 계산
- [x] 수익률 계산


## 🎯예외 사항 목록
* **구매 금액 입력**
- [x] 1000원 이하일 경우
- [x] 1000원 단위가 아닐 경우

* **로또 번호 입력**
- [x] 46 이상의 입력이 있을 경우
- [x] 중복된 수가 입력될 경우
- [x] 6개 이상 입력 될 경우
- [x] 보너스 볼이 1개 이상 입력 될 경우


## 클래스 및 매소드
- Application
- Lotto
- Lottos
- WinningNumber
- Printer
- Receiver



## 기능 요구사항
- 로또 구입 금액을 입력하면 구입 금액에 해당하는 로또를 발급해야 한다.
- 로또 1장의 가격은 1000원이다.
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apply plugin: 'java'
apply plugin: 'eclipse'

version = '1.0.0'
sourceCompatibility = 1.8
sourceCompatibility = 14

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

프로젝트의 자바 버전을 올린 이유가 있을까요?


repositories {
mavenCentral()
Expand Down
Empty file removed src/main/java/empty.txt
Empty file.
90 changes: 90 additions & 0 deletions src/main/java/lotto/LottoApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package lotto;

import lotto.domain.Statistics;
import lotto.domain.factory.Issuer;
import lotto.domain.lotto.LottoTickets;
import lotto.domain.lotto.WinningNumber;
import lotto.domain.result.GameResults;
import lotto.ui.Printer;
import lotto.ui.Receiver;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class LottoApplication {
private static final String LOTTO_NUMBER_INPUT_DELIMITER = ", ";
private static final int LOTTO_TICKET_PRICE = 1000;
private static final String LOTTO_TICKET_PRICE_RANGE_EXCEPTION_MESSAGE =
"수동 구매 티켓의 갯수가 구입 금액을 초과했습니다.";

private final Printer printer;
private final Receiver receiver;

public LottoApplication(Printer printer, Receiver receiver) {
this.printer = printer;
this.receiver = receiver;
}

public static void main(String[] args) {
LottoApplication app = new LottoApplication(new Printer(), new Receiver(System.in));
app.run();
Comment on lines +31 to +32

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Application이 Application을 생성해서 실행시키는 것이 어색하게 느껴지네요.
run()은 애플리케이션의 흐름을 제어하면서 로직을 진행시키는 것 같은데 이것을 따로 객체로 분리해보면 어떨까요?
MVC 패턴과 Controller의 역할에 대해 학습해보면 좋을것같아요.

https://m.blog.naver.com/jhc9639/220967034588

}

public void run() {
int purchaseAmount = receivePurchaseAmount();
int manualTicketCount = receiveManualTicketCount(purchaseAmount);
LottoTickets lottoTickets = Issuer.issueManualLottoTickets(manualTicketCount, receiveManualTicketNumber(manualTicketCount));
lottoTickets.addTickets(Issuer.issueLottoTickets(purchaseAmount, manualTicketCount));
printer.printIssuedTickets(lottoTickets, manualTicketCount);

WinningNumber winningNumber = new WinningNumber(receiveWinningNumber(), receiveBonusNumber());
GameResults gameResults = lottoTickets.matchNumbers(winningNumber);
Statistics statistics = new Statistics(gameResults, purchaseAmount);
printer.printStatistics(statistics);
}

private int receivePurchaseAmount() {
printer.requestPurchaseAmount();
String purchaseAmount = receiver.receiveLine();
return Integer.parseInt(purchaseAmount);
}

private int receiveManualTicketCount(int purchaseAmount) {
printer.requestManualTicketCount();
int manualTicketCount = Integer.parseInt(receiver.receiveLine());
if(manualTicketCount > purchaseAmount/LOTTO_TICKET_PRICE){
throw new IllegalArgumentException(LOTTO_TICKET_PRICE_RANGE_EXCEPTION_MESSAGE);
}
Comment on lines +57 to +59

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PurchaseAmount란 객체를 만들고 이 역할을 하도록 할 수 있지 않을까요?
main의 역할이 너무 큰 것 같아요.

return manualTicketCount;
}

private List<List<Integer>> receiveManualTicketNumber(int manualTicketCount) {
printer.requestManualTicketNumber();
List<List<Integer>> manualTickets = new ArrayList<>();
for(int count = 0; count <manualTicketCount; count++) {
String manualNumber = receiver.receiveLine();

manualTickets.add(Arrays.stream(manualNumber.split(LOTTO_NUMBER_INPUT_DELIMITER))
.map(Integer::valueOf)
.collect(Collectors.toList()));
}
return manualTickets;
}

private List<Integer> receiveWinningNumber() {
printer.requestWinningNumber();
String winningNumber = receiver.receiveLine();

return Arrays.stream(winningNumber.split(LOTTO_NUMBER_INPUT_DELIMITER))
.map(Integer::valueOf)
.collect(Collectors.toList());
Comment on lines +80 to +82

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것은 로또 번호를 생성하는 비즈니스 로직인데 Application에 드러나는 것이 적절하지 않은 것 같아요.
객체에게 위임하고 값을 돌려받는 식으로 변경해보는건 어떨까요?

}

private int receiveBonusNumber() {
printer.requestBonusNumber();
String bonusNumber = receiver.receiveLine();
return Integer.parseInt(bonusNumber);
}
}
27 changes: 27 additions & 0 deletions src/main/java/lotto/domain/MatchCount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package lotto.domain;
public class MatchCount {
private final int matchCount;
private final boolean isBonusMatch;
public MatchCount(int matchCount, boolean isBonusMatch) {
this.matchCount = matchCount;
this.isBonusMatch = isBonusMatch;
}
public boolean isUnderThree() {
return matchCount < 3;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전역상수로 빼는 방향은 어떠신가요??? 예를들어 로또의 규칙이 바뀌거나 범위가 1~45에서 바뀔 경우 상수로 빼는것도 좋을 것 같아요!!!

}
public boolean isMatchThree() {
return matchCount == 3;
}
public boolean isMatchFour() {
return matchCount == 4;
}
public boolean isMatchFiveWithoutBonus() {
return matchCount == 5 && !isBonusMatch;
}
public boolean isMatchFiveWithBonus() {
return matchCount == 5 && isBonusMatch;
}
public boolean isAllMatch() {
return matchCount == 6;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isAllMatch 와 matchCount == 6 으로 했을 때 나중에 수정을 할 상황이 올 것 같아요!!!

}
}
35 changes: 35 additions & 0 deletions src/main/java/lotto/domain/Statistics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package lotto.domain;

import lotto.domain.dto.WinningResult;
import lotto.domain.result.GameResult;
import lotto.domain.result.GameResults;

import java.util.List;
import java.util.stream.Collectors;

public class Statistics {
private static final int IS_EQUAL_RATE = 1;

private final GameResults gameResults;
private final int purchaseAmount;

public Statistics(GameResults gameResults, int purchaseAmount) {
this.gameResults = gameResults;
this.purchaseAmount = purchaseAmount;
}

public List<WinningResult> winningResults() {
return GameResult.valuesWithoutUnderThreeMatched()
.stream()
.map(gameResult -> new WinningResult(gameResults.count(gameResult), gameResult))
.collect(Collectors.toList());
}

public double calculateEarningRate() {
return gameResults.calculatePrize() / purchaseAmount;
}

public boolean isProfit(double earningRate) {
return earningRate > IS_EQUAL_RATE;
}
}
18 changes: 18 additions & 0 deletions src/main/java/lotto/domain/dto/WinningResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package lotto.domain.dto;

import lotto.domain.result.GameResult;

public class WinningResult {
private final int numberOfWinners;
private final GameResult gameResult;
public WinningResult(int numberOfWinners, GameResult gameResult) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

numberOfWinners 라고 하니까 살짝 이해가 안될 수도 있을 것 같아요!!! 읽었을 때 우승자의 수?? 이렇게 해석이 될 수도 있지 않을까 하는 조심스러운 리뷰 달겠습니다!!! 저의 지극히 개인적인 생각이옵니다!

this.numberOfWinners = numberOfWinners;
this.gameResult = gameResult;
}
public int getNumberOfWinners() {
return numberOfWinners;
}
public GameResult getGameResult() {
return gameResult;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

개행을 추가하면 될 거에요!!

35 changes: 35 additions & 0 deletions src/main/java/lotto/domain/factory/Issuer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package lotto.domain.factory;
import lotto.domain.lotto.LottoTicket;
import lotto.domain.lotto.LottoTickets;

import java.util.ArrayList;
import java.util.List;
public class Issuer {
private static final int TICKET_PRICE = 1000;
private static final int MINIMUM_NUMBER_OF_TICKETS = 1;
private static final String MONEY_AMOUNT_EXCEPTION_MESSAGE = "금액은 " + TICKET_PRICE + "원 이상으로 입력해주세요.";

public static LottoTickets issueManualLottoTickets(int manualTicketCount, List<List<Integer>> manualLottoTicketNumbers){
validate(manualTicketCount);
List<LottoTicket> manualLottoTickets = new ArrayList<>();
for(int i = 0; i <manualTicketCount; i++) {
manualLottoTickets.add(new LottoTicket(manualLottoTicketNumbers.get(i)));
}
return new LottoTickets(manualLottoTickets);
}

public static LottoTickets issueLottoTickets(int money, int manualTicketCount) {
int numberOfTickets = (money / TICKET_PRICE)-manualTicketCount;
validate(numberOfTickets);
List<LottoTicket> lottoTickets = new ArrayList<>();
for (int i = 0; i < numberOfTickets; i++) {
lottoTickets.add(new LottoTicket());
}
return new LottoTickets(lottoTickets);
}
private static void validate(int numberOfTickets) {
if (numberOfTickets < MINIMUM_NUMBER_OF_TICKETS) {
throw new IllegalArgumentException(MONEY_AMOUNT_EXCEPTION_MESSAGE);
}
}
}
52 changes: 52 additions & 0 deletions src/main/java/lotto/domain/lotto/LottoNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package lotto.domain.lotto;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class LottoNumber {
private static final int LOTTO_NUMBER_LOWER_BOUND = 1;
private static final int LOTTO_NUMBER_UPPER_BOUND = 45;
private static final String LOTTO_NUMBER_RANGE_EXCEPTION_MESSAGE =
"로또 번호는 " + LOTTO_NUMBER_LOWER_BOUND + " 이상, " + LOTTO_NUMBER_UPPER_BOUND + " 이하여야 합니다.";
private final int lottoNumber;
public LottoNumber(int lottoNumber) {
validate(lottoNumber);
this.lottoNumber = lottoNumber;
}
private void validate(int lottoNumber) {
if (!isInRange(lottoNumber)) {
throw new IllegalArgumentException(LOTTO_NUMBER_RANGE_EXCEPTION_MESSAGE);
}
}
private boolean isInRange(int lottoNumber) {
return lottoNumber >= LOTTO_NUMBER_LOWER_BOUND && lottoNumber <= LOTTO_NUMBER_UPPER_BOUND;
}
public static List<LottoNumber> range() {
return IntStream.range(LOTTO_NUMBER_LOWER_BOUND, LOTTO_NUMBER_UPPER_BOUND + 1)
.boxed()
.map(LottoNumber::new)
.collect(Collectors.toList());
}
public static List<LottoNumber> setManualNumber(List<Integer> manualNumber){
List<LottoNumber> lottoNumberManualNumber = new ArrayList<>();
for (Integer integer : manualNumber) {
lottoNumberManualNumber.add(new LottoNumber(integer));
}
return lottoNumberManualNumber;
}
public int getLottoNumber() {
return lottoNumber;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LottoNumber that = (LottoNumber) o;
return lottoNumber == that.lottoNumber;
}
@Override
public int hashCode() {
return Objects.hash(lottoNumber);
}
}
35 changes: 35 additions & 0 deletions src/main/java/lotto/domain/lotto/LottoTicket.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package lotto.domain.lotto;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class LottoTicket {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

살포시 띄어주세요!!!

private static final int NUMBER_OF_LOTTO_NUMBERS = 6;
private List<LottoNumber> lottoNumbers;

public LottoTicket() {
List<LottoNumber> lottoNumbers = LottoNumber.range();
lottoNumbers = generateLottoNumbers(lottoNumbers);
this.lottoNumbers = new ArrayList<>(lottoNumbers);
}
public LottoTicket(List<Integer> manualLottoNumbers){
List<LottoNumber> lottoNumbers = LottoNumber.setManualNumber(manualLottoNumbers);
this.lottoNumbers = new ArrayList<>(lottoNumbers);
}
Comment on lines +11 to +19

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 경우 사용자는 어떤 생성자가 수동 로또 생성인지, 자동 로또 생성인지 모를 것 같아요.
정적 팩토리 메소드로 구분해보는건 어떨까요?


private List<LottoNumber> generateLottoNumbers(List<LottoNumber> lottoNumbers) {
Collections.shuffle(lottoNumbers);
lottoNumbers = lottoNumbers.stream()
.limit(NUMBER_OF_LOTTO_NUMBERS)
.sorted(Comparator.comparing(LottoNumber::getLottoNumber))
.collect(Collectors.toList());
return lottoNumbers;
}
public boolean contains(LottoNumber lottoNumber) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 제가 궁금해서 그런 부분인데 contains 라는 method가 기존에 있는데 같은 이름의 method 를 구현하는게 괜찮은 방향인지 모르겠어요!!!

return lottoNumbers.contains(lottoNumber);
}
public List<LottoNumber> getLottoNumbers() {
return lottoNumbers;
}
}
26 changes: 26 additions & 0 deletions src/main/java/lotto/domain/lotto/LottoTickets.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package lotto.domain.lotto;
import lotto.domain.result.GameResult;
import lotto.domain.result.GameResults;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class LottoTickets {
private final List<LottoTicket> lottoTickets;
public LottoTickets(List<LottoTicket> lottoTickets) {
this.lottoTickets = new ArrayList<>(lottoTickets);
}
public void addTickets(LottoTickets lottoTickets){
this.lottoTickets.addAll(lottoTickets.getLottoTickets());
}
public GameResults matchNumbers(WinningNumber winningNumber) {
List<GameResult> results = lottoTickets.stream()
.map(winningNumber::matchNumbers)
.map(GameResult::evaluate)
.collect(Collectors.toList());
return new GameResults(results);
}
public List<LottoTicket> getLottoTickets() {
return lottoTickets;
}
}
Loading