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

통합 테스트를 포함하고 컨트롤러를 리팩토링 #7

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3d9dcae
레이어드 아키텍처에 따라 기능 목록 단위 작성
haxr369 Feb 29, 2024
620d197
✨ Feat : 새로운 기능 추가
haxr369 Feb 29, 2024
60cb7de
✅ Test : 테스트 코드 추가
haxr369 Feb 29, 2024
35b56da
📝 Docs : 문서 수정
haxr369 Mar 1, 2024
6fd1c50
✨ Feat : 새로운 기능 추가
haxr369 Mar 2, 2024
798dd51
✨ Feat : 새로운 기능 추가
haxr369 Mar 2, 2024
83a1377
✨ Feat : 새로운 기능 추가
haxr369 Mar 2, 2024
ff16439
✨ Feat : 새로운 기능 추가
haxr369 Mar 3, 2024
399d63e
✨ Feat : 새로운 기능 추가
haxr369 Mar 3, 2024
1f14e7d
✨ Feat : 새로운 기능 추가
haxr369 Mar 3, 2024
cba7969
✨ Feat : 새로운 기능 추가
haxr369 Mar 3, 2024
554a306
✨ Feat : 새로운 기능 추가
haxr369 Mar 5, 2024
df2957b
🐛 Fix : 버그 수정
haxr369 Mar 5, 2024
36f273a
🤖 Refactor : 코드 리팩토링
haxr369 Mar 5, 2024
cd23699
🤖 Refactor : 코드 리팩토링
haxr369 Mar 5, 2024
c9ad654
🤖 Refactor : 코드 리팩토링
haxr369 Mar 5, 2024
377490a
✅ Test : 테스트 코드 추가
haxr369 Mar 5, 2024
8d5f953
🤖 Refactor : 코드 리팩토링
haxr369 Mar 9, 2024
bfdca44
🤖 Refactor : 코드 리팩토링
haxr369 Mar 9, 2024
92c356f
🤖 Refactor : 코드 리팩토링
haxr369 Mar 10, 2024
0609483
🤖 Refactor : 코드 리팩토링
haxr369 Mar 10, 2024
bcbcf52
java 버전 수정 및 출력 형태 수정
haxr369 Mar 10, 2024
592a003
java version 17로 수정
haxr369 Mar 10, 2024
c0f09fc
✅ Test : 테스트 코드 추가
haxr369 Mar 11, 2024
afa5871
🤖 Refactor : 코드 리팩토링
haxr369 Mar 12, 2024
912243a
✅ Test : 테스트 코드 추가
haxr369 Mar 12, 2024
2015f02
🤖 Refactor : 코드 리팩토링
haxr369 Mar 12, 2024
f5ccb88
🤖 Refactor : 코드 리팩토링
haxr369 Mar 12, 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
Empty file modified .github/PULL_REQUEST_TEMPLATE/pull_request_template.md
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion .github/workflows/gradle-test.yml
100644 → 100755
Copy link
Contributor

Choose a reason for hiding this comment

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

Java 19에 대한 의존성을 만든 계기와 이유가 무엇인가요?
요구사항에서는 JDK 17에서의 테스트 성공을 명시해두었는데, 저희가 완전히 동일한 요구사항을 바탕으로 진행하고 있는 것이 아니므로 근거가 필요할 것 같습니다.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/setup-java@v4
with:
distribution: 'liberica'
java-version: '17'
java-version: '19'

- name: Grant execute permission for gradlew
run: chmod +x gradlew
Expand Down
Empty file modified .gitignore
100644 → 100755
Empty file.
Empty file modified .gitmessage.txt
100644 → 100755
Empty file.
Empty file modified README.md
100644 → 100755
Empty file.
Empty file modified build.gradle.kts
100644 → 100755
Empty file.
41 changes: 41 additions & 0 deletions docs/README.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Layered Architecture에 따른 기능 목록

### Presentation Layer - 사용자와 상호작용

- UserInputManager - 사용자의 입력
- 로또 구입 금액 입력
- 당첨 번호 입력
- 보너스 번호 입력
- SystemOutputManager - 값 출력
- 로또 수량 및 번호 출력
- 당첨 내역 출력
- 수익률 출력

### Application Layer - 기능적 요구사항

- LottoGenerator - 금액에 따라 로또를 생성
- 구입 금액에 따른 로또 수량 계산
- 로또 수량에 따른 로또 번호 생성

- LottoResultCalculator - 로또 당첨 내역과 수익률 계산
- 로또의 당첨 내역와 수익률 계산

