From e68f567b926f852360378c26df1d65eec04d26ca Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Wed, 3 Dec 2025 22:24:45 +0900 Subject: [PATCH 01/26] =?UTF-8?q?docs:=20=EB=A1=9C=EB=98=90=204=EB=8B=A8?= =?UTF-8?q?=EA=B3=84(=EC=88=98=EB=8F=99)=20=EB=AC=B8=EC=84=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20README=20=EB=A7=81=ED=81=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit README.md - 4단계 문서 링크를 `./docs/04-lotto-manual.md`로 수정하여 잘못된 링크를 정상화 04-lotto-manual.md - 로또 4단계(수동) 요구사항 문서 신규 추가 - 기능 요구사항, 프로그래밍 규칙, 체크리스트, 구현 기능 목록 상세 기술 --- README.md | 2 +- docs/04-lotto-manual.md | 118 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 docs/04-lotto-manual.md diff --git a/README.md b/README.md index cb44fbb4e3..905d38c7bd 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ - **[1단계 - 문자열 계산기](./docs/01-string-calculator.md)** - **[2단계 - 로또(자동)](./docs/02-lotto-auto.md)** - **[3단계 - 로또(2등)](./docs/03-lotto-rank-second.md)** -- **[4단계 - 로또(수동)]()** +- **[4단계 - 로또(수동)](./docs/04-lotto-manual.md)** ## 진행 방법 * 로또 요구사항을 파악한다. * 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 코드 리뷰 요청을 한다. diff --git a/docs/04-lotto-manual.md b/docs/04-lotto-manual.md new file mode 100644 index 0000000000..1222ceff03 --- /dev/null +++ b/docs/04-lotto-manual.md @@ -0,0 +1,118 @@ +# 4단계 - 로또(수동) +*** +## 코드 리뷰 +> PR 링크: +> +## 나의 학습 목표 +- TDD 사이클로 구현 +- 객체지향 생활 체조 원칙 준수 +- 테스트 작성하기 쉬운 구조로 설계 +- 체크리스트 및 피드백 준수 +- 기능 추가 시 컴파일 에러를 최소화하며 점진적인 리팩터링에 도전 +## 기능 요구 사항 +- 현재 로또 생성기는 자동 생성 기능만 제공한다. 사용자가 수동으로 추첨 번호를 입력할 수 있도록 해야 한다. +- 입력한 금액, 자동 생성 숫자, 수동 생성 번호를 입력하도록 해야 한다. +## 힌트 +- 규칙 3: 모든 원시값과 문자열을 포장한다. + - 로또 숫자 하나는 int 타입이다. 이 숫자 하나를 추상화한 LottoNo 객체를 추가해 구현한다. +- 예외 처리를 통해 프로그램이 중단되지 않고 다시 입력할 수 있도록 구현한다. + - 사용자가 잘못된 값을 입력했을 때 java exception으로 에러 처리를 한다. + - java8에 추가된 Optional을 적용해 NullPointerException이 발생하지 않도록 한다. +## 프로그래밍 요구사항 +- 규칙 3: 모든 원시값과 문자열을 포장한다. +- 규칙 5: 줄여쓰지 않는다(축약 금지). +- 예외 처리를 통해 에러가 발생하지 않도록 한다. +- 모든 기능을 TDD로 구현해 단위 테스트가 존재해야 한다. 단, UI(System.out, System.in) 로직은 제외 +- java enum을 적용해 프로그래밍을 구현한다. +- 규칙 8: 일급 콜렉션을 쓴다. +- indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다. +- 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다. +- 자바 코드 컨벤션을 지키면서 프로그래밍한다. +- else 예약어를 쓰지 않는다. +## PR 전 점검 +**[체크리스트 확인하기](checklist.md)** +## 구현 기능 목록 +### 공통 +- [x] 금액 (Money) + - [x] 0원 이상의 정수로 생성 + - [x] 금액 비교 (미만 여부) + - [x] 나눗셈 가능 여부 판단 + - [x] 나눗셈 연산 + - [x] 비율 계산 + - [x] 곱셈 연산 + - [x] 덧셈 연산 + - [x] 원화 문자열 변환 + +### 로또 번호 +- [x] 로또 번호 (LottoNumber) + - [x] 1~45 범위의 정수로 생성 + - [x] 문자열 입력으로 생성 + - [x] 범위 벗어날 시 예외 발생 + - [x] 동일 값은 캐싱된 인스턴스 반환 + +### 로또 +- [x] 로또 (Lotto) + - [x] 6개의 로또 번호로 생성 + - [x] 중복된 번호 존재 시 예외 발생 + - [x] 번호 누락 시 예외 발생 + - [x] 6개가 아닐 시 예외 발생 + - [x] 다른 로또와 일치하는 번호 개수 계산 + - [x] 특정 번호 포함 여부 판단 + - [x] 정렬된 출력용 문자열 반환 + +### 로또 구매 +- [x] 로또 구매 개수 (LottoCount) + - [x] 1개 이상의 정수로 생성 + - [x] 1개 미만일 시 예외 발생 + +- [x] 로또 구매 금액 (LottoPurchaseAmount) + - [x] 금액으로 생성 + - [x] 문자열 입력으로 생성 + - [x] 정수 입력으로 생성 + - [x] 최소 금액(1,000원) 미달 시 예외 발생 + - [x] 1,000원 단위가 아닐 시 예외 발생 + - [x] 구매 가능한 로또 개수 계산 + +- [x] 구매한 로또 목록 (PurchasedLottos) + - [x] 로또 목록으로 생성 + - [x] 빈 목록일 시 예외 발생 + - [x] 당첨 로또와 비교하여 결과 생성 + - [x] 구매 개수 출력용 문자열 반환 + +### 당첨 판정 +- [x] 당첨 로또 (WinningLotto) + - [x] 로또 번호 목록과 보너스 번호로 생성 + - [x] 보너스 번호가 당첨 번호와 중복 시 예외 발생 + - [x] 구매 로또와 비교하여 등수 판정 + +- [x] 등수 (LottoRank) + - [x] 일치 개수와 보너스 일치 여부로 등수 결정 + - [x] 3개 미만 일치 시 MISS 반환 + - [x] 3개 일치 시 FIFTH (5,000원) + - [x] 4개 일치 시 FOURTH (50,000원) + - [x] 5개 일치 시 THIRD (1,500,000원) + - [x] 5개 일치 + 보너스 일치 시 SECOND (30,000,000원) + - [x] 6개 일치 시 FIRST (2,000,000,000원) + - [x] 등수별 총 상금 계산 + - [x] 일치 개수 출력용 문자열 반환 + - [x] 상금 출력용 문자열 반환 + +- [x] 로또 결과 (LottoResult) + - [x] 빈 상태로 생성 + - [x] 등수 추가 + - [x] 총 상금 계산 + - [x] 등수별 결과 출력용 문자열 반환 + +- [x] 수익률 (ReturnRate) + - [x] 구매금액과 총 상금으로 생성 + - [x] 수익률 0 미만일 시 예외 발생 + - [x] 수익률 출력용 문자열 반환 + +### 유틸리티 +- [x] 자동 로또 생성기 (AutoBasedLottoGenerator) + - [x] 1~45 범위의 번호 풀 보유 + - [x] 지정 개수만큼 로또 생성 + - [x] 셔플 방식으로 6개 번호 선택 + +- [x] 로또 번호 파서 (LottoNumberParser) + - [x] 쉼표 구분 문자열을 로또 번호 목록으로 변환 \ No newline at end of file From dee80ed7fb6048fe02846e4c08abfa8acea0adab Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Wed, 3 Dec 2025 22:47:06 +0900 Subject: [PATCH 02/26] =?UTF-8?q?feat:=20=EC=88=98=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=20=EC=83=9D=EC=84=B1=EA=B8=B0=20=EB=B0=8F=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ManualBasedLottoGenerator.java - 문자열 입력을 받아 로또 번호 파싱 후 Lotto 생성하도록 수동 로또 생성기 구현 - 기본 생성자에서 LottoNumberParser 주입 방식 제공 ManualBasedLottoGeneratorTest.java - 문자열 목록 입력 시 올바른 Lotto 리스트가 생성되는지 검증 테스트 추가 --- .../utils/ManualBasedLottoGenerator.java | 21 +++++++++++++++++++ .../utils/ManualBasedLottoGeneratorTest.java | 19 +++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/main/java/lotto/utils/ManualBasedLottoGenerator.java create mode 100644 src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java diff --git a/src/main/java/lotto/utils/ManualBasedLottoGenerator.java b/src/main/java/lotto/utils/ManualBasedLottoGenerator.java new file mode 100644 index 0000000000..11ecf89620 --- /dev/null +++ b/src/main/java/lotto/utils/ManualBasedLottoGenerator.java @@ -0,0 +1,21 @@ +package lotto.utils; + +import java.util.List; +import lotto.domain.Lotto; + +public class ManualBasedLottoGenerator { + + private final LottoNumberParser parser; + + public ManualBasedLottoGenerator() { + this(new LottoNumberParser()); + } + + private ManualBasedLottoGenerator(LottoNumberParser parser) { + this.parser = parser; + } + + public List generate(List inputs) { + return inputs.stream().map(parser::parse).map(Lotto::new).toList(); + } +} diff --git a/src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java b/src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java new file mode 100644 index 0000000000..f60e8e2719 --- /dev/null +++ b/src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java @@ -0,0 +1,19 @@ +package lotto.utils; + +import static org.assertj.core.api.Assertions.*; + +import java.util.List; +import lotto.domain.Lotto; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; + +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +class ManualBasedLottoGeneratorTest { + + @Test + void generate_문자열목록_생성() { + assertThat(new ManualBasedLottoGenerator().generate(List.of("1, 2, 3, 4, 5, 6", "7, 8, 9, 10, 11, 12"))) + .isEqualTo(List.of(new Lotto(1, 2, 3, 4, 5, 6), new Lotto(7, 8, 9, 10, 11, 12))); + } +} From 05ceaac05584a58b88ea24629a1288236a12fd1c Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Wed, 3 Dec 2025 22:47:49 +0900 Subject: [PATCH 03/26] =?UTF-8?q?docs:=20=EC=88=98=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=20=EC=83=9D=EC=84=B1=EA=B8=B0=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EB=AC=B8=EC=84=9C=EC=97=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 04-lotto-manual.md - 수동 로또 생성기(ManualBasedLottoGenerator) 기능 요구사항 항목 추가 - 문자열 목록을 기반으로 로또 목록을 생성하는 기능 명시 --- docs/04-lotto-manual.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/04-lotto-manual.md b/docs/04-lotto-manual.md index 1222ceff03..ddcff68fbc 100644 --- a/docs/04-lotto-manual.md +++ b/docs/04-lotto-manual.md @@ -113,6 +113,8 @@ - [x] 1~45 범위의 번호 풀 보유 - [x] 지정 개수만큼 로또 생성 - [x] 셔플 방식으로 6개 번호 선택 +- [x] 수동 로또 생성기 (ManualBasedLottoGenerator) + - [x] 문자열 목록을 입력받아 로또 목록 생성 - [x] 로또 번호 파서 (LottoNumberParser) - [x] 쉼표 구분 문자열을 로또 번호 목록으로 변환 \ No newline at end of file From eda4de9fbd2831df14add1a4ef7ac5a397fdb296 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Wed, 3 Dec 2025 23:13:38 +0900 Subject: [PATCH 04/26] =?UTF-8?q?feat:=20=EC=88=98=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=20=EA=B5=AC=EB=A7=A4=20=EA=B0=9C=EC=88=98=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ManualLottoCount.java - 문자열 입력을 정수로 변환하여 수동 구매 개수 생성 - null·빈값 입력 시 예외 발생 처리 ManualLottoCountTest.java - 정상 숫자 입력 시 생성 성공 테스트 - null·빈 문자열 입력 시 예외 발생 여부 검증 --- .../java/lotto/domain/ManualLottoCount.java | 16 +++++++++++ .../lotto/domain/ManualLottoCountTest.java | 28 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/main/java/lotto/domain/ManualLottoCount.java create mode 100644 src/test/java/lotto/domain/ManualLottoCountTest.java diff --git a/src/main/java/lotto/domain/ManualLottoCount.java b/src/main/java/lotto/domain/ManualLottoCount.java new file mode 100644 index 0000000000..ec901cfdf8 --- /dev/null +++ b/src/main/java/lotto/domain/ManualLottoCount.java @@ -0,0 +1,16 @@ +package lotto.domain; + +public record ManualLottoCount(int value) { + + public ManualLottoCount(String input) { + this(toInt(input)); + } + + private static int toInt(String input) { + if (input == null || input.isBlank()) { + throw new IllegalArgumentException("수동 구매 개수는 필수입니다."); + } + + return Integer.parseInt(input); + } +} diff --git a/src/test/java/lotto/domain/ManualLottoCountTest.java b/src/test/java/lotto/domain/ManualLottoCountTest.java new file mode 100644 index 0000000000..16492fce95 --- /dev/null +++ b/src/test/java/lotto/domain/ManualLottoCountTest.java @@ -0,0 +1,28 @@ +package lotto.domain; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; + +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +class ManualLottoCountTest { + + @ParameterizedTest(name = "입력값:{0}") + @ValueSource(ints = {0, 5}) + void 생성자_문자열_생성성공(int input) { + assertThatCode(() -> new ManualLottoCount(input)).doesNotThrowAnyException(); + } + + @ParameterizedTest(name = "빈값:{0}") + @NullAndEmptySource + @ValueSource(strings = " ") + void 생성자_빈문자열_예외발생(String input) { + assertThatThrownBy(() -> new ManualLottoCount(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("수동 구매 개수는 필수입니다."); + } +} From 7b4716c4d78621a8b455744ff7815581d7051dc5 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Wed, 3 Dec 2025 23:14:58 +0900 Subject: [PATCH 05/26] =?UTF-8?q?feat:=20=EC=88=98=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=20=EA=B0=9C=EC=88=98=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B0=95=ED=99=94=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ManualLottoCount.java - 생성자 블록에서 음수 값 검증 로직 추가 - 음수 입력 시 "수동 구매 개수는 0 이상이어야 합니다." 예외 발생 ManualLottoCountTest.java - 음수 입력 시 예외 발생 여부 검증 테스트 추가 --- src/main/java/lotto/domain/ManualLottoCount.java | 10 ++++++++++ src/test/java/lotto/domain/ManualLottoCountTest.java | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/main/java/lotto/domain/ManualLottoCount.java b/src/main/java/lotto/domain/ManualLottoCount.java index ec901cfdf8..1f30f9c765 100644 --- a/src/main/java/lotto/domain/ManualLottoCount.java +++ b/src/main/java/lotto/domain/ManualLottoCount.java @@ -13,4 +13,14 @@ private static int toInt(String input) { return Integer.parseInt(input); } + + public ManualLottoCount { + validateNonNegative(value); + } + + private static void validateNonNegative(int input) { + if (input < 0) { + throw new IllegalArgumentException("수동 구매 개수는 0 이상이어야 합니다."); + } + } } diff --git a/src/test/java/lotto/domain/ManualLottoCountTest.java b/src/test/java/lotto/domain/ManualLottoCountTest.java index 16492fce95..1b9e7fb728 100644 --- a/src/test/java/lotto/domain/ManualLottoCountTest.java +++ b/src/test/java/lotto/domain/ManualLottoCountTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; @@ -25,4 +26,11 @@ class ManualLottoCountTest { .isInstanceOf(IllegalArgumentException.class) .hasMessage("수동 구매 개수는 필수입니다."); } + + @Test + void 생성자_음수문자열_예외발생() { + assertThatThrownBy(() -> new ManualLottoCount(-1)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("수동 구매 개수는 0 이상이어야 합니다."); + } } From 07c96730f3c00233b94c465eded69d4e358bd179 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Wed, 3 Dec 2025 23:17:24 +0900 Subject: [PATCH 06/26] =?UTF-8?q?docs:=20=EC=88=98=EB=8F=99=20=EA=B5=AC?= =?UTF-8?q?=EB=A7=A4=20=EA=B0=9C=EC=88=98=20=EA=B8=B0=EB=8A=A5=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 04-lotto-manual.md - ManualLottoCount 요구사항 항목 추가 - 0 이상 정수 생성 조건 명시 - 문자열 생성 지원 명시 - 빈 문자열 및 음수 입력 시 예외 발생 명시 --- docs/04-lotto-manual.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/04-lotto-manual.md b/docs/04-lotto-manual.md index ddcff68fbc..c2a8d72c31 100644 --- a/docs/04-lotto-manual.md +++ b/docs/04-lotto-manual.md @@ -65,6 +65,12 @@ - [x] 1개 이상의 정수로 생성 - [x] 1개 미만일 시 예외 발생 +- [x] 수동 구매 개수 (ManualLottoCount) + - [x] 0 이상의 정수로 생성 + - [x] 문자열 입력으로 생성 + - [x] 빈 문자열일 시 예외 발생 + - [x] 음수일 시 예외 발생 + - [x] 로또 구매 금액 (LottoPurchaseAmount) - [x] 금액으로 생성 - [x] 문자열 입력으로 생성 From 5000c32a19072c0c8a78965f7f98db1e3f2fde81 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Wed, 3 Dec 2025 23:58:57 +0900 Subject: [PATCH 07/26] =?UTF-8?q?refactor:=20LottoCount=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EA=B2=80=EC=A6=9D=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F?= =?UTF-8?q?=20=EB=AC=B8=EC=9E=90=EC=97=B4=20=EC=83=9D=EC=84=B1=EC=9E=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LottoCount.java - 문자열 기반 생성자 추가 및 빈 문자열 검증 로직 도입 - 최소값 기준을 1 → 0 이상으로 변경 - 음수 입력 시 예외 메시지 "구매 개수는 0이상이어야 합니다."로 통일 LottoCountTest.java - 정상 생성 가능 범위를 0 이상으로 확장한 테스트 추가 - 문자열 입력 시 빈값 예외 발생 테스트 추가 - 음수 입력 시 예외 검증으로 테스트 수정 --- src/main/java/lotto/domain/LottoCount.java | 16 +++++++++--- .../java/lotto/domain/LottoCountTest.java | 25 ++++++++++++++----- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/main/java/lotto/domain/LottoCount.java b/src/main/java/lotto/domain/LottoCount.java index cd6c2b444e..91eac0e3fd 100644 --- a/src/main/java/lotto/domain/LottoCount.java +++ b/src/main/java/lotto/domain/LottoCount.java @@ -1,11 +1,21 @@ package lotto.domain; public record LottoCount(int value) { - private static final int MIN_COUNT = 1; + + public LottoCount(String input) { + this(toInt(input)); + } + + private static int toInt(String input) { + if (input == null || input.isBlank()) { + throw new IllegalArgumentException("구매 개수는 필수입니다."); + } + return Integer.parseInt(input); + } public LottoCount { - if (value < MIN_COUNT) { - throw new IllegalArgumentException("로또 구매 개수는 %d개 이상이어야 합니다.".formatted(MIN_COUNT)); + if (value < 0) { + throw new IllegalArgumentException("구매 개수는 0이상이어야 합니다."); } } } diff --git a/src/test/java/lotto/domain/LottoCountTest.java b/src/test/java/lotto/domain/LottoCountTest.java index 3454ca0b29..114efec06e 100644 --- a/src/test/java/lotto/domain/LottoCountTest.java +++ b/src/test/java/lotto/domain/LottoCountTest.java @@ -5,19 +5,32 @@ import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) class LottoCountTest { - @Test - void 생성자_정상값_생성성공() { - assertThatCode(() -> new LottoCount(1)).doesNotThrowAnyException(); + @ParameterizedTest(name = "입력값:{0}") + @ValueSource(ints = {0, 5}) + void 생성자_정상값_생성성공(int input) { + assertThatCode(() -> new LottoCount(input)).doesNotThrowAnyException(); + } + + @ParameterizedTest(name = "빈값:{0}") + @NullAndEmptySource + @ValueSource(strings = {" "}) + void 생성자_빈문자열_예외발생(String input) { + assertThatThrownBy(() -> new LottoCount(input)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("구매 개수는 필수입니다."); } @Test - void 생성자_1미만입력_예외발생() { - assertThatThrownBy(() -> new LottoCount(0)) + void 생성자_음수입력_예외발생() { + assertThatThrownBy(() -> new LottoCount(-1)) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("로또 구매 개수는 1개 이상이어야 합니다."); + .hasMessage("구매 개수는 0이상이어야 합니다."); } } From 0e54ee821064103cf14053508efb9d6099038cd6 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 00:02:30 +0900 Subject: [PATCH 08/26] =?UTF-8?q?refactor:=20LottoCount=20=EC=B0=A8?= =?UTF-8?q?=EA=B0=90=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LottoCount.java - subtract 메서드 추가하여 다른 LottoCount와의 차감 기능 제공 LottoCountTest.java - subtract 호출 시 정상적으로 값이 감소하는지 검증 테스트 추가 --- src/main/java/lotto/domain/LottoCount.java | 4 ++++ src/test/java/lotto/domain/LottoCountTest.java | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/lotto/domain/LottoCount.java b/src/main/java/lotto/domain/LottoCount.java index 91eac0e3fd..6a0c471a98 100644 --- a/src/main/java/lotto/domain/LottoCount.java +++ b/src/main/java/lotto/domain/LottoCount.java @@ -18,4 +18,8 @@ private static int toInt(String input) { throw new IllegalArgumentException("구매 개수는 0이상이어야 합니다."); } } + + public LottoCount subtract(LottoCount lottoCount) { + return new LottoCount(this.value - lottoCount.value); + } } diff --git a/src/test/java/lotto/domain/LottoCountTest.java b/src/test/java/lotto/domain/LottoCountTest.java index 114efec06e..0d20435a06 100644 --- a/src/test/java/lotto/domain/LottoCountTest.java +++ b/src/test/java/lotto/domain/LottoCountTest.java @@ -33,4 +33,9 @@ class LottoCountTest { .isInstanceOf(IllegalArgumentException.class) .hasMessage("구매 개수는 0이상이어야 합니다."); } + + @Test + void subtract_정상값_차감() { + assertThat(new LottoCount(10).subtract(new LottoCount(3))).isEqualTo(new LottoCount(7)); + } } From 055de052ce44bf9cf938560a61c4ff0ce97fb313 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 00:06:12 +0900 Subject: [PATCH 09/26] =?UTF-8?q?refactor:=20ManualLottoCount=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ManualLottoCount.java - 수동 구매 개수 도메인 클래스 삭제 ManualLottoCountTest.java - 관련 테스트 코드 전체 삭제 --- .../java/lotto/domain/ManualLottoCount.java | 26 -------------- .../lotto/domain/ManualLottoCountTest.java | 36 ------------------- 2 files changed, 62 deletions(-) delete mode 100644 src/main/java/lotto/domain/ManualLottoCount.java delete mode 100644 src/test/java/lotto/domain/ManualLottoCountTest.java diff --git a/src/main/java/lotto/domain/ManualLottoCount.java b/src/main/java/lotto/domain/ManualLottoCount.java deleted file mode 100644 index 1f30f9c765..0000000000 --- a/src/main/java/lotto/domain/ManualLottoCount.java +++ /dev/null @@ -1,26 +0,0 @@ -package lotto.domain; - -public record ManualLottoCount(int value) { - - public ManualLottoCount(String input) { - this(toInt(input)); - } - - private static int toInt(String input) { - if (input == null || input.isBlank()) { - throw new IllegalArgumentException("수동 구매 개수는 필수입니다."); - } - - return Integer.parseInt(input); - } - - public ManualLottoCount { - validateNonNegative(value); - } - - private static void validateNonNegative(int input) { - if (input < 0) { - throw new IllegalArgumentException("수동 구매 개수는 0 이상이어야 합니다."); - } - } -} diff --git a/src/test/java/lotto/domain/ManualLottoCountTest.java b/src/test/java/lotto/domain/ManualLottoCountTest.java deleted file mode 100644 index 1b9e7fb728..0000000000 --- a/src/test/java/lotto/domain/ManualLottoCountTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package lotto.domain; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.jupiter.api.DisplayNameGeneration; -import org.junit.jupiter.api.DisplayNameGenerator; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.NullAndEmptySource; -import org.junit.jupiter.params.provider.ValueSource; - -@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) -class ManualLottoCountTest { - - @ParameterizedTest(name = "입력값:{0}") - @ValueSource(ints = {0, 5}) - void 생성자_문자열_생성성공(int input) { - assertThatCode(() -> new ManualLottoCount(input)).doesNotThrowAnyException(); - } - - @ParameterizedTest(name = "빈값:{0}") - @NullAndEmptySource - @ValueSource(strings = " ") - void 생성자_빈문자열_예외발생(String input) { - assertThatThrownBy(() -> new ManualLottoCount(input)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("수동 구매 개수는 필수입니다."); - } - - @Test - void 생성자_음수문자열_예외발생() { - assertThatThrownBy(() -> new ManualLottoCount(-1)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("수동 구매 개수는 0 이상이어야 합니다."); - } -} From 2bd391de83a6f68c72fc960c81a12625c462f313 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 00:12:10 +0900 Subject: [PATCH 10/26] =?UTF-8?q?feat:=20=EC=88=98=EB=8F=99=20=EB=A1=9C?= =?UTF-8?q?=EB=98=90=20=EA=B5=AC=EB=A7=A4=20=ED=9D=90=EB=A6=84=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20=EC=9E=85=EC=B6=9C=EB=A0=A5=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=ED=99=95=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Application.java - 전체 구매 수에서 수동/자동 개수 분리 로직 추가 - 수동 번호 입력 및 로또 생성 기능 연동 - 자동/수동 로또 병합 처리 메서드 추가 - 구매 개수 출력 방식 변경(수동/자동 구분 출력) InputView.java - 수동 구매 개수 입력 메서드 추가 - 수동 번호 리스트 입력 메서드 추가 ResultView.java - 구매 개수 출력 형식을 변경하여 수동/자동 개수 명시 --- src/main/java/lotto/Application.java | 35 +++++++++++++++++++++--- src/main/java/lotto/view/InputView.java | 14 ++++++++++ src/main/java/lotto/view/ResultView.java | 4 +-- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index da7c70e75a..ac67c3983f 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,18 +1,19 @@ package lotto; +import java.util.ArrayList; import java.util.List; import lotto.domain.*; import lotto.utils.AutoBasedLottoGenerator; import lotto.utils.LottoNumberParser; +import lotto.utils.ManualBasedLottoGenerator; import lotto.view.InputView; import lotto.view.ResultView; public class Application { public static void main(String[] args) { LottoPurchaseAmount purchaseAmount = getPurchaseAmount(); - PurchasedLottos purchased = new PurchasedLottos(generateLottos(purchaseAmount)); + PurchasedLottos purchased = purchaseLottos(purchaseAmount); - ResultView.printPurchaseCount(purchased); ResultView.printPurchasedLottos(purchased); LottoResult result = purchased.result(getWinningLotto()); @@ -24,8 +25,34 @@ private static LottoPurchaseAmount getPurchaseAmount() { return new LottoPurchaseAmount(InputView.readPurchaseAmount()); } - private static List generateLottos(LottoPurchaseAmount purchaseAmount) { - return new AutoBasedLottoGenerator().generate(purchaseAmount.lottoCount()); + private static PurchasedLottos purchaseLottos(LottoPurchaseAmount purchaseAmount) { + LottoCount totalCount = purchaseAmount.lottoCount(); + + LottoCount manualCount = new LottoCount(InputView.readManualLottoCount()); + List manualLottos = generateManualLottos(manualCount); + + LottoCount autoCount = totalCount.subtract(manualCount); + List autoLottos = generateAutoLottos(autoCount); + + ResultView.printPurchaseCount(manualCount, autoCount); + + return mergeLottos(manualLottos, autoLottos); + } + + private static List generateManualLottos(LottoCount manualCount) { + List manualInputs = InputView.readManualLottoNumbers(manualCount.value()); + List manualLottos = new ManualBasedLottoGenerator().generate(manualInputs); + return manualLottos; + } + + private static List generateAutoLottos(LottoCount autoCount) { + return new AutoBasedLottoGenerator().generate(autoCount); + } + + private static PurchasedLottos mergeLottos(List manual, List auto) { + List all = new ArrayList<>(manual); + all.addAll(auto); + return new PurchasedLottos(all); } private static WinningLotto getWinningLotto() { diff --git a/src/main/java/lotto/view/InputView.java b/src/main/java/lotto/view/InputView.java index 6a1b581352..2af7bdc8bb 100644 --- a/src/main/java/lotto/view/InputView.java +++ b/src/main/java/lotto/view/InputView.java @@ -1,6 +1,8 @@ package lotto.view; +import java.util.List; import java.util.Scanner; +import java.util.stream.IntStream; public class InputView { private static final Scanner scanner = new Scanner(System.in); @@ -11,6 +13,18 @@ public static String readPurchaseAmount() { return scanner.nextLine(); } + public static String readManualLottoCount() { + System.out.println("수동으로 구매할 로또 수를 입력해 주세요."); + + return scanner.nextLine(); + } + + public static List readManualLottoNumbers(int count) { + System.out.println("수동으로 구매할 번호를 입력해 주세요."); + + return IntStream.range(0, count).mapToObj(i -> scanner.nextLine()).toList(); + } + public static String readWinningNumbers() { System.out.println("지난 주 당첨 번호를 입력해 주세요."); diff --git a/src/main/java/lotto/view/ResultView.java b/src/main/java/lotto/view/ResultView.java index bd6c06e391..c843c82414 100644 --- a/src/main/java/lotto/view/ResultView.java +++ b/src/main/java/lotto/view/ResultView.java @@ -4,8 +4,8 @@ public class ResultView { - public static void printPurchaseCount(PurchasedLottos purchased) { - System.out.println(purchased.purchaseCountForDisplay()); + public static void printPurchaseCount(LottoCount manualCount, LottoCount auto) { + System.out.printf("수동으로 %d장, 자동으로 %d개를 구매했습니다.%n", manualCount.value(), auto.value()); } public static void printPurchasedLottos(PurchasedLottos purchased) { From d9c80e730c7b519c62c8b9e509b6836572ecfa2d Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 00:13:28 +0900 Subject: [PATCH 11/26] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EA=B5=AC=EB=A7=A4=20=EA=B0=9C=EC=88=98=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PurchasedLottos.java - purchaseCountForDisplay 및 size 관련 메서드 제거 (구매 수 출력 책임을 ResultView로 완전 이관) PurchasedLottosTest.java - purchaseCountForDisplay 검증 테스트 삭제 --- src/main/java/lotto/domain/PurchasedLottos.java | 8 -------- src/test/java/lotto/domain/PurchasedLottosTest.java | 7 ------- 2 files changed, 15 deletions(-) diff --git a/src/main/java/lotto/domain/PurchasedLottos.java b/src/main/java/lotto/domain/PurchasedLottos.java index 5c6a176950..250247c2b2 100644 --- a/src/main/java/lotto/domain/PurchasedLottos.java +++ b/src/main/java/lotto/domain/PurchasedLottos.java @@ -27,12 +27,4 @@ public LottoResult result(WinningLotto winningLotto) { return result; } - - public String purchaseCountForDisplay() { - return "%d개를 구매했습니다.".formatted(size()); - } - - private int size() { - return values.size(); - } } diff --git a/src/test/java/lotto/domain/PurchasedLottosTest.java b/src/test/java/lotto/domain/PurchasedLottosTest.java index 688a67a292..a1f7b9ec8b 100644 --- a/src/test/java/lotto/domain/PurchasedLottosTest.java +++ b/src/test/java/lotto/domain/PurchasedLottosTest.java @@ -24,11 +24,4 @@ class PurchasedLottosTest { .isInstanceOf(IllegalArgumentException.class) .hasMessage("구매한 로또는 1개 이상이어야 합니다."); } - - @Test - void purchaseCountForDisplay_구매개수_표시() { - PurchasedLottos purchased = new PurchasedLottos(new Lotto(1, 2, 3, 4, 5, 6)); - - assertThat(purchased.purchaseCountForDisplay()).isEqualTo("1개를 구매했습니다."); - } } From a67115dac1f520c9489529501a8efdf4ac5b1fc4 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 07:07:26 +0900 Subject: [PATCH 12/26] =?UTF-8?q?refactor:=20LottoCount=20=EC=B0=A8?= =?UTF-8?q?=EA=B0=90=20=EA=B2=80=EC=A6=9D=20=EA=B0=95=ED=99=94=20=EB=B0=8F?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=99=95=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LottoCount.java - subtract 호출 시 차감 가능 여부 검증 추가 - isLessThan 기반의 validateSubtractable 메서드 도입 - 차감 불가 시 "차감할 수 없습니다." 예외 발생하도록 수정 LottoCountTest.java - subtract 정상/동일 값 케이스에 대한 CSV 기반 테스트 추가 - subtract 시 초과 차감 예외 테스트 추가 - validateSubtractable 정상/예외 케이스 테스트 추가 --- src/main/java/lotto/domain/LottoCount.java | 15 +++++++++-- .../java/lotto/domain/LottoCountTest.java | 27 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/main/java/lotto/domain/LottoCount.java b/src/main/java/lotto/domain/LottoCount.java index 6a0c471a98..18e9e03d6a 100644 --- a/src/main/java/lotto/domain/LottoCount.java +++ b/src/main/java/lotto/domain/LottoCount.java @@ -19,7 +19,18 @@ private static int toInt(String input) { } } - public LottoCount subtract(LottoCount lottoCount) { - return new LottoCount(this.value - lottoCount.value); + public LottoCount subtract(LottoCount other) { + validateSubtractable(other); + return new LottoCount(this.value - other.value); + } + + public void validateSubtractable(LottoCount other) { + if (isLessThan(other)) { + throw new IllegalArgumentException("차감할 수 없습니다."); + } + } + + private boolean isLessThan(LottoCount other) { + return this.value < other.value; } } diff --git a/src/test/java/lotto/domain/LottoCountTest.java b/src/test/java/lotto/domain/LottoCountTest.java index 0d20435a06..da97fd7e85 100644 --- a/src/test/java/lotto/domain/LottoCountTest.java +++ b/src/test/java/lotto/domain/LottoCountTest.java @@ -6,6 +6,7 @@ import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; @@ -34,8 +35,30 @@ class LottoCountTest { .hasMessage("구매 개수는 0이상이어야 합니다."); } + @ParameterizedTest(name = "원본:{0} - 차감:{1} = 결과:{2}") + @CsvSource({"10, 3, 7", "5, 5, 0"}) + void subtract_정상값_차감(int original, int subtrahend, int expected) { + assertThat(new LottoCount(original).subtract(new LottoCount(subtrahend))) + .isEqualTo(new LottoCount(expected)); + } + + @Test + void subtract_초과값_예외발생() { + assertThatThrownBy(() -> new LottoCount(3).subtract(new LottoCount(5))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("차감할 수 없습니다."); + } + @Test - void subtract_정상값_차감() { - assertThat(new LottoCount(10).subtract(new LottoCount(3))).isEqualTo(new LottoCount(7)); + void validateSubtractable_정상값_예외없음() { + assertThatCode(() -> new LottoCount(10).validateSubtractable(new LottoCount(5))) + .doesNotThrowAnyException(); + } + + @Test + void validateSubtractable_초과값_예외발생() { + assertThatThrownBy(() -> new LottoCount(3).validateSubtractable(new LottoCount(5))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("차감할 수 없습니다."); } } From 75c9e324ef40cb854280bc16ad88ab82a254b864 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 07:10:52 +0900 Subject: [PATCH 13/26] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=20=EC=8B=9C=20=EC=9E=AC=EC=9E=85=EB=A0=A5=20=EA=B0=80?= =?UTF-8?q?=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=9E=AC=EC=8B=9C?= =?UTF-8?q?=EB=8F=84=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Application.java - 구매 금액 입력을 `retryUntilSuccess`로 감싸 예외 발생 시 재입력 가능하도록 개선 - 수동 구매 개수 입력 시 총 구매 수 초과 여부 검증 및 재입력 처리 추가 - 수동 로또 생성 단계에도 재시도 로직 적용 - 입력 람다 처리용 `retryUntilSuccess` 유틸 메서드 추가 - manual/auto 입력 분리 메서드(`getManualLottoCount`, `getManualLottoNumbers`) 추가 --- src/main/java/lotto/Application.java | 32 ++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index ac67c3983f..ba207846ce 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.Supplier; import lotto.domain.*; import lotto.utils.AutoBasedLottoGenerator; import lotto.utils.LottoNumberParser; @@ -22,13 +23,12 @@ public static void main(String[] args) { } private static LottoPurchaseAmount getPurchaseAmount() { - return new LottoPurchaseAmount(InputView.readPurchaseAmount()); + return retryUntilSuccess(() -> new LottoPurchaseAmount(InputView.readPurchaseAmount())); } private static PurchasedLottos purchaseLottos(LottoPurchaseAmount purchaseAmount) { LottoCount totalCount = purchaseAmount.lottoCount(); - - LottoCount manualCount = new LottoCount(InputView.readManualLottoCount()); + LottoCount manualCount = getManualLottoCount(totalCount); List manualLottos = generateManualLottos(manualCount); LottoCount autoCount = totalCount.subtract(manualCount); @@ -39,10 +39,20 @@ private static PurchasedLottos purchaseLottos(LottoPurchaseAmount purchaseAmount return mergeLottos(manualLottos, autoLottos); } + private static LottoCount getManualLottoCount(LottoCount totalCount) { + return retryUntilSuccess(() -> { + LottoCount manualCount = new LottoCount(InputView.readManualLottoCount()); + totalCount.validateSubtractable(manualCount); + return manualCount; + }); + } + private static List generateManualLottos(LottoCount manualCount) { - List manualInputs = InputView.readManualLottoNumbers(manualCount.value()); - List manualLottos = new ManualBasedLottoGenerator().generate(manualInputs); - return manualLottos; + return retryUntilSuccess(() -> new ManualBasedLottoGenerator().generate(getManualLottoNumbers(manualCount))); + } + + private static List getManualLottoNumbers(LottoCount manualCount) { + return InputView.readManualLottoNumbers(manualCount.value()); } private static List generateAutoLottos(LottoCount autoCount) { @@ -62,4 +72,14 @@ private static WinningLotto getWinningLotto() { List numbers = new LottoNumberParser().parse(winningNumbers); return new WinningLotto(numbers, bonusNumber); } + + private static T retryUntilSuccess(Supplier action) { + while (true) { + try { + return action.get(); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } } From 2b66fdc8d652232ddae8e59e86a0999094ad1c5e Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 07:25:07 +0900 Subject: [PATCH 14/26] =?UTF-8?q?refactor:=20=EC=9E=85=EB=A0=A5/=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20static=20import=20=EC=A0=81=EC=9A=A9=20=EB=B0=8F=20?= =?UTF-8?q?=EB=B3=B4=EB=84=88=EC=8A=A4=20=EB=B2=88=ED=98=B8=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Application.java - InputView, ResultView 메서드들을 static import로 교체하여 코드 가독성 개선 - 구매 금액/수동 개수/수동 번호/당첨 번호/보너스 번호 입력에 재시도(retry) 로직 적용 - 수동 로또 번호 입력 흐름 간소화 (`getManualLottoNumbers` 제거) - 당첨 번호 파싱 및 보너스 번호 중복 검증 로직(`validateBonusNotDuplicated`) 분리 - WinningLotto 생성 시 LottoNumber를 직접 전달하도록 수정 WinningLotto.java - 생성자 시그니처 변경: 보너스 번호를 String → LottoNumber로 받도록 일원화 --- src/main/java/lotto/Application.java | 46 +++++++++++++------- src/main/java/lotto/domain/WinningLotto.java | 4 +- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index ba207846ce..fa589b71bd 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -1,5 +1,8 @@ package lotto; +import static lotto.view.InputView.*; +import static lotto.view.ResultView.*; + import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; @@ -7,23 +10,21 @@ import lotto.utils.AutoBasedLottoGenerator; import lotto.utils.LottoNumberParser; import lotto.utils.ManualBasedLottoGenerator; -import lotto.view.InputView; -import lotto.view.ResultView; public class Application { public static void main(String[] args) { LottoPurchaseAmount purchaseAmount = getPurchaseAmount(); PurchasedLottos purchased = purchaseLottos(purchaseAmount); - ResultView.printPurchasedLottos(purchased); + printPurchasedLottos(purchased); LottoResult result = purchased.result(getWinningLotto()); - ResultView.printResult(result, purchaseAmount); + printResult(result, purchaseAmount); } private static LottoPurchaseAmount getPurchaseAmount() { - return retryUntilSuccess(() -> new LottoPurchaseAmount(InputView.readPurchaseAmount())); + return retryUntilSuccess(() -> new LottoPurchaseAmount(readPurchaseAmount())); } private static PurchasedLottos purchaseLottos(LottoPurchaseAmount purchaseAmount) { @@ -34,25 +35,22 @@ private static PurchasedLottos purchaseLottos(LottoPurchaseAmount purchaseAmount LottoCount autoCount = totalCount.subtract(manualCount); List autoLottos = generateAutoLottos(autoCount); - ResultView.printPurchaseCount(manualCount, autoCount); + printPurchaseCount(manualCount, autoCount); return mergeLottos(manualLottos, autoLottos); } private static LottoCount getManualLottoCount(LottoCount totalCount) { return retryUntilSuccess(() -> { - LottoCount manualCount = new LottoCount(InputView.readManualLottoCount()); + LottoCount manualCount = new LottoCount(readManualLottoCount()); totalCount.validateSubtractable(manualCount); return manualCount; }); } private static List generateManualLottos(LottoCount manualCount) { - return retryUntilSuccess(() -> new ManualBasedLottoGenerator().generate(getManualLottoNumbers(manualCount))); - } - - private static List getManualLottoNumbers(LottoCount manualCount) { - return InputView.readManualLottoNumbers(manualCount.value()); + return retryUntilSuccess( + () -> new ManualBasedLottoGenerator().generate(readManualLottoNumbers(manualCount.value()))); } private static List generateAutoLottos(LottoCount autoCount) { @@ -66,11 +64,27 @@ private static PurchasedLottos mergeLottos(List manual, List auto) } private static WinningLotto getWinningLotto() { - String winningNumbers = InputView.readWinningNumbers(); - String bonusNumber = InputView.readBonusNumber(); + List numbers = getWinningNumbers(); + LottoNumber bonus = getBonusNumber(numbers); + return new WinningLotto(numbers, bonus); + } + + private static List getWinningNumbers() { + return retryUntilSuccess(() -> new LottoNumberParser().parse(readWinningNumbers())); + } - List numbers = new LottoNumberParser().parse(winningNumbers); - return new WinningLotto(numbers, bonusNumber); + private static LottoNumber getBonusNumber(List winningNumbers) { + return retryUntilSuccess(() -> { + LottoNumber bonus = LottoNumber.of(readBonusNumber()); + validateBonusNotDuplicated(winningNumbers, bonus); + return bonus; + }); + } + + private static void validateBonusNotDuplicated(List numbers, LottoNumber bonus) { + if (numbers.contains(bonus)) { + throw new IllegalArgumentException("보너스 번호는 당첨 번호와 중복될 수 없습니다."); + } } private static T retryUntilSuccess(Supplier action) { diff --git a/src/main/java/lotto/domain/WinningLotto.java b/src/main/java/lotto/domain/WinningLotto.java index 475b815747..ebd3ac8e55 100644 --- a/src/main/java/lotto/domain/WinningLotto.java +++ b/src/main/java/lotto/domain/WinningLotto.java @@ -4,8 +4,8 @@ public record WinningLotto(Lotto lotto, LottoNumber bonus) { - public WinningLotto(List numbers, String bonus) { - this(new Lotto(numbers), LottoNumber.of(bonus)); + public WinningLotto(List numbers, LottoNumber bonus) { + this(new Lotto(numbers), bonus); } public WinningLotto(Lotto lotto, int bonus) { From acfae395fb763c5ca57303b18c801a752b352c69 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 07:39:21 +0900 Subject: [PATCH 15/26] =?UTF-8?q?refactor:=20=EB=8B=B9=EC=B2=A8=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EC=83=9D=EC=84=B1=20=ED=9D=90=EB=A6=84=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20=EC=A4=91=EB=B3=B5=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EB=8B=A8=EC=88=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Application.java - WinningLotto 생성 과정 분리: `generateWinningLotto` 메서드 추가 - 당첨 번호 파싱 후 바로 Lotto 객체로 생성 - 보너스 번호 검증 시 `Lotto`의 contains 사용하도록 개선 - 기존 List 기반 검증 로직을 Lotto 기반으로 단순화 --- src/main/java/lotto/Application.java | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index fa589b71bd..9c5b76f2aa 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -64,25 +64,29 @@ private static PurchasedLottos mergeLottos(List manual, List auto) } private static WinningLotto getWinningLotto() { - List numbers = getWinningNumbers(); - LottoNumber bonus = getBonusNumber(numbers); - return new WinningLotto(numbers, bonus); + Lotto lotto = generateWinningLotto(); + LottoNumber bonus = getBonusNumber(lotto); + return new WinningLotto(lotto, bonus); + } + + private static Lotto generateWinningLotto() { + return retryUntilSuccess(() -> new Lotto(getWinningNumbers())); } private static List getWinningNumbers() { - return retryUntilSuccess(() -> new LottoNumberParser().parse(readWinningNumbers())); + return new LottoNumberParser().parse(readWinningNumbers()); } - private static LottoNumber getBonusNumber(List winningNumbers) { + private static LottoNumber getBonusNumber(Lotto lotto) { return retryUntilSuccess(() -> { LottoNumber bonus = LottoNumber.of(readBonusNumber()); - validateBonusNotDuplicated(winningNumbers, bonus); + validateBonusNotDuplicated(lotto, bonus); return bonus; }); } - private static void validateBonusNotDuplicated(List numbers, LottoNumber bonus) { - if (numbers.contains(bonus)) { + private static void validateBonusNotDuplicated(Lotto lotto, LottoNumber bonus) { + if (lotto.contains(bonus)) { throw new IllegalArgumentException("보너스 번호는 당첨 번호와 중복될 수 없습니다."); } } From dee1310ca40552a91b02b084adc18eb30f689f6d Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 07:49:21 +0900 Subject: [PATCH 16/26] =?UTF-8?q?refactor:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=A0=95=EB=A6=AC=20=EB=B0=8F?= =?UTF-8?q?=20=EB=8B=B9=EC=B2=A8=20=EB=A1=9C=EB=98=90=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=ED=9D=90=EB=A6=84=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Application.java - 입력/생성 메서드 네이밍을 create* 스타일로 통일하여 책임 명확화 - 구매 로또 생성 흐름을 createManualLottos, generateAutoLottos로 단순화 - 당첨 번호 생성 흐름을 createLottoForWinning, createBonusNumber로 개선 - 전체적으로 불필요한 임시 변수 제거 및 호출 구조 간결화 --- src/main/java/lotto/Application.java | 31 +++++++++++++--------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index 9c5b76f2aa..bcc923e8a4 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -13,34 +13,31 @@ public class Application { public static void main(String[] args) { - LottoPurchaseAmount purchaseAmount = getPurchaseAmount(); + LottoPurchaseAmount purchaseAmount = createPurchaseAmount(); PurchasedLottos purchased = purchaseLottos(purchaseAmount); printPurchasedLottos(purchased); - LottoResult result = purchased.result(getWinningLotto()); + LottoResult result = purchased.result(createWinningLotto()); printResult(result, purchaseAmount); } - private static LottoPurchaseAmount getPurchaseAmount() { + private static LottoPurchaseAmount createPurchaseAmount() { return retryUntilSuccess(() -> new LottoPurchaseAmount(readPurchaseAmount())); } private static PurchasedLottos purchaseLottos(LottoPurchaseAmount purchaseAmount) { LottoCount totalCount = purchaseAmount.lottoCount(); - LottoCount manualCount = getManualLottoCount(totalCount); - List manualLottos = generateManualLottos(manualCount); - + LottoCount manualCount = createManualLottoCount(totalCount); LottoCount autoCount = totalCount.subtract(manualCount); - List autoLottos = generateAutoLottos(autoCount); printPurchaseCount(manualCount, autoCount); - return mergeLottos(manualLottos, autoLottos); + return mergeLottos(createManualLottos(manualCount), generateAutoLottos(autoCount)); } - private static LottoCount getManualLottoCount(LottoCount totalCount) { + private static LottoCount createManualLottoCount(LottoCount totalCount) { return retryUntilSuccess(() -> { LottoCount manualCount = new LottoCount(readManualLottoCount()); totalCount.validateSubtractable(manualCount); @@ -48,7 +45,7 @@ private static LottoCount getManualLottoCount(LottoCount totalCount) { }); } - private static List generateManualLottos(LottoCount manualCount) { + private static List createManualLottos(LottoCount manualCount) { return retryUntilSuccess( () -> new ManualBasedLottoGenerator().generate(readManualLottoNumbers(manualCount.value()))); } @@ -63,21 +60,21 @@ private static PurchasedLottos mergeLottos(List manual, List auto) return new PurchasedLottos(all); } - private static WinningLotto getWinningLotto() { - Lotto lotto = generateWinningLotto(); - LottoNumber bonus = getBonusNumber(lotto); + private static WinningLotto createWinningLotto() { + Lotto lotto = createLottoForWinning(); + LottoNumber bonus = createBonusNumber(lotto); return new WinningLotto(lotto, bonus); } - private static Lotto generateWinningLotto() { - return retryUntilSuccess(() -> new Lotto(getWinningNumbers())); + private static Lotto createLottoForWinning() { + return retryUntilSuccess(() -> new Lotto(createWinningNumbers())); } - private static List getWinningNumbers() { + private static List createWinningNumbers() { return new LottoNumberParser().parse(readWinningNumbers()); } - private static LottoNumber getBonusNumber(Lotto lotto) { + private static LottoNumber createBonusNumber(Lotto lotto) { return retryUntilSuccess(() -> { LottoNumber bonus = LottoNumber.of(readBonusNumber()); validateBonusNotDuplicated(lotto, bonus); From f73cd13f803f44b87a333e9fc874c118b6349bea Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 07:51:52 +0900 Subject: [PATCH 17/26] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=83=9D=EC=84=B1=EC=9E=90=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WinningLotto.java - List를 입력받는 생성자 제거하여 Lotto 기반 생성 방식으로 일원화 - 기존 int 보너스 번호 생성자는 그대로 유지 --- src/main/java/lotto/domain/WinningLotto.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/lotto/domain/WinningLotto.java b/src/main/java/lotto/domain/WinningLotto.java index ebd3ac8e55..581a273eb3 100644 --- a/src/main/java/lotto/domain/WinningLotto.java +++ b/src/main/java/lotto/domain/WinningLotto.java @@ -1,13 +1,7 @@ package lotto.domain; -import java.util.List; - public record WinningLotto(Lotto lotto, LottoNumber bonus) { - public WinningLotto(List numbers, LottoNumber bonus) { - this(new Lotto(numbers), bonus); - } - public WinningLotto(Lotto lotto, int bonus) { this(lotto, LottoNumber.of(bonus)); } From be9ef0a6ef3eeb50e6dfd4e925afc8dd422df00e Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Thu, 4 Dec 2025 08:09:20 +0900 Subject: [PATCH 18/26] =?UTF-8?q?docs:=20=EB=A1=9C=EB=98=90=20=EC=88=98?= =?UTF-8?q?=EB=8F=99=20=EA=B5=AC=EB=A7=A4=20=EB=B0=8F=20WinningLotto=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=EC=82=AC=ED=95=AD=20=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 04-lotto-manual.md - PR 링크 추가 - LottoCount 요구사항을 0 이상 생성 및 차감 검증 중심으로 업데이트 - ManualLottoCount 제거에 따른 관련 항목 삭제 - PurchasedLottos의 구매 개수 출력 기능 제거 반영 - WinningLotto 생성 방식 변경(로또 + 보너스 번호)으로 요구사항 수정 --- docs/04-lotto-manual.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/docs/04-lotto-manual.md b/docs/04-lotto-manual.md index c2a8d72c31..a1c3403938 100644 --- a/docs/04-lotto-manual.md +++ b/docs/04-lotto-manual.md @@ -2,7 +2,7 @@ *** ## 코드 리뷰 > PR 링크: -> +> **[https://github.com/next-step/java-lotto/pull/4232](https://github.com/next-step/java-lotto/pull/4232)** ## 나의 학습 목표 - TDD 사이클로 구현 - 객체지향 생활 체조 원칙 준수 @@ -62,14 +62,12 @@ ### 로또 구매 - [x] 로또 구매 개수 (LottoCount) - - [x] 1개 이상의 정수로 생성 - - [x] 1개 미만일 시 예외 발생 - -- [x] 수동 구매 개수 (ManualLottoCount) - - [x] 0 이상의 정수로 생성 - - [x] 문자열 입력으로 생성 - - [x] 빈 문자열일 시 예외 발생 - - [x] 음수일 시 예외 발생 + - [x] 0 이상의 정수로 생성 + - [x] 문자열 입력으로 생성 + - [x] 빈 문자열일 시 예외 발생 + - [x] 음수일 시 예외 발생 + - [x] 다른 개수와 차감 연산 + - [x] 차감 결과가 음수일 시 예외 발생 - [x] 로또 구매 금액 (LottoPurchaseAmount) - [x] 금액으로 생성 @@ -83,11 +81,10 @@ - [x] 로또 목록으로 생성 - [x] 빈 목록일 시 예외 발생 - [x] 당첨 로또와 비교하여 결과 생성 - - [x] 구매 개수 출력용 문자열 반환 ### 당첨 판정 - [x] 당첨 로또 (WinningLotto) - - [x] 로또 번호 목록과 보너스 번호로 생성 + - [x] 로또와 보너스 번호로 생성 - [x] 보너스 번호가 당첨 번호와 중복 시 예외 발생 - [x] 구매 로또와 비교하여 등수 판정 From 219cc8b22b0e4ad6d358ab4467371260865ef756 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Fri, 26 Dec 2025 06:16:10 +0900 Subject: [PATCH 19/26] =?UTF-8?q?refactor:=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=ED=8C=8C=EC=8B=B1=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/Application.java | 6 +++--- .../lotto/{utils => domain}/AutoBasedLottoGenerator.java | 5 +---- .../java/lotto/{utils => domain}/LottoNumberParser.java | 3 +-- .../lotto/{utils => domain}/ManualBasedLottoGenerator.java | 3 +-- src/test/java/lotto/utils/AutoBasedLottoGeneratorTest.java | 1 + src/test/java/lotto/utils/LottoNumberParserTest.java | 1 + .../java/lotto/utils/ManualBasedLottoGeneratorTest.java | 1 + 7 files changed, 9 insertions(+), 11 deletions(-) rename src/main/java/lotto/{utils => domain}/AutoBasedLottoGenerator.java (89%) rename src/main/java/lotto/{utils => domain}/LottoNumberParser.java (87%) rename src/main/java/lotto/{utils => domain}/ManualBasedLottoGenerator.java (90%) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index bcc923e8a4..b809625e27 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -7,9 +7,9 @@ import java.util.List; import java.util.function.Supplier; import lotto.domain.*; -import lotto.utils.AutoBasedLottoGenerator; -import lotto.utils.LottoNumberParser; -import lotto.utils.ManualBasedLottoGenerator; +import lotto.domain.AutoBasedLottoGenerator; +import lotto.domain.LottoNumberParser; +import lotto.domain.ManualBasedLottoGenerator; public class Application { public static void main(String[] args) { diff --git a/src/main/java/lotto/utils/AutoBasedLottoGenerator.java b/src/main/java/lotto/domain/AutoBasedLottoGenerator.java similarity index 89% rename from src/main/java/lotto/utils/AutoBasedLottoGenerator.java rename to src/main/java/lotto/domain/AutoBasedLottoGenerator.java index 81f8c0cadb..2cd506f3e9 100644 --- a/src/main/java/lotto/utils/AutoBasedLottoGenerator.java +++ b/src/main/java/lotto/domain/AutoBasedLottoGenerator.java @@ -1,12 +1,9 @@ -package lotto.utils; +package lotto.domain; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.IntStream; -import lotto.domain.Lotto; -import lotto.domain.LottoCount; -import lotto.domain.LottoNumber; public class AutoBasedLottoGenerator { private static final int LOTTO_NUMBER_MIN = 1; diff --git a/src/main/java/lotto/utils/LottoNumberParser.java b/src/main/java/lotto/domain/LottoNumberParser.java similarity index 87% rename from src/main/java/lotto/utils/LottoNumberParser.java rename to src/main/java/lotto/domain/LottoNumberParser.java index 461ffb7ea0..b9c571138a 100644 --- a/src/main/java/lotto/utils/LottoNumberParser.java +++ b/src/main/java/lotto/domain/LottoNumberParser.java @@ -1,8 +1,7 @@ -package lotto.utils; +package lotto.domain; import java.util.Arrays; import java.util.List; -import lotto.domain.LottoNumber; public class LottoNumberParser { private static final String DELIMITER = ","; diff --git a/src/main/java/lotto/utils/ManualBasedLottoGenerator.java b/src/main/java/lotto/domain/ManualBasedLottoGenerator.java similarity index 90% rename from src/main/java/lotto/utils/ManualBasedLottoGenerator.java rename to src/main/java/lotto/domain/ManualBasedLottoGenerator.java index 11ecf89620..ca6d4447f8 100644 --- a/src/main/java/lotto/utils/ManualBasedLottoGenerator.java +++ b/src/main/java/lotto/domain/ManualBasedLottoGenerator.java @@ -1,7 +1,6 @@ -package lotto.utils; +package lotto.domain; import java.util.List; -import lotto.domain.Lotto; public class ManualBasedLottoGenerator { diff --git a/src/test/java/lotto/utils/AutoBasedLottoGeneratorTest.java b/src/test/java/lotto/utils/AutoBasedLottoGeneratorTest.java index 1a6f8e25b9..89700003f7 100644 --- a/src/test/java/lotto/utils/AutoBasedLottoGeneratorTest.java +++ b/src/test/java/lotto/utils/AutoBasedLottoGeneratorTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.*; +import lotto.domain.AutoBasedLottoGenerator; import lotto.domain.LottoCount; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; diff --git a/src/test/java/lotto/utils/LottoNumberParserTest.java b/src/test/java/lotto/utils/LottoNumberParserTest.java index df9cf33823..3686a74d1f 100644 --- a/src/test/java/lotto/utils/LottoNumberParserTest.java +++ b/src/test/java/lotto/utils/LottoNumberParserTest.java @@ -5,6 +5,7 @@ import java.util.Arrays; import java.util.List; import lotto.domain.LottoNumber; +import lotto.domain.LottoNumberParser; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; diff --git a/src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java b/src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java index f60e8e2719..4983cdb7ca 100644 --- a/src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java +++ b/src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java @@ -4,6 +4,7 @@ import java.util.List; import lotto.domain.Lotto; +import lotto.domain.ManualBasedLottoGenerator; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; From 486303a405eb38272ef4e8190d64b8b33271e6d7 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Fri, 26 Dec 2025 06:20:57 +0900 Subject: [PATCH 20/26] =?UTF-8?q?refactor:=20PurchasedLottos=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=AA=85=EC=B9=AD=EC=9D=84=20Lottos?= =?UTF-8?q?=EB=A1=9C=20=EB=8B=A8=EC=88=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Application.java - PurchasedLottos 타입을 Lottos로 변경 - 관련 메서드 반환 타입 및 생성 로직 수정 Lottos.java - PurchasedLottos → Lottos로 클래스명 변경 - 생성자 및 레코드 선언부 명칭 일관성 개선 ResultView.java - 구매 로또 출력 메서드 파라미터 타입을 Lottos로 변경 LottosTest.java - 테스트 클래스 및 테스트 코드에서 Lottos 명칭으로 변경 --- src/main/java/lotto/Application.java | 8 ++++---- .../lotto/domain/{PurchasedLottos.java => Lottos.java} | 6 +++--- src/main/java/lotto/view/ResultView.java | 2 +- .../domain/{PurchasedLottosTest.java => LottosTest.java} | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) rename src/main/java/lotto/domain/{PurchasedLottos.java => Lottos.java} (82%) rename src/test/java/lotto/domain/{PurchasedLottosTest.java => LottosTest.java} (79%) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index b809625e27..5d0f1fcb33 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -14,7 +14,7 @@ public class Application { public static void main(String[] args) { LottoPurchaseAmount purchaseAmount = createPurchaseAmount(); - PurchasedLottos purchased = purchaseLottos(purchaseAmount); + Lottos purchased = purchaseLottos(purchaseAmount); printPurchasedLottos(purchased); @@ -27,7 +27,7 @@ private static LottoPurchaseAmount createPurchaseAmount() { return retryUntilSuccess(() -> new LottoPurchaseAmount(readPurchaseAmount())); } - private static PurchasedLottos purchaseLottos(LottoPurchaseAmount purchaseAmount) { + private static Lottos purchaseLottos(LottoPurchaseAmount purchaseAmount) { LottoCount totalCount = purchaseAmount.lottoCount(); LottoCount manualCount = createManualLottoCount(totalCount); LottoCount autoCount = totalCount.subtract(manualCount); @@ -54,10 +54,10 @@ private static List generateAutoLottos(LottoCount autoCount) { return new AutoBasedLottoGenerator().generate(autoCount); } - private static PurchasedLottos mergeLottos(List manual, List auto) { + private static Lottos mergeLottos(List manual, List auto) { List all = new ArrayList<>(manual); all.addAll(auto); - return new PurchasedLottos(all); + return new Lottos(all); } private static WinningLotto createWinningLotto() { diff --git a/src/main/java/lotto/domain/PurchasedLottos.java b/src/main/java/lotto/domain/Lottos.java similarity index 82% rename from src/main/java/lotto/domain/PurchasedLottos.java rename to src/main/java/lotto/domain/Lottos.java index 250247c2b2..56ee0bb7e1 100644 --- a/src/main/java/lotto/domain/PurchasedLottos.java +++ b/src/main/java/lotto/domain/Lottos.java @@ -2,13 +2,13 @@ import java.util.List; -public record PurchasedLottos(List values) { +public record Lottos(List values) { - public PurchasedLottos(Lotto... inputs) { + public Lottos(Lotto... inputs) { this(List.of(inputs)); } - public PurchasedLottos { + public Lottos { validateNotBlank(values); } diff --git a/src/main/java/lotto/view/ResultView.java b/src/main/java/lotto/view/ResultView.java index c843c82414..21b1ea86b7 100644 --- a/src/main/java/lotto/view/ResultView.java +++ b/src/main/java/lotto/view/ResultView.java @@ -8,7 +8,7 @@ public static void printPurchaseCount(LottoCount manualCount, LottoCount auto) { System.out.printf("수동으로 %d장, 자동으로 %d개를 구매했습니다.%n", manualCount.value(), auto.value()); } - public static void printPurchasedLottos(PurchasedLottos purchased) { + public static void printPurchasedLottos(Lottos purchased) { for (Lotto lottoV2 : purchased.values()) { System.out.println(lottoV2.sortedValuesForDisplay()); } diff --git a/src/test/java/lotto/domain/PurchasedLottosTest.java b/src/test/java/lotto/domain/LottosTest.java similarity index 79% rename from src/test/java/lotto/domain/PurchasedLottosTest.java rename to src/test/java/lotto/domain/LottosTest.java index a1f7b9ec8b..932d2932a6 100644 --- a/src/test/java/lotto/domain/PurchasedLottosTest.java +++ b/src/test/java/lotto/domain/LottosTest.java @@ -10,17 +10,17 @@ import org.junit.jupiter.params.provider.NullAndEmptySource; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) -class PurchasedLottosTest { +class LottosTest { @Test void 생성자_정상입력_생성성공() { - assertThatCode(() -> new PurchasedLottos(new Lotto(1, 2, 3, 4, 5, 6))).doesNotThrowAnyException(); + assertThatCode(() -> new Lottos(new Lotto(1, 2, 3, 4, 5, 6))).doesNotThrowAnyException(); } @ParameterizedTest(name = "입력:{0}") @NullAndEmptySource void 생성자_빈값입력_예외발생(List inputs) { - assertThatThrownBy(() -> new PurchasedLottos(inputs)) + assertThatThrownBy(() -> new Lottos(inputs)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("구매한 로또는 1개 이상이어야 합니다."); } From 675748627bc22d1e12c547cc006e49e61187c4e6 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Fri, 26 Dec 2025 06:29:01 +0900 Subject: [PATCH 21/26] =?UTF-8?q?refactor:=20=EB=8F=84=EB=A9=94=EC=9D=B8?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=EB=A5=BC=20domain=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AutoBasedLottoGeneratorTest.java - 테스트 패키지를 utils에서 domain으로 변경 - 동일 패키지로 인한 불필요한 import 제거 LottoNumberParserTest.java - 테스트 패키지를 utils에서 domain으로 변경 - 중복 import 제거로 코드 정리 ManualBasedLottoGeneratorTest.java - 테스트 패키지를 utils에서 domain으로 변경 - 불필요한 도메인 import 제거 --- .../lotto/{utils => domain}/AutoBasedLottoGeneratorTest.java | 4 +--- .../java/lotto/{utils => domain}/LottoNumberParserTest.java | 4 +--- .../{utils => domain}/ManualBasedLottoGeneratorTest.java | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) rename src/test/java/lotto/{utils => domain}/AutoBasedLottoGeneratorTest.java (82%) rename src/test/java/lotto/{utils => domain}/LottoNumberParserTest.java (87%) rename src/test/java/lotto/{utils => domain}/ManualBasedLottoGeneratorTest.java (86%) diff --git a/src/test/java/lotto/utils/AutoBasedLottoGeneratorTest.java b/src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java similarity index 82% rename from src/test/java/lotto/utils/AutoBasedLottoGeneratorTest.java rename to src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java index 89700003f7..0de595ac46 100644 --- a/src/test/java/lotto/utils/AutoBasedLottoGeneratorTest.java +++ b/src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java @@ -1,9 +1,7 @@ -package lotto.utils; +package lotto.domain; import static org.assertj.core.api.Assertions.*; -import lotto.domain.AutoBasedLottoGenerator; -import lotto.domain.LottoCount; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; diff --git a/src/test/java/lotto/utils/LottoNumberParserTest.java b/src/test/java/lotto/domain/LottoNumberParserTest.java similarity index 87% rename from src/test/java/lotto/utils/LottoNumberParserTest.java rename to src/test/java/lotto/domain/LottoNumberParserTest.java index 3686a74d1f..99b70c55e7 100644 --- a/src/test/java/lotto/utils/LottoNumberParserTest.java +++ b/src/test/java/lotto/domain/LottoNumberParserTest.java @@ -1,11 +1,9 @@ -package lotto.utils; +package lotto.domain; import static org.assertj.core.api.Assertions.*; import java.util.Arrays; import java.util.List; -import lotto.domain.LottoNumber; -import lotto.domain.LottoNumberParser; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; diff --git a/src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java b/src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java similarity index 86% rename from src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java rename to src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java index 4983cdb7ca..4f4b6b8bb3 100644 --- a/src/test/java/lotto/utils/ManualBasedLottoGeneratorTest.java +++ b/src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java @@ -1,10 +1,8 @@ -package lotto.utils; +package lotto.domain; import static org.assertj.core.api.Assertions.*; import java.util.List; -import lotto.domain.Lotto; -import lotto.domain.ManualBasedLottoGenerator; import org.junit.jupiter.api.DisplayNameGeneration; import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; From dad504f584e7adc49666f0e164791bf3a4685326 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Fri, 26 Dec 2025 06:43:27 +0900 Subject: [PATCH 22/26] =?UTF-8?q?refactor:=20=EB=A1=9C=EB=98=90=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=B1=85=EC=9E=84=EC=9D=84=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=ED=95=98=EA=B3=A0=20=EC=83=9D=EC=84=B1=EA=B8=B0=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Application.java - 수동/자동 로또 생성을 Lottos 단위로 처리하도록 변경 - merge 로직을 Application에서 제거하고 Lottos로 위임 AutoBasedLottoGenerator.java - LottosGenerator 인터페이스 구현 - 생성 시 LottoCount를 주입받도록 생성자 구조 변경 - generate 결과를 Lottos로 반환하도록 수정 ManualBasedLottoGenerator.java - LottosGenerator 인터페이스 구현 - 수동 입력값을 생성자에서 주입받도록 변경 - generate 결과를 Lottos로 반환 Lottos.java - Lottos 병합 책임을 가지는 merge 메서드 추가 - size 메서드 추가로 컬렉션 역할 명확화 LottosGenerator.java - 로또 생성 책임을 추상화한 인터페이스 추가 AutoBasedLottoGeneratorTest.java - 변경된 생성자 및 반환 타입에 맞게 테스트 수정 ManualBasedLottoGeneratorTest.java - generate 결과를 Lottos 기준으로 검증하도록 수정 LottosTest.java - merge 기능에 대한 테스트 추가 --- src/main/java/lotto/Application.java | 17 +++++------------ .../lotto/domain/AutoBasedLottoGenerator.java | 11 +++++++---- src/main/java/lotto/domain/Lottos.java | 13 +++++++++++++ .../java/lotto/domain/LottosGenerator.java | 6 ++++++ .../domain/ManualBasedLottoGenerator.java | 18 ++++++++++++------ .../domain/AutoBasedLottoGeneratorTest.java | 3 ++- src/test/java/lotto/domain/LottosTest.java | 10 ++++++++++ .../domain/ManualBasedLottoGeneratorTest.java | 4 ++-- 8 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 src/main/java/lotto/domain/LottosGenerator.java diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index 5d0f1fcb33..9b116fa68f 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -3,7 +3,6 @@ import static lotto.view.InputView.*; import static lotto.view.ResultView.*; -import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; import lotto.domain.*; @@ -34,7 +33,7 @@ private static Lottos purchaseLottos(LottoPurchaseAmount purchaseAmount) { printPurchaseCount(manualCount, autoCount); - return mergeLottos(createManualLottos(manualCount), generateAutoLottos(autoCount)); + return createManualLottos(manualCount).merge(generateAutoLottos(autoCount)); } private static LottoCount createManualLottoCount(LottoCount totalCount) { @@ -45,19 +44,13 @@ private static LottoCount createManualLottoCount(LottoCount totalCount) { }); } - private static List createManualLottos(LottoCount manualCount) { + private static Lottos createManualLottos(LottoCount manualCount) { return retryUntilSuccess( - () -> new ManualBasedLottoGenerator().generate(readManualLottoNumbers(manualCount.value()))); + () -> new ManualBasedLottoGenerator(readManualLottoNumbers(manualCount.value())).generate()); } - private static List generateAutoLottos(LottoCount autoCount) { - return new AutoBasedLottoGenerator().generate(autoCount); - } - - private static Lottos mergeLottos(List manual, List auto) { - List all = new ArrayList<>(manual); - all.addAll(auto); - return new Lottos(all); + private static Lottos generateAutoLottos(LottoCount autoCount) { + return new AutoBasedLottoGenerator(autoCount).generate(); } private static WinningLotto createWinningLotto() { diff --git a/src/main/java/lotto/domain/AutoBasedLottoGenerator.java b/src/main/java/lotto/domain/AutoBasedLottoGenerator.java index 2cd506f3e9..42ddf17d98 100644 --- a/src/main/java/lotto/domain/AutoBasedLottoGenerator.java +++ b/src/main/java/lotto/domain/AutoBasedLottoGenerator.java @@ -5,21 +5,24 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; -public class AutoBasedLottoGenerator { +public class AutoBasedLottoGenerator implements LottosGenerator { private static final int LOTTO_NUMBER_MIN = 1; private static final int LOTTO_NUMBER_MAX = 45; private static final int LOTTO_PICK_SIZE = 6; private final List numbers; + private final LottoCount count; - public AutoBasedLottoGenerator() { + public AutoBasedLottoGenerator(LottoCount count) { + this.count = count; this.numbers = IntStream.rangeClosed(LOTTO_NUMBER_MIN, LOTTO_NUMBER_MAX) .mapToObj(LottoNumber::of) .collect(Collectors.toList()); } - public List generate(LottoCount count) { - return generateLottos(count.value()); + @Override + public Lottos generate() { + return new Lottos(generateLottos(count.value())); } private List generateLottos(int count) { diff --git a/src/main/java/lotto/domain/Lottos.java b/src/main/java/lotto/domain/Lottos.java index 56ee0bb7e1..391c8849b1 100644 --- a/src/main/java/lotto/domain/Lottos.java +++ b/src/main/java/lotto/domain/Lottos.java @@ -1,5 +1,6 @@ package lotto.domain; +import java.util.ArrayList; import java.util.List; public record Lottos(List values) { @@ -18,6 +19,14 @@ private void validateNotBlank(List inputs) { } } + public Lottos merge(Lottos other) { + List merged = new ArrayList<>(this.values); + + merged.addAll(other.values); + + return new Lottos(merged); + } + public LottoResult result(WinningLotto winningLotto) { LottoResult result = new LottoResult(); @@ -27,4 +36,8 @@ public LottoResult result(WinningLotto winningLotto) { return result; } + + public int size() { + return values().size(); + } } diff --git a/src/main/java/lotto/domain/LottosGenerator.java b/src/main/java/lotto/domain/LottosGenerator.java new file mode 100644 index 0000000000..8e4d0e273d --- /dev/null +++ b/src/main/java/lotto/domain/LottosGenerator.java @@ -0,0 +1,6 @@ +package lotto.domain; + +@FunctionalInterface +public interface LottosGenerator { + Lottos generate(); +} diff --git a/src/main/java/lotto/domain/ManualBasedLottoGenerator.java b/src/main/java/lotto/domain/ManualBasedLottoGenerator.java index ca6d4447f8..d02cf40583 100644 --- a/src/main/java/lotto/domain/ManualBasedLottoGenerator.java +++ b/src/main/java/lotto/domain/ManualBasedLottoGenerator.java @@ -2,19 +2,25 @@ import java.util.List; -public class ManualBasedLottoGenerator { - +public class ManualBasedLottoGenerator implements LottosGenerator { + private final List manualInputs; private final LottoNumberParser parser; - public ManualBasedLottoGenerator() { - this(new LottoNumberParser()); + public ManualBasedLottoGenerator(List manualInputs) { + this(manualInputs, new LottoNumberParser()); } - private ManualBasedLottoGenerator(LottoNumberParser parser) { + private ManualBasedLottoGenerator(List manualInputs, LottoNumberParser parser) { + this.manualInputs = manualInputs; this.parser = parser; } - public List generate(List inputs) { + @Override + public Lottos generate() { + return new Lottos(generateLottos(manualInputs)); + } + + private List generateLottos(List inputs) { return inputs.stream().map(parser::parse).map(Lotto::new).toList(); } } diff --git a/src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java b/src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java index 0de595ac46..557d6aced3 100644 --- a/src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java +++ b/src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java @@ -11,6 +11,7 @@ class AutoBasedLottoGeneratorTest { @Test void generate_지정개수_생성() { - assertThat(new AutoBasedLottoGenerator().generate(new LottoCount(5))).hasSize(5); + assertThat(new AutoBasedLottoGenerator(new LottoCount(5)).generate().size()) + .isEqualTo(5); } } diff --git a/src/test/java/lotto/domain/LottosTest.java b/src/test/java/lotto/domain/LottosTest.java index 932d2932a6..123728048d 100644 --- a/src/test/java/lotto/domain/LottosTest.java +++ b/src/test/java/lotto/domain/LottosTest.java @@ -24,4 +24,14 @@ class LottosTest { .isInstanceOf(IllegalArgumentException.class) .hasMessage("구매한 로또는 1개 이상이어야 합니다."); } + + @Test + void merge_두_로또_목록을_합친다() { + Lottos first = new Lottos(new Lotto(1, 2, 3, 4, 5, 6)); + Lottos second = new Lottos(new Lotto(7, 8, 9, 10, 11, 12)); + + Lottos merged = first.merge(second); + + assertThat(merged.size()).isEqualTo(2); + } } diff --git a/src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java b/src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java index 4f4b6b8bb3..ef520c17f0 100644 --- a/src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java +++ b/src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java @@ -12,7 +12,7 @@ class ManualBasedLottoGeneratorTest { @Test void generate_문자열목록_생성() { - assertThat(new ManualBasedLottoGenerator().generate(List.of("1, 2, 3, 4, 5, 6", "7, 8, 9, 10, 11, 12"))) - .isEqualTo(List.of(new Lotto(1, 2, 3, 4, 5, 6), new Lotto(7, 8, 9, 10, 11, 12))); + assertThat(new ManualBasedLottoGenerator(List.of("1, 2, 3, 4, 5, 6", "7, 8, 9, 10, 11, 12")).generate()) + .isEqualTo(new Lottos(List.of(new Lotto(1, 2, 3, 4, 5, 6), new Lotto(7, 8, 9, 10, 11, 12)))); } } From 9f9ee78af38da4df25a3c68e623706c782a8024d Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Fri, 26 Dec 2025 21:33:46 +0900 Subject: [PATCH 23/26] =?UTF-8?q?refactor:=20Application=EC=9D=98=20?= =?UTF-8?q?=EB=A1=9C=EB=98=90=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EB=8B=B9?= =?UTF-8?q?=EC=B2=A8=20=EB=A1=9C=EC=A7=81=20=EA=B0=84=EC=86=8C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Application.java - 자동 로또 생성 메서드명을 generateAutoLottos → createAutoLottos로 변경해 네이밍 일관성 개선 - 당첨 로또 생성 관련 메서드들을 하나의 람다로 통합하여 로직 단순화 - 불필요한 import(List) 및 중간 메서드 제거로 코드 가독성 향상 --- src/main/java/lotto/Application.java | 32 ++++------------------------ 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index 9b116fa68f..71474916f7 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -3,7 +3,6 @@ import static lotto.view.InputView.*; import static lotto.view.ResultView.*; -import java.util.List; import java.util.function.Supplier; import lotto.domain.*; import lotto.domain.AutoBasedLottoGenerator; @@ -33,7 +32,7 @@ private static Lottos purchaseLottos(LottoPurchaseAmount purchaseAmount) { printPurchaseCount(manualCount, autoCount); - return createManualLottos(manualCount).merge(generateAutoLottos(autoCount)); + return createManualLottos(manualCount).merge(createAutoLottos(autoCount)); } private static LottoCount createManualLottoCount(LottoCount totalCount) { @@ -49,36 +48,13 @@ private static Lottos createManualLottos(LottoCount manualCount) { () -> new ManualBasedLottoGenerator(readManualLottoNumbers(manualCount.value())).generate()); } - private static Lottos generateAutoLottos(LottoCount autoCount) { + private static Lottos createAutoLottos(LottoCount autoCount) { return new AutoBasedLottoGenerator(autoCount).generate(); } private static WinningLotto createWinningLotto() { - Lotto lotto = createLottoForWinning(); - LottoNumber bonus = createBonusNumber(lotto); - return new WinningLotto(lotto, bonus); - } - - private static Lotto createLottoForWinning() { - return retryUntilSuccess(() -> new Lotto(createWinningNumbers())); - } - - private static List createWinningNumbers() { - return new LottoNumberParser().parse(readWinningNumbers()); - } - - private static LottoNumber createBonusNumber(Lotto lotto) { - return retryUntilSuccess(() -> { - LottoNumber bonus = LottoNumber.of(readBonusNumber()); - validateBonusNotDuplicated(lotto, bonus); - return bonus; - }); - } - - private static void validateBonusNotDuplicated(Lotto lotto, LottoNumber bonus) { - if (lotto.contains(bonus)) { - throw new IllegalArgumentException("보너스 번호는 당첨 번호와 중복될 수 없습니다."); - } + return retryUntilSuccess(() -> new WinningLotto( + new Lotto(new LottoNumberParser().parse(readWinningNumbers())), LottoNumber.of(readBonusNumber()))); } private static T retryUntilSuccess(Supplier action) { From ad83bdc9b6a5668030d2f7ba0bcbe7c083032a0c Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Fri, 26 Dec 2025 23:18:34 +0900 Subject: [PATCH 24/26] =?UTF-8?q?refactor:=20LottoGenerator=20=EB=AA=85?= =?UTF-8?q?=EB=AA=85=20=EC=9D=BC=EA=B4=80=EC=84=B1=20=EA=B0=9C=EC=84=A0=20?= =?UTF-8?q?=EB=B0=8F=20=EB=B3=B5=EC=88=98=20=EA=B0=9C=EB=85=90=20=EB=AA=85?= =?UTF-8?q?=ED=99=95=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lotto/Application.java | 8 ++++---- ...dLottoGenerator.java => AutoBasedLottosGenerator.java} | 4 ++-- ...ottoGenerator.java => ManualBasedLottosGenerator.java} | 6 +++--- ...neratorTest.java => AutoBasedLottosGeneratorTest.java} | 4 ++-- ...ratorTest.java => ManualBasedLottosGeneratorTest.java} | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) rename src/main/java/lotto/domain/{AutoBasedLottoGenerator.java => AutoBasedLottosGenerator.java} (88%) rename src/main/java/lotto/domain/{ManualBasedLottoGenerator.java => ManualBasedLottosGenerator.java} (69%) rename src/test/java/lotto/domain/{AutoBasedLottoGeneratorTest.java => AutoBasedLottosGeneratorTest.java} (75%) rename src/test/java/lotto/domain/{ManualBasedLottoGeneratorTest.java => ManualBasedLottosGeneratorTest.java} (75%) diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index 71474916f7..fa4f1fd451 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -5,9 +5,9 @@ import java.util.function.Supplier; import lotto.domain.*; -import lotto.domain.AutoBasedLottoGenerator; +import lotto.domain.AutoBasedLottosGenerator; import lotto.domain.LottoNumberParser; -import lotto.domain.ManualBasedLottoGenerator; +import lotto.domain.ManualBasedLottosGenerator; public class Application { public static void main(String[] args) { @@ -45,11 +45,11 @@ private static LottoCount createManualLottoCount(LottoCount totalCount) { private static Lottos createManualLottos(LottoCount manualCount) { return retryUntilSuccess( - () -> new ManualBasedLottoGenerator(readManualLottoNumbers(manualCount.value())).generate()); + () -> new ManualBasedLottosGenerator(readManualLottoNumbers(manualCount.value())).generate()); } private static Lottos createAutoLottos(LottoCount autoCount) { - return new AutoBasedLottoGenerator(autoCount).generate(); + return new AutoBasedLottosGenerator(autoCount).generate(); } private static WinningLotto createWinningLotto() { diff --git a/src/main/java/lotto/domain/AutoBasedLottoGenerator.java b/src/main/java/lotto/domain/AutoBasedLottosGenerator.java similarity index 88% rename from src/main/java/lotto/domain/AutoBasedLottoGenerator.java rename to src/main/java/lotto/domain/AutoBasedLottosGenerator.java index 42ddf17d98..d4631bda2f 100644 --- a/src/main/java/lotto/domain/AutoBasedLottoGenerator.java +++ b/src/main/java/lotto/domain/AutoBasedLottosGenerator.java @@ -5,7 +5,7 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; -public class AutoBasedLottoGenerator implements LottosGenerator { +public class AutoBasedLottosGenerator implements LottosGenerator { private static final int LOTTO_NUMBER_MIN = 1; private static final int LOTTO_NUMBER_MAX = 45; private static final int LOTTO_PICK_SIZE = 6; @@ -13,7 +13,7 @@ public class AutoBasedLottoGenerator implements LottosGenerator { private final List numbers; private final LottoCount count; - public AutoBasedLottoGenerator(LottoCount count) { + public AutoBasedLottosGenerator(LottoCount count) { this.count = count; this.numbers = IntStream.rangeClosed(LOTTO_NUMBER_MIN, LOTTO_NUMBER_MAX) .mapToObj(LottoNumber::of) diff --git a/src/main/java/lotto/domain/ManualBasedLottoGenerator.java b/src/main/java/lotto/domain/ManualBasedLottosGenerator.java similarity index 69% rename from src/main/java/lotto/domain/ManualBasedLottoGenerator.java rename to src/main/java/lotto/domain/ManualBasedLottosGenerator.java index d02cf40583..2eaed528ff 100644 --- a/src/main/java/lotto/domain/ManualBasedLottoGenerator.java +++ b/src/main/java/lotto/domain/ManualBasedLottosGenerator.java @@ -2,15 +2,15 @@ import java.util.List; -public class ManualBasedLottoGenerator implements LottosGenerator { +public class ManualBasedLottosGenerator implements LottosGenerator { private final List manualInputs; private final LottoNumberParser parser; - public ManualBasedLottoGenerator(List manualInputs) { + public ManualBasedLottosGenerator(List manualInputs) { this(manualInputs, new LottoNumberParser()); } - private ManualBasedLottoGenerator(List manualInputs, LottoNumberParser parser) { + private ManualBasedLottosGenerator(List manualInputs, LottoNumberParser parser) { this.manualInputs = manualInputs; this.parser = parser; } diff --git a/src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java b/src/test/java/lotto/domain/AutoBasedLottosGeneratorTest.java similarity index 75% rename from src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java rename to src/test/java/lotto/domain/AutoBasedLottosGeneratorTest.java index 557d6aced3..10ffa0e958 100644 --- a/src/test/java/lotto/domain/AutoBasedLottoGeneratorTest.java +++ b/src/test/java/lotto/domain/AutoBasedLottosGeneratorTest.java @@ -7,11 +7,11 @@ import org.junit.jupiter.api.Test; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) -class AutoBasedLottoGeneratorTest { +class AutoBasedLottosGeneratorTest { @Test void generate_지정개수_생성() { - assertThat(new AutoBasedLottoGenerator(new LottoCount(5)).generate().size()) + assertThat(new AutoBasedLottosGenerator(new LottoCount(5)).generate().size()) .isEqualTo(5); } } diff --git a/src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java b/src/test/java/lotto/domain/ManualBasedLottosGeneratorTest.java similarity index 75% rename from src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java rename to src/test/java/lotto/domain/ManualBasedLottosGeneratorTest.java index ef520c17f0..c3fb28a40d 100644 --- a/src/test/java/lotto/domain/ManualBasedLottoGeneratorTest.java +++ b/src/test/java/lotto/domain/ManualBasedLottosGeneratorTest.java @@ -8,11 +8,11 @@ import org.junit.jupiter.api.Test; @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) -class ManualBasedLottoGeneratorTest { +class ManualBasedLottosGeneratorTest { @Test void generate_문자열목록_생성() { - assertThat(new ManualBasedLottoGenerator(List.of("1, 2, 3, 4, 5, 6", "7, 8, 9, 10, 11, 12")).generate()) + assertThat(new ManualBasedLottosGenerator(List.of("1, 2, 3, 4, 5, 6", "7, 8, 9, 10, 11, 12")).generate()) .isEqualTo(new Lottos(List.of(new Lotto(1, 2, 3, 4, 5, 6), new Lotto(7, 8, 9, 10, 11, 12)))); } } From 7f523ecd6bda73b7b9fb85864c3c0458cf581725 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Fri, 26 Dec 2025 23:41:28 +0900 Subject: [PATCH 25/26] =?UTF-8?q?feat:=20=EC=88=98=EB=8F=99/=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EB=A1=9C=EB=98=90=20=EC=83=9D=EC=84=B1=EC=9D=84=20?= =?UTF-8?q?CombinedLottosGenerator=EB=A1=9C=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Application.java - 수동/자동 로또 생성 로직을 CombinedLottosGenerator 사용 방식으로 리팩터링 - 개별 Manual/Auto 생성 메서드 제거 및 생성 책임 위임 CombinedLottosGenerator.java - 수동/자동 LottosGenerator를 조합해 하나의 Lottos를 생성하는 Generator 추가 - 구매 금액과 수동 입력을 기반으로 Generator 구성을 캡슐화 CombinedLottosGeneratorTest.java - 여러 Generator를 조합해 로또가 정상 생성되는지 검증하는 테스트 추가 --- src/main/java/lotto/Application.java | 21 ++++++------- .../lotto/domain/CombinedLottosGenerator.java | 31 +++++++++++++++++++ .../domain/CombinedLottosGeneratorTest.java | 22 +++++++++++++ 3 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 src/main/java/lotto/domain/CombinedLottosGenerator.java create mode 100644 src/test/java/lotto/domain/CombinedLottosGeneratorTest.java diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java index fa4f1fd451..1905970f26 100644 --- a/src/main/java/lotto/Application.java +++ b/src/main/java/lotto/Application.java @@ -3,11 +3,10 @@ import static lotto.view.InputView.*; import static lotto.view.ResultView.*; +import java.util.List; import java.util.function.Supplier; import lotto.domain.*; -import lotto.domain.AutoBasedLottosGenerator; import lotto.domain.LottoNumberParser; -import lotto.domain.ManualBasedLottosGenerator; public class Application { public static void main(String[] args) { @@ -32,7 +31,14 @@ private static Lottos purchaseLottos(LottoPurchaseAmount purchaseAmount) { printPurchaseCount(manualCount, autoCount); - return createManualLottos(manualCount).merge(createAutoLottos(autoCount)); + return createLottos(purchaseAmount, manualCount); + } + + private static Lottos createLottos(LottoPurchaseAmount purchaseAmount, LottoCount manualCount) { + return retryUntilSuccess(() -> { + List manualInputs = readManualLottoNumbers(manualCount.value()); + return new CombinedLottosGenerator(purchaseAmount, manualInputs).generate(); + }); } private static LottoCount createManualLottoCount(LottoCount totalCount) { @@ -43,15 +49,6 @@ private static LottoCount createManualLottoCount(LottoCount totalCount) { }); } - private static Lottos createManualLottos(LottoCount manualCount) { - return retryUntilSuccess( - () -> new ManualBasedLottosGenerator(readManualLottoNumbers(manualCount.value())).generate()); - } - - private static Lottos createAutoLottos(LottoCount autoCount) { - return new AutoBasedLottosGenerator(autoCount).generate(); - } - private static WinningLotto createWinningLotto() { return retryUntilSuccess(() -> new WinningLotto( new Lotto(new LottoNumberParser().parse(readWinningNumbers())), LottoNumber.of(readBonusNumber()))); diff --git a/src/main/java/lotto/domain/CombinedLottosGenerator.java b/src/main/java/lotto/domain/CombinedLottosGenerator.java new file mode 100644 index 0000000000..a62e58b714 --- /dev/null +++ b/src/main/java/lotto/domain/CombinedLottosGenerator.java @@ -0,0 +1,31 @@ +package lotto.domain; + +import java.util.List; + +public class CombinedLottosGenerator implements LottosGenerator { + private final List generators; + + public CombinedLottosGenerator(LottoPurchaseAmount amount, List manualInputs) { + this(toGenerators(amount, manualInputs)); + } + + private static List toGenerators(LottoPurchaseAmount amount, List manualInputs) { + LottoCount totalCount = amount.lottoCount(); + LottoCount manualCount = new LottoCount(manualInputs.size()); + LottoCount autoCount = totalCount.subtract(manualCount); + + return List.of(new ManualBasedLottosGenerator(manualInputs), new AutoBasedLottosGenerator(autoCount)); + } + + public CombinedLottosGenerator(List generators) { + this.generators = generators; + } + + @Override + public Lottos generate() { + return generators.stream() + .map(LottosGenerator::generate) + .reduce(Lottos::merge) + .orElseThrow(() -> new IllegalStateException("Generator가 없습니다.")); + } +} diff --git a/src/test/java/lotto/domain/CombinedLottosGeneratorTest.java b/src/test/java/lotto/domain/CombinedLottosGeneratorTest.java new file mode 100644 index 0000000000..de15aefcd8 --- /dev/null +++ b/src/test/java/lotto/domain/CombinedLottosGeneratorTest.java @@ -0,0 +1,22 @@ +package lotto.domain; + +import static org.assertj.core.api.Assertions.*; + +import java.util.List; +import org.junit.jupiter.api.DisplayNameGeneration; +import org.junit.jupiter.api.DisplayNameGenerator; +import org.junit.jupiter.api.Test; + +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +class CombinedLottosGeneratorTest { + + @Test + void 여러_Generator를_조합하여_로또를_생성한다() { + LottosGenerator gen1 = () -> new Lottos(new Lotto(1, 2, 3, 4, 5, 6)); + LottosGenerator gen2 = () -> new Lottos(new Lotto(7, 8, 9, 10, 11, 12)); + + CombinedLottosGenerator combined = new CombinedLottosGenerator(List.of(gen1, gen2)); + + assertThat(combined.generate().size()).isEqualTo(2); + } +} From bc156b67c21d6fbe411e5c688fe300eef52efef4 Mon Sep 17 00:00:00 2001 From: ghtjr410 Date: Fri, 26 Dec 2025 23:48:42 +0900 Subject: [PATCH 26/26] =?UTF-8?q?docs:=20=EB=A1=9C=EB=98=90=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20=EB=AC=B8=EC=84=9C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 04-lotto-manual.md - Lottos 도메인 역할 및 책임 명세 추가 - PurchasedLottos 제거에 따른 문서 정리 - LottosGenerator 인터페이스 및 구현체 구조 설명 추가 - Auto/Manual/Combined LottosGenerator 개념과 책임을 문서에 반영 --- docs/04-lotto-manual.md | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/04-lotto-manual.md b/docs/04-lotto-manual.md index a1c3403938..41a29be263 100644 --- a/docs/04-lotto-manual.md +++ b/docs/04-lotto-manual.md @@ -60,6 +60,13 @@ - [x] 특정 번호 포함 여부 판단 - [x] 정렬된 출력용 문자열 반환 +### 로또 목록 +- [x] 로또 목록 (Lottos) + - [x] 로또 목록으로 생성 + - [x] 빈 목록일 시 예외 발생 + - [x] 당첨 로또와 비교하여 결과 생성 + - [x] 다른 로또 목록과 병합 (merge) + ### 로또 구매 - [x] 로또 구매 개수 (LottoCount) - [x] 0 이상의 정수로 생성 @@ -77,11 +84,6 @@ - [x] 1,000원 단위가 아닐 시 예외 발생 - [x] 구매 가능한 로또 개수 계산 -- [x] 구매한 로또 목록 (PurchasedLottos) - - [x] 로또 목록으로 생성 - - [x] 빈 목록일 시 예외 발생 - - [x] 당첨 로또와 비교하여 결과 생성 - ### 당첨 판정 - [x] 당첨 로또 (WinningLotto) - [x] 로또와 보너스 번호로 생성 @@ -111,13 +113,26 @@ - [x] 수익률 0 미만일 시 예외 발생 - [x] 수익률 출력용 문자열 반환 -### 유틸리티 -- [x] 자동 로또 생성기 (AutoBasedLottoGenerator) +### 로또 생성 +- [x] 로또 생성기 인터페이스 (LottosGenerator) + - [x] 로또 목록 생성 메서드 정의 + +- [x] 자동 로또 생성기 (AutoBasedLottosGenerator) + - LottosGenerator 구현 - [x] 1~45 범위의 번호 풀 보유 - [x] 지정 개수만큼 로또 생성 - [x] 셔플 방식으로 6개 번호 선택 -- [x] 수동 로또 생성기 (ManualBasedLottoGenerator) + +- [x] 수동 로또 생성기 (ManualBasedLottosGenerator) + - [x] LottosGenerator 구현 - [x] 문자열 목록을 입력받아 로또 목록 생성 +- [x] 복합 로또 생성기 (CombinedLottosGenerator) + - [x] LottosGenerator 구현 + - [x] 구매 금액과 수동 입력으로 생성 + - [x] 수동/자동 개수 계산 후 각 Generator 생성 + - [x] 여러 Generator 결과를 병합하여 반환 + +### 유틸리티 - [x] 로또 번호 파서 (LottoNumberParser) - [x] 쉼표 구분 문자열을 로또 번호 목록으로 변환 \ No newline at end of file