Skip to content
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

[2주차] 객체지향 코드연습 (Suehyun666) #31

Open
wants to merge 48 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e6ecb6a
lotto 클래스
Suehyun666 Sep 30, 2024
e287377
로또 진행 클래스
Suehyun666 Sep 30, 2024
41845b7
로또 생성 클래스
Suehyun666 Sep 30, 2024
69aba52
result
Suehyun666 Oct 5, 2024
928bcc2
Create OutputHandler.java
Suehyun666 Oct 5, 2024
87adba7
lotto generate
Suehyun666 Oct 5, 2024
26c32dd
lotto
Suehyun666 Oct 5, 2024
355ebf0
inputhandler
Suehyun666 Oct 5, 2024
619aae4
Update LottoGame.java
Suehyun666 Oct 5, 2024
7aaa590
inputhandler
Suehyun666 Oct 5, 2024
77bae68
1.application
Suehyun666 Oct 5, 2024
6049a3f
2. inputhandler
Suehyun666 Oct 5, 2024
a14bc17
3. 로또 클래스
Suehyun666 Oct 5, 2024
bff4f55
4. 결과계산
Suehyun666 Oct 5, 2024
0d78f68
5. 로또 생성기
Suehyun666 Oct 5, 2024
20eb9f3
6. 로또 게임
Suehyun666 Oct 5, 2024
97b2cd3
7. 출력 핸들러
Suehyun666 Oct 5, 2024
1a2ebfe
로또 클래스 다이어그램입니다.
Suehyun666 Oct 6, 2024
1858311
1.1 application
Suehyun666 Oct 9, 2024
fde267e
2.1 inputhandler
Suehyun666 Oct 9, 2024
f208822
2.2 inputconstants
Suehyun666 Oct 9, 2024
55be10e
2.3 inputvalidator
Suehyun666 Oct 9, 2024
a6c7390
3.1 로또 클래스
Suehyun666 Oct 9, 2024
a5440df
3.2 lottoconstants
Suehyun666 Oct 9, 2024
bcb6e36
3.3 로또 구매 정보
Suehyun666 Oct 9, 2024
e48a13c
4.1 결과계산
Suehyun666 Oct 9, 2024
3867749
4.2 결과계산 constants
Suehyun666 Oct 9, 2024
6de8f99
4.3 매치카운트 정보
Suehyun666 Oct 9, 2024
771e99b
7.1 출력 핸들러
Suehyun666 Oct 9, 2024
8382b15
6.1 로또게임
Suehyun666 Oct 9, 2024
64269f2
5.1 당첨번호 저장
Suehyun666 Oct 9, 2024
f018d51
Merge branch 'main' of https://github.com/Suehyun666/practice-oop-lotto
Suehyun666 Oct 9, 2024
89a61c1
삭제할 내용
Suehyun666 Oct 10, 2024
f7c2bbf
1.1.1application
Suehyun666 Oct 10, 2024
3430382
2.1 inputhandler
Suehyun666 Oct 10, 2024
743cfc9
2.2.1 InputConstants
Suehyun666 Oct 10, 2024
732acb0
2.3.1 InputValidator
Suehyun666 Oct 10, 2024
ec97241
3.1.1 lotto
Suehyun666 Oct 10, 2024
2aa1c6f
3.2.1 lottoconstants
Suehyun666 Oct 10, 2024
01e7fe1
3.3.1 purchaseinfo
Suehyun666 Oct 10, 2024
d2112f1
3.4.1 WinningInfo
Suehyun666 Oct 10, 2024
c1af815
4.1.1 resultcalculator
Suehyun666 Oct 10, 2024
96bbaf3
4.2.1 resultconstants
Suehyun666 Oct 10, 2024
4a63945
5.0.1 lottogenerator
Suehyun666 Oct 10, 2024
e764b62
7.1.1OutputHandler
Suehyun666 Oct 10, 2024
dfb20a1
7.2.1 outputconstants
Suehyun666 Oct 10, 2024
bea7598
6.1.1 lottogame
Suehyun666 Oct 10, 2024
958f0a5
4.3.1MatchResult
Suehyun666 Oct 10, 2024
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
4 changes: 3 additions & 1 deletion src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package lotto;

public class Application {

public static void main(String[] args) {
// TODO: 프로그램 구현
LottoGame lottoGame = new LottoGame();
lottoGame.start();
}
}
47 changes: 43 additions & 4 deletions src/main/java/lotto/Lotto.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,59 @@
package lotto;