### Data Layer
- Customer - class - **정확한** 고객의 저장
- 사용자 구입 금액 저장
- 생성한 로또 저장
- 로또 구입 금액 유효성 검사
- LottoCompany - class - **정확한** 당첨 번호와 보너스 번호 저장
- 당첨 번호 저장
- 보너스 번호 저장
- 당첨 번호와 보너스 번호 유효성 검사
- Lotto - record - **정확한** 로또 번호 저장
- 로또 저장
- 생성한 로또 유효성 검사

### Util

- ExceptionStatus - enum
- 예외 코드와 에러 메세지 저장 및 exception 발생
- Winnings - enum
- 상금과 당첨 액수 저장
Empty file modified docs/pull_request_template.md
100644 → 100755
Empty file.
Empty file modified gradle.properties
100644 → 100755
Empty file.
Empty file modified gradle/wrapper/gradle-wrapper.jar
100644 → 100755
Empty file.
Empty file modified gradle/wrapper/gradle-wrapper.properties
100644 → 100755
Empty file.
Empty file modified gradlew
100644 → 100755
Empty file.
Empty file modified gradlew.bat
100644 → 100755
Empty file.
1,481 changes: 1,481 additions & 0 deletions hs_err_pid36733.log
Copy link
Contributor

Choose a reason for hiding this comment

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

이 파일을 함께 커밋한 이유가 무엇인가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

프로그램 테스트나 실행하면서 자동으로 만들어졌나보네요 지우겠습니다!

Large diffs are not rendered by default.

Empty file modified settings.gradle
100644 → 100755
Empty file.
16 changes: 16 additions & 0 deletions src/main/java/lotto/Application.java
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
package lotto;

import lotto.controller.LottoController;
import lotto.model.service.LottoGenerator;
import lotto.view.InputManager;
import lotto.view.OutputManager;
import lotto.view.SystemOutputManager;
import lotto.view.UserInputManager;

import java.util.Random;
import java.util.Scanner;

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
InputManager inputManager = new UserInputManager(new Scanner(System.in));
OutputManager outputManager = new SystemOutputManager();
Random random = new Random();

LottoController lottoController = new LottoController(inputManager, outputManager, random);
lottoController.runGame();
}
}
20 changes: 0 additions & 20 deletions src/main/java/lotto/Lotto.java

This file was deleted.

96 changes: 96 additions & 0 deletions src/main/java/lotto/controller/LottoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package lotto.controller;

import lombok.AllArgsConstructor;
import lotto.model.Lotto;
import lotto.model.dto.Money;
import lotto.model.service.LottoGenerator;
import lotto.model.service.LottoResultCalculator;
import lotto.model.dto.PrizeNumbers;
import lotto.model.enums.Winnings;
import lotto.view.InputManager;
import lotto.view.OutputManager;

import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

@AllArgsConstructor
public class LottoController {
private final InputManager inputManager;
private final OutputManager outputManager;
private final Random random;
// 입력 처리 및 비즈니스 로직 통제
public void runGame(){
LottoGenerator lottoGenerator = new LottoGenerator(random);
LottoResultCalculator lottoResultCalculator = new LottoResultCalculator();
// 돈 받고 로또 생성
Money money = getMoney(Lotto::validateMoney);
int lottoQuantity = lottoGenerator.countQuentityBasedOnMoney(money);
outputManager.outputLottoQuantity(lottoQuantity);
List<Lotto> lottos = lottoGenerator.createLottos(lottoQuantity);
outputManager.outputLottoNumbers(lottos);

PrizeNumbers prizeNumbers = getPrizeNumbersForLotto();
HashMap<Winnings,Integer> lottoResult = lottoResultCalculator.provideWinningDetails(lottos, prizeNumbers);
outputManager.outputWinningDetails(lottoResult);
String rateOrReturn = lottoResultCalculator.calculateReturn(lottoResult, money);
outputManager.outputRateOfReturn(rateOrReturn);
}

// 로또를 사기 위한 구입 금액 입력
// 만약 자동차를 사기 위한 Money를 입력 받는 경우가 생긴다면? 어떻게 할 수 있을까?
// 함수형 인터페이스의 익명함수를 사용하면 유효성 검사 로직과 입력 받는 로직을 분리할 수 있다.
private Money getMoney(Consumer<Money> vaildator){
while(true){
try{
outputManager.displayMessage("구입금액을 입력해 주세요.");
int amount = inputManager.enterPurchaseAmount(); // View
Money money = new Money(amount);
vaildator.accept(money);
return money; // 데이터 생성
}
catch(IllegalArgumentException e){
outputManager.displayMessage(e.getMessage());
}
}
}

private PrizeNumbers getPrizeNumbersForLotto(){
// (w) -> Lotto.validateLottoNumbers(w)
List<Integer> winningNumbers = retryWinningNumbers(Lotto::validateLottoNumbers);
int bonusNumber = retryBonusNumber(winningNumbers, Lotto::validateBonusNumber);
return new PrizeNumbers(winningNumbers, bonusNumber);
}

// Lotto를 위한 당첨금 받기
private List<Integer> retryWinningNumbers(Consumer<List<Integer>> vaildator){
while(true){
try{
outputManager.displayWinningNumbersRequest();
List<Integer> winningNumbers = inputManager.enterWinningNumbers();
vaildator.accept(winningNumbers);
return winningNumbers;
}
catch(IllegalArgumentException e){
outputManager.displayMessage(e.getMessage());
}
}
}

// Lotto를 위한 보너스 받기
private int retryBonusNumber(List<Integer> winningNumbers, BiConsumer<List<Integer>, Integer> vaildator){
while(true){
try{
outputManager.displayBonusNumberRequest();
int bonusNumber = inputManager.enterBonusNumber();
vaildator.accept(winningNumbers, bonusNumber);
return bonusNumber;
}
catch(IllegalArgumentException e){
outputManager.displayMessage(e.getMessage());
}
}
}
}
62 changes: 62 additions & 0 deletions src/main/java/lotto/model/Lotto.java
Copy link
Contributor

Choose a reason for hiding this comment

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

참고) SoC를 신경써서 확장 가능한 프로젝트 구조를 고안하고 있어요
통합 구조 제안

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package lotto.model;

import lotto.model.dto.Money;
import lotto.model.enums.LottoDefinition;
import lotto.model.enums.LottoExceptionStatus;

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

public record Lotto(List<Integer> numbers) {

public Lotto(List<Integer> numbers) {
Lotto.validateLottoNumbers(numbers);
this.numbers = numbers.stream() // 정렬해서 저장
.sorted()
.collect(Collectors.toList());
}

@Override
public String toString(){
return numbers.toString();
}

public static void validateMoney(Money money){
if (money.getMoney() % LottoDefinition.PriceOfLotto.getNumber() > 0) {
throw new IllegalArgumentException(LottoExceptionStatus.IllegalPurchaseRemainderException.getMessage());
}
}

public static void validateBonusNumber(List<Integer> winningNumbers, int bonusNumber) {
validateNumberLottoScope(bonusNumber);
Lotto.validateNumberLottoScope(bonusNumber); // 유효 범위
if(winningNumbers.contains(bonusNumber)){ // 당첨 번호와 중복 체크
throw new IllegalArgumentException(LottoExceptionStatus.IllegalBonusDuplicateException.getMessage());
}
}

public static void validateLottoNumbers(List<Integer> numbers){
validateNumberCount(numbers);
validateNumberDuplicate(numbers);
validateNumbersLottoScope(numbers);
}
private static void validateNumberCount(List<Integer> numbers){
if (numbers.size() != LottoDefinition.SelectionSize.getNumber()) {
throw new IllegalArgumentException(LottoExceptionStatus.IllegalLottoSizeException.getMessage());
}
}
private static void validateNumberDuplicate(List<Integer> numbers){
int distinctSize = (int) numbers.stream().distinct().count();
if(distinctSize != LottoDefinition.SelectionSize.getNumber()){
throw new IllegalArgumentException(LottoExceptionStatus.IllegalLottoDuplicateException.getMessage());
}
}
private static void validateNumberLottoScope(int number){
if(number>LottoDefinition.MaximumNumber.getNumber() || number<LottoDefinition.MinimunNumber.getNumber()){
throw new IllegalArgumentException(LottoExceptionStatus.IllegalLottoScopeException.getMessage());
}
}
private static void validateNumbersLottoScope(List<Integer> numbers){
numbers.forEach(Lotto::validateNumberLottoScope);
}
}
17 changes: 17 additions & 0 deletions src/main/java/lotto/model/dto/Money.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lotto.model.dto;

import lombok.Getter;

@Getter
public class Money {
private int money;
public Money(int money){
validateMoney(money);
this.money = money;
}
private void validateMoney(int money){
if(money < 0 )
// Lotto와는 관련 없는 에러 메시지기 때문에 따로 enum 처리하지 않음
Copy link
Contributor

Choose a reason for hiding this comment

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

우테코에서는 모든 상수를 Enum 처리하라고 가이드 하더라구요

별도의 파일로 분리하기 애매해서 그런거라면, 내부 Enum으로 처리해도 괜찮을 것 같아요

throw new IllegalArgumentException("[ERROR] 구입 금액은 0 이상일 때 입력할 수 있어요.");
}
}
15 changes: 15 additions & 0 deletions src/main/java/lotto/model/dto/PrizeNumbers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package lotto.model.dto;

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