import camp.nextstep.edu.missionutils.Randoms;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Lotto {
private final List<Integer> numbers;
private final int bonusNumber;
Copy link
Contributor

Choose a reason for hiding this comment

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

과제 요구사항 중 Lotto클래스 내부에 필드를 추가할 수 없다고 적혀있습니다!
요구사항을 지켜주세요

그래도 bonusNumber를 Lotto내에 한곳에 관리한다는 접근은 굉장히 좋았던 것 같습니다.


// 번호를 저장할 수 있는 리스트 생성(ALL)
public Lotto() {
Copy link
Contributor

Choose a reason for hiding this comment

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

매개변수가 없는 생성자를 추가할 수 없다는 요구사항이 있습니다. 요구사항 지켜주세요

this.numbers = new ArrayList<>();
}

// 사용자가 입력한 번호를 받는 생성자 (User)
public Lotto(List<Integer> numbers) {
validate(numbers);
this.numbers = numbers;
}


//일반 번호 6개 생성 (Lotto)
public void generateRandomNumbers() {
numbers.clear();
numbers.addAll(Randoms.pickUniqueNumbersInRange(1, 45, 6));
Copy link
Contributor

Choose a reason for hiding this comment

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

1, 45, 6이 어떤 의미를 가지는지 이름을 지어주세요.
코드 내에 숫자를 그대로 작성하는 것은 가독성을 해칠 뿐만 아니라 유지보수성도 떨어뜨립니다.
매직넘버를 상수로 바꿔주세요.
아래에 관련 링크 남깁니다!

https://velog.io/@jeongbeom4693/JAVA-%EC%83%81%EC%88%98-%EB%A7%A4%EC%A7%81-%EB%84%98%EB%B2%84Magic-Number

}

// 보너스 번호 생성 (Lotto )
private int generateBonusNumber() {
Copy link
Contributor

Choose a reason for hiding this comment

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

코드 컨벤션을 지켜주세요.
private 메소드는 public 메소드 아래에 위치해야 합니다.

int bonus;
do {
bonus = Randoms.pickNumberInRange(1, 45);
} while (numbers.contains(bonus));
return bonus;
}

//get
public List<Integer> getNumbers() {
return numbers;
}

public int getBonusNumber() {
return bonusNumber;
}

//validate
private void validate(List<Integer> numbers) {
Copy link
Contributor

Choose a reason for hiding this comment

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

어떤 검사를 하고있는지, 메소드 명을 구체적으로 변경하여도 좋을 것 같습니다.

if (numbers.size() != 6) {
throw new IllegalArgumentException();
if (numbers.size() != 6 || hasDuplicate(numbers)) {
throw new IllegalArgumentException("[ERROR] 잘못된 로또 번호입니다.");
}
}

// TODO: 추가 기능 구현
private boolean hasDuplicate(List<Integer> numbers) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
private boolean hasDuplicate(List<Integer> numbers) {
private boolean isDuplicated(List<Integer> numbers) {

메소드 명은 개인이 짓는 것이지만, 의견 하나 내보고 갑니다!

Set<Integer> uniqueNumbers = new HashSet<>(numbers);
return uniqueNumbers.size() != numbers.size();
}
}
156 changes: 156 additions & 0 deletions src/main/java/lotto/LottoGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package lotto;

import camp.nextstep.edu.missionutils.Console;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class LottoGame {
Copy link
Contributor

Choose a reason for hiding this comment

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

이 클래스에 너무 많은 책임이 부여되어 있습니다.

  1. 입출력의 책임
  2. 로또를 생성하는 책임
  3. 입력한 String을 관리하기 쉽게 parsing해주는 역할
  4. 비즈니스 로직과 관련된 계산하는 로직
  5. 결과를 출력하기 위한 로직
  6. 입력한 값이 필요한 비즈니스 로직에 넘겨주는 책임

이외에도 여러 책임이 있고 조금 분리해야할 필요성이 보입니다.

//
private static final int LOTTO_PRICE = 1000;
Copy link
Member

Choose a reason for hiding this comment

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

매직넘버로 변수를 관리하는 것은 가독성인 면에서 아주 좋습니다!
매직변수가 많아졌을 때 변수가 어떤 것을 의미하는지 네이밍에 대해서도 신경써주시면 좋을 거 같습니다


//method
public void start() {
//구성요소
int money = getMoney();
int lottoCount = getLottoCount(money);
List<Lotto> boughtLottos = buyLottos(lottoCount);
printLottos(boughtLottos);

// 사용자가 당첨 번호와 보너스 번호 입력
List<Integer> winningNumbers = getWinningNumbers();
int bonusNumber = getBonusNumber(winningNumbers);

// Lotto 클래스에서 자동 생성된 번호와 비교
calculateResults(boughtLottos, winningNumbers, bonusNumber);
}

//Input
//입금
private int getMoney() {
System.out.println("구입금액을 입력해 주세요.");
String input = Console.readLine();
return validateMoney(input);
}
//잘못된 입금 시 에러 처리
Copy link
Member

Choose a reason for hiding this comment

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

메소드간 간격 유지 해주시기 바랍니다.

private int validateMoney(String input) {
Copy link
Contributor

Choose a reason for hiding this comment

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

무언가를 검사하는 메소드에서 String타입을 int타입의 Money를 반환하는 것을 올바르지 않은 것 같습니다.
메소드를 분리해주세요

Suggested change
private int validateMoney(String input) {
private void validateMoney(String input) {

if (!input.matches("\\d+")) {
throw new IllegalArgumentException("[ERROR] 유효한 금액을 입력해 주세요.");
}
int money = Integer.parseInt(input);
if (money < LOTTO_PRICE) {
throw new IllegalArgumentException("[ERROR] 금액은 1000원 이상이어야 합니다.");
}
return money;
}
// how many bought lottos
private int getLottoCount(int money) {
return money / LOTTO_PRICE;
}
// generate lotto (manually)
private List<Lotto> buyLottos(int count) {
List<Lotto> lottos = new ArrayList<>();
for (int i = 0; i < count; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

stream API를 사용하여 가독성을 높일 수 있습니다

lottos.add(new Lotto());
}
return lottos;
}

private List<Integer> getWinningNumbers() {
System.out.println("당첨 번호를 입력해 주세요.");
String input = Console.readLine();
return parseWinningNumbers(input);
}

//,로 파싱 => indentation 수정 예정
private List<Integer> parseWinningNumbers(String input) {
String[] tokens = input.split(",");
if (tokens.length != 6) {
Copy link
Member

Choose a reason for hiding this comment

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

여기서 사용한 6이라는 변수가 무엇을 의미하는지 모르겠습니다!
이 또한 매직변수를 통해 변수의 의미를 지정하여 사용하는 것이 좋습니다!

throw new IllegalArgumentException("[ERROR] 당첨 번호는 6개여야 합니다.");
}
List<Integer> numbers = new ArrayList<>();
for (String token : tokens) {
int number = Integer.parseInt(token.trim());
if (number < 1 || number > 45) {
throw new IllegalArgumentException("[ERROR] 번호는 1부터 45 사이여야 합니다.");
}
numbers.add(number);
}
if (HasDuplicate(numbers)) {
throw new IllegalArgumentException("[ERROR] 중복된 번호가 있습니다.");
}
return numbers;
}

private boolean HasDuplicate(List<Integer> numbers) {
Copy link
Contributor

Choose a reason for hiding this comment

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

메소드 네이밍 컨벤션 지켜주세요

Suggested change
private boolean HasDuplicate(List<Integer> numbers) {
private boolean hasDuplicate(List<Integer> numbers) {

Set<Integer> uniqueNumbers = new HashSet<>(numbers);
return uniqueNumbers.size() != numbers.size();
}

private int getBonusNumber(List<Integer> winningNumbers) {
System.out.println("보너스 번호를 입력해 주세요.");
String input = Console.readLine();
int bonusNumber = Integer.parseInt(input.trim());
if (bonusNumber < 1 || bonusNumber > 45 || winningNumbers.contains(bonusNumber)) {
throw new IllegalArgumentException("[ERROR] 보너스 번호는 1부터 45 사이의 당첨 번호와 중복되지 않는 번호여야 합니다.");
}
return bonusNumber;
}


//Output
// 얼마나 구입했는지 출력
private void printLottos(List<Lotto> lottos) {
System.out.println(lottos.size() + "개를 구매했습니다.");
for (Lotto lotto : lottos) {
System.out.println(lotto.getNumbers());
}
}

//로또 결과 출력
private void calculateResults(List<Lotto> boughtLottos, List<Integer> winningNumbers, int bonusNumber) {
int[] matchCounts = new int[7];
for (Lotto lotto : boughtLottos) {
int matchCount = getMatchCount(lotto.getNumbers(), winningNumbers);
boolean bonusMatch = (lotto.getBonusNumber() == bonusNumber);
matchCounts[getResultIndex(matchCount, bonusMatch)]++;
}
printStatistics(matchCounts);
}

//로또 맞은 개수 출력
private int getMatchCount(List<Integer> numbers, List<Integer> winningNumbers) {
int count = 0;
for (int number : numbers) {
if (winningNumbers.contains(number)) {
count++;
}
}
return count;
}
//1등과 2등 구분
private int getResultIndex(int matchCount, boolean bonusMatch) {
if (matchCount == 6) return 6;
if (matchCount == 5 && bonusMatch) return 5;
return matchCount;
}

//통계 출력
private void printStatistics(int[] matchCounts) {
System.out.println("3개 일치 (5,000원) - " + matchCounts[3] + "개");
System.out.println("4개 일치 (50,000원) - " + matchCounts[4] + "개");
System.out.println("5개 일치 (1,500,000원) - " + matchCounts[5] + "개");
System.out.println("5개 일치, 보너스 볼 일치 (30,000,000원) - " + matchCounts[5] + "개");
System.out.println("6개 일치 (2,000,000,000원) - " + matchCounts[6] + "개");
calculateProfit(matchCounts);
}

//수익률 출력
private void calculateProfit(int[] matchCounts) {
double totalPrize = matchCounts[3] * 5000 + matchCounts[4] * 50000 + matchCounts[5] * 1500000 + matchCounts[6] * 2000000000;
double profitRate = (totalPrize / (matchCounts.length * LOTTO_PRICE)) * 100;
System.out.println("총 수익률은 " + profitRate + "%입니다.");
}
}