// 생성되고 더 이상 수정되지 않음
Copy link
Contributor

Choose a reason for hiding this comment

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

생성되고 더 이상 수정되지 않음

어떤 의도로 작성한 주석인가요?

public record PrizeNumbers(List<Integer> winningNumbers, int bonusNumber){

public PrizeNumbers(List<Integer> winningNumbers, int bonusNumber){
this.winningNumbers = winningNumbers.stream() // 정렬해서 저장
.sorted()
.collect(Collectors.toList());
this.bonusNumber = bonusNumber;
}
}
17 changes: 17 additions & 0 deletions src/main/java/lotto/model/enums/LottoDefinition.java
Copy link
Contributor

Choose a reason for hiding this comment

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

oracle namingconventions

MAXIMUM_NUMBER처럼 대문자와 언더바를 활용해서 명명하길 추천하고 있네요
내부적으로 합의한 바가 없기 떄문에 참고만 하면 될 것 같습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lotto.model.enums;

import lombok.Getter;

@Getter
public enum LottoDefinition {
MaximumNumber(45),
MinimunNumber(1),
PriceOfLotto(1000),
SelectionSize(6);

private final int number;

LottoDefinition(int number){
this.number = number;
}
}
25 changes: 25 additions & 0 deletions src/main/java/lotto/model/enums/LottoExceptionStatus.java
Copy link
Contributor

Choose a reason for hiding this comment

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

접두사 [ERROR]에 대한 규칙성을 유틸 클래스로 분리할 수도 있었을텐데 판단 근거가 무엇인가요?

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package lotto.model.enums;

public enum LottoExceptionStatus {

IllegalPurchaseRemainderException("[ERROR] 구입 금액은 1000으로 나눠 떨어질 때 입력할 수 있어요."),
IllegalPurchaseNegativeException("[ERROR] 구입 금액은 0 이상일 때 입력할 수 있어요."),
IllegalLottoDuplicateException("[ERROR] 로또 번호는 중복이 없을 때 입력할 수 있어요."),
IllegalLottoSizeException("[ERROR] 로또 번호는 6개 숫자를 입력할 수 있어요."),
IllegalLottoScopeException("[ERROR] 로또 번호는 1에서 45 사이 숫자를 입력할 수 있어요."),
IllegalBonusDuplicateException("[ERROR] 보너스 번호는 당첨 보호와 중복이 없을 때 입력할 수 있어요.");

private String message;

LottoExceptionStatus(String message){
this.message = message;
}
public String getMessage(){
return message;
}

public IllegalArgumentException makeException(){
return new IllegalArgumentException(getMessage());
}

}
33 changes: 33 additions & 0 deletions src/main/java/lotto/model/enums/Winnings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package lotto.model.enums;

import lombok.Getter;
import java.util.Arrays;

@Getter
public enum Winnings {
Fail(0,0,false),
Copy link
Contributor

Choose a reason for hiding this comment

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

Winnings.Fail로 적혀있는 걸 보고, 오류가 발생하는건가 생각해서 돌아봤는데 그건 아니었네요

Fifth(5000,3,false),
Fourth(50000,4,false),
Third(1500000,5,false),
Second(30000000,5,true),
First(2000000000,6,false);

private int winningValue;
private int winningMatchCount;
private boolean bonusMatchCount;

Winnings(int winningValue,int winningMatchCount, boolean bonusMatchCount) {
this.winningValue = winningValue;
this.winningMatchCount = winningMatchCount;
this.bonusMatchCount = bonusMatchCount;
}

// valueOfWinningsAndBonus의 if문 분기를 제거. 대신 Fail에 따른 Output 로직 수정은 필요.
Copy link
Contributor

Choose a reason for hiding this comment

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

솔이 이전에 if문 분기를 근거로 enum의 효용성을 얘기했을 때 조금 의아했어요
솔이 if문을 두고 저에게 얘기했기 때문에 저도 코드 리뷰로 동일한 얘기를 했던 것 같아요
하지만 제 기준은 동일한데요

람다식으로 n번 순회하는 것보다,
반복문으로 n번 순회하는 것의 가독성이 좋다고 생각하고,
(적은 경우에 대해서는) 그냥 if문으로 나열하는 것이 더 가독성이 좋다고 생각합니다.

이 생각에 대해서는 어떤 입장인지 궁금해요

public static Winnings of(int winningMatchCount, boolean bonusMatch){
return Arrays.stream(values())
.filter(it -> (it.winningMatchCount == winningMatchCount &&
it.bonusMatchCount == bonusMatch))
.findAny()
.orElse(Fail);
}
}
Loading