From 8b0dbc1086779542580aa3ba455ebdf0a94bc650 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EB=B0=95=EB=AF=BC=EC=9A=B1?=
<88137420+JohnPrk@users.noreply.github.com>
Date: Sun, 2 Nov 2025 15:56:17 +0900
Subject: [PATCH 01/10] Update README.md
---
README.md | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 215 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5fa2560b46..a71d9a7ea2 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,215 @@
-# java-lotto-precourse
+# ๐ฐ ๋ก๋ ๊ฒ์ (Lotto Game)
+
+์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๊ธ์ก๋งํผ ๋ก๋๋ฅผ ์๋์ผ๋ก ๋ฐํํ๊ณ , ๋น์ฒจ ๋ฒํธ์ ๋ณด๋์ค ๋ฒํธ๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฒฐ๊ณผ ํต๊ณ์ ์์ต๋ฅ ์ ์ถ๋ ฅํ๋ ์ฝ์ ๊ธฐ๋ฐ ํ๋ก๊ทธ๋จ์
๋๋ค.
+
+Java 21 ํ๊ฒฝ์์ ๋์ํ๋ฉฐ, ๊ธฐ๋ฅ๋ณ ์ฑ
์์ ๋ถ๋ฆฌํด ๊ตฌํํ๋ ๋ฐ ์ค์ ์ ๋์์ต๋๋ค.
+
+
+
+
+## ๐ญ **๐ฏ ํ๋ก์ ํธ์ ์งํฅ์ ๋ฐ** ๋ฐฉํฅ
+
+๊ด๋ จ๋ ๋ฐ์ดํฐ์ ๋์์ ํจ๊ป ๋ฌถ์ด **๊ฐ ํด๋์ค๊ฐ ๋ถ๋ช
ํ ์ฑ
์์ ๊ฐ๋๋ก ๊ตฌ์ฑ**ํ๊ณ , **์ฌ๋ฌ ๊ฐ์ฒด๋ค์ด ์ญํ ์ ๋ฐ๋ผ ํ๋ ฅ**ํ๋ฉฐ ํ๋์ ๊ธฐ๋ฅ์ ์์ฑํ ์ ์๋๋ก ์ค๊ณํฉ๋๋ค.
+
+TDD ์ฌ์ดํด ์ค **Inside-Out ๋ฐฉ์์ ๊ธฐ๋ฐ์ผ๋ก**, **์
์ถ๋ ฅ๋ณด๋ค๋ ๋จผ์ ๋๋ฉ์ธ ๋ก์ง์ ์ค์ฌ์ผ๋ก ๊ฐ๋ฐ์ ์์**ํ๊ณ , ํ
์คํธ ๊ฐ๋ฅํ ์์ ๋จ์๋ถํฐ ์ ์ฐจ ํ์ฅํด ๋๊ฐ๋๋ค.
+
+
+
+
+## ๐ ์ํ์ค ๋ค์ด์ด๊ทธ๋จ
+
+์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฒด ๋์ ๊ณผ์ ๊ณผ ๊ฐ์ฒด ๊ฐ์ ์ํธ์์ฉ์ ์๊ฐํํ๊ธฐ ์ํด ์ํ์ค ๋ค์ด์ด๊ทธ๋จ์ ์ฌ์ฉํ์ต๋๋ค.
+
+```mermaid
+sequenceDiagram
+ participant U as ์ฌ์ฉ์
+ participant I as InputView
+ participant O as OutputView
+ participant C as LottoController
+ participant M as Money
+ participant F as LottoFactory
+ participant L as Lotto
+ participant W as WinningNumbers
+ participant R as LottoResults
+
+Note over U,C: ๐ซ 1๋จ๊ณ: ๋ก๋ ๊ตฌ๋งค
+ loop ์ ํจํ ๊ธ์ก์ด ์
๋ ฅ๋ ๋๊น์ง
+ U->>I: ๊ตฌ์
๊ธ์ก ์
๋ ฅ
+ I->>C: ๊ธ์ก ์ ๋ฌ
+ C->>M: Money ์์ฑ ๋ฐ ๊ฒ์ฆ
+ alt ๊ฒ์ฆ ์ฑ๊ณต
+ M-->>C: ์ ํจํ Money ๊ฐ์ฒด
+ else ๊ฒ์ฆ ์คํจ
+ M-->>C: IllegalArgumentException
+ C->>O: ๋ฉ์์ง ์ถ๋ ฅ
+ O->>U: ์๋ฌ ํ์
+ end
+ end
+
+ C->>M: getLottoCount() ํธ์ถ
+ M-->>C: ๊ตฌ๋งค ๊ฐ๋ฅํ ๋ก๋ ๊ฐ์
+ loop N๋ฒ (๋ก๋ ๊ฐ์๋งํผ)
+ C->>F: generateLotto() ํธ์ถ
+ F->>F: Randoms.pickUniqueNumbersInRange(1,45,6)
+ F-->>C: ์์ฑ๋ ๋ฒํธ ๋ชฉ๋ก
+ C->>L: Lotto ๊ฐ์ฒด ์์ฑ
+ end
+ C->>O: ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก ์ถ๋ ฅ
+ O->>U: ๋ก๋ ๋ชฉ๋ก ํ์
+
+Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
+ loop ์ ํจํ ๋น์ฒจ ๋ฒํธ๊ฐ ์
๋ ฅ๋ ๋๊น์ง
+ U->>I: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ (์ผํ ๊ตฌ๋ถ)
+ I->>C: ๋น์ฒจ ๋ฒํธ ์ ๋ฌ
+ C->>W: WinningNumbers ์์ฑ ๋ฐ ๊ฒ์ฆ
+ alt ๊ฒ์ฆ ์ฑ๊ณต
+ W-->>C: ๋น์ฒจ ๋ฒํธ ๊ฐ์ฒด ์์ฑ๋จ
+ else ๊ฒ์ฆ ์คํจ
+ W-->>C: IllegalArgumentException
+ C->>O: ๋ฉ์์ง ์ถ๋ ฅ
+ O->>U: ์๋ฌ ํ์
+ end
+ end
+
+ loop ์ ํจํ ๋ณด๋์ค ๋ฒํธ๊ฐ ์
๋ ฅ๋ ๋๊น์ง
+ U->>I: ๋ณด๋์ค ๋ฒํธ ์
๋ ฅ
+ I->>C: ๋ณด๋์ค ๋ฒํธ ์ ๋ฌ
+ C->>W: ๋ณด๋์ค ๋ฒํธ ์ค์ ๋ฐ ๊ฒ์ฆ
+ alt ๊ฒ์ฆ ์ฑ๊ณต
+ W-->>C: ์ต์ข
๋น์ฒจ ๋ฒํธ ๊ฐ์ฒด ์์ฑ
+ else ๊ฒ์ฆ ์คํจ
+ W-->>C: IllegalArgumentException
+ C->>O: ๋ฉ์์ง ์ถ๋ ฅ
+ O->>U: ์๋ฌ ํ์
+ end
+ end
+ Note over U,C: ๐ 3๋จ๊ณ: ๊ฒฐ๊ณผ ๋ถ์ ๋ฐ ์ถ๋ ฅ
+ C->>R: LottoResults ์์ฑ (List, WinningNumbers)
+ loop ๊ฐ ๋ก๋์ ๋ํด
+ R->>R: calculateRank(lotto, winningNumbers)
+ R->>R: ๋ฑ์๋ณ ์นด์ดํธ ์ฆ๊ฐ
+ R->>R: ์ด ์๊ธ ๋์
+ end
+ R->>R: ์์ต๋ฅ ๊ณ์ฐ
+ R-->>C: ๋ถ์ ๊ฒฐ๊ณผ
+ C->>O: ๋น์ฒจ ํต๊ณ ์ถ๋ ฅ
+ O->>U: ํต๊ณ ํ์
+ C->>O: ์์ต๋ฅ ์ถ๋ ฅ
+ O->>U: ์์ต๋ฅ ํ์
+```
+
+
+
+
+## **๐งฑ ๊ฐ์ฒด ์ญํ ์์ฝ**
+
+| ๊ฐ์ฒด ์ด๋ฆ | ์ญํ (์ฑ
์) | ๋ณด์ ๊ฐ(์ํ) | ์ฃผ์ ํ์ |
+| --- | --- | --- | --- |
+| `Money` | ๊ตฌ์
๊ธ์ก์ ํํํ๊ณ ๊ด๋ จ ๊ท์น์ ๊ฒ์ฆํ๋ ๊ฐ ๊ฐ์ฒด | * ๊ตฌ์
๊ธ์ก | - ๊ธ์ก ์ ํจ์ฑ ๊ฒ์ฌ, ๊ตฌ๋งค ๊ฐ๋ฅํ ๋ก๋ ์ ๊ณ์ฐ |
+| `Lotto` | ๋ก๋ ํ ์ฅ์ ํํํ๋ฉฐ ๋ฒํธ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ๋ถ๋ณ์ฑ์ ๋ณด์ฅ | * 6๊ฐ์ ๋ก๋ ๋ฒํธ | - ๋ฒํธ ์ ๋ ฌ ๋ฐ ์ค๋ณต ๊ฒ์ฌ, ๋น์ฒจ ๋ฒํธ์ ์ผ์น ๊ฐ์ ๊ณ์ฐ, ๋ณด๋์ค ํฌํจ ์ฌ๋ถ ํ์ธ |
+| `LottoFactory` | ๋ก๋ ๊ท์น์ ๋ง๋ ๋๋ค ๋ฒํธ๋ฅผ ์์ฑํ์ฌย `Lotto`ย ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ์ฑ
์์ ์ง | | -`Randoms.pickUniqueNumbersInRange()`๋ฅผ ์ฌ์ฉํด ๋ก๋ ๋ฒํธ ์์ฑ |
+| `WinningNumbers` | ๋น์ฒจ ๋ฒํธ์ ๋ณด๋์ค ๋ฒํธ๋ฅผ ๊ฐ์ง๋ฉฐ ๊ด๋ จ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ์ฑ
์์ง | * 6๊ฐ ๋น์ฒจ ๋ฒํธ, 1๊ฐ ๋ณด๋์ค ๋ฒํธ | - ๋น์ฒจ ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ, ๋ณด๋์ค ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์ค๋ณต ํ์ธ |
+| `LottoRank` | ๋น์ฒจ ๋ฑ์(1~5๋ฑ, ๊ฝ)์ ์กฐ๊ฑด(์ผ์น ๊ฐ์, ๋ณด๋์ค)๊ณผ ์๊ธ์ ์ ์ | *Enum class(์ผ์น ๊ฐ์, ๋ณด๋์ค ํฌํจ์ฌ๋ถ,๋น์ฒจ ๊ธ์ก) | - ์ผ์น ์/๋ณด๋์ค ํฌํจ ์ฌ๋ถ๋ก ๋ฑ์ ๋ฐํ, ์๊ธ ๋ฐํ |
+| `LottoResults` | ์ ์ฒด ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐ | * ๋ฑ์๋ณ ๋น์ฒจ ํ์, ์ด ์์ต๋ฅ , ๋์ ์๊ธ | - ๊ฐ ๋ก๋์ ๋ํ ๋ฑ์ ๊ณ์ฐ, ๋น์ฒจ ๊ฒฐ๊ณผ ๋์ , ์์ต๋ฅ ๊ณ์ฐ |
+| `InputView` | ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์
๋ ฅ ์ ๋์ฌ | - ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ์, `camp.nextstep.edu.missionutils.Console`์ย `readLine()`์ ์ฌ์ฉ |
+| `OutputView` | ์ฌ์ฉ์์๊ฒ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์ถ๋ ฅ ์ ๋์ฌ | - ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก ์ถ๋ ฅ, ๋น์ฒจ ๊ฒฐ๊ณผ ์ถ๋ ฅ, ์์ต๋ฅ ์ถ๋ ฅ |
+| `LottoController` | ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฒด ์คํ ํ๋ฆ์ ์กฐ์จ. View์ Domain ๊ฐ์ฒด๋ค์ ์ฐ๊ฒฐ | | - ์ ์ฒด ํ๋ฆ ์ ์ด |
+
+
+
+
+## **๐ฐ ๊ตฌํ ์์ (Inside-Out ๋ฐฉ์)**
+
+### **1๋จ๊ณ: ํต์ฌ ๋๋ฉ์ธ ๋ชจ๋ธ ๊ตฌํ**
+
+> ๋น์ฆ๋์ค์ ๊ฐ์ฅ ๋ณธ์ง์ ์ธ ๊ท์น๊ณผ ๋ฐ์ดํฐ๋ฅผ ์ ์ํ๊ณ ํ
์คํธํฉ๋๋ค.
+>
+- `Money`: ๊ธ์ก์ ํํํ๊ณ , 1,000์ ๋จ์ ๊ฒ์ฆ ๋ฐ ๋ก๋ ๊ตฌ๋งค ๊ฐ๋ฅ ๊ฐ์ ๊ณ์ฐ ์ฑ
์์ ๊ฐ์ง๋๋ค.
+- `Lotto`: ๋ก๋ ํ ์ฅ(6๊ฐ ๋ฒํธ)์ ํํํ๋ฉฐ, ๋ฒํธ ๊ฐ์, ๋ฒ์, ์ค๋ณต ๋ฑ ๊ท์น์ ๋ถ๋ณ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
+
+### **2๋จ๊ณ: ๋น์ฒจ ๊ท์น ๋ฐ ํ์ ๋ก์ง ๊ตฌํ**
+
+> ๋น์ฒจ์ ๊ฒฐ์ ํ๋ ๊ธฐ์ค๊ณผ ๋ก์ง์ ๊ตฌํํฉ๋๋ค.
+>
+- `WinningNumbers`: ๋น์ฒจ ๋ฒํธ(6๊ฐ)์ ๋ณด๋์ค ๋ฒํธ(1๊ฐ)๋ฅผ ๊ฐ์ง๋ฉฐ, ๊ด๋ จ๋ ์ ํจ์ฑ ๊ฒ์ฆ ์ฑ
์์ ๊ฐ์ง๋๋ค.
+- `LottoRank`: 5๊ฐ ๋ฑ์์ '๊ฝ'์ ๋ํ ์กฐ๊ฑด(์ผ์น ๊ฐ์, ๋ณด๋์ค ์ฌ๋ถ)๊ณผ ์๊ธ์ `enum`์ผ๋ก ์ ์ํฉ๋๋ค. **(๋ฑ์ ํ์ ๋ก์ง ํฌํจ)**
+
+### **3๋จ๊ณ: ๊ฒฐ๊ณผ ์ง๊ณ ๋ฐ ๋ถ์ ๋ก์ง ๊ตฌํ**
+
+> ๊ตฌ๋งคํ ๋ก๋๋ค์ ๊ฒฐ๊ณผ๋ฅผ ์ข
ํฉํ์ฌ ํต๊ณ๋ฅผ ๋ด๋ ์ฑ
์์ ๊ตฌํํฉ๋๋ค.
+>
+- `LottoResults`: ๊ตฌ๋งคํ ๋ชจ๋ `Lotto`์ `WinningNumbers`๋ฅผ ๋น๊ตํ์ฌ, ๋ฑ์๋ณ ๋น์ฒจ ํ์๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐํฉ๋๋ค.
+
+### **4๋จ๊ณ: ๋ก๋ ์์ฑ ๋ก์ง ๊ตฌํ**
+
+> ๋๋ฉ์ธ ๊ท์น์ ๋ฐ๋ผ ๋ก๋๋ฅผ ์์ฑํ๋ ์ฑ
์์ ๊ตฌํํฉ๋๋ค.
+>
+- `LottoFactory`: `Randoms` ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๋ ๋ฒํธ๋ฅผ ์์ฑํ๊ณ , ๊ฒ์ฆ๋ `Lotto` ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ฐํํฉ๋๋ค.
+
+### **5๋จ๊ณ: ์
์ถ๋ ฅ(UI) ๊ณ์ธต ๊ตฌํ**
+
+> ์ฌ์ฉ์์ ์ํธ์์ฉํ๋ ๋ถ๋ถ์ ๊ตฌํํฉ๋๋ค.
+>
+- `InputView`: ์ฌ์ฉ์๋ก๋ถํฐ ๊ตฌ์
๊ธ์ก, ๋น์ฒจ ๋ฒํธ, ๋ณด๋์ค ๋ฒํธ๋ฅผ ์
๋ ฅ๋ฐ๋ ์ฑ
์์ ๊ฐ์ง๋๋ค.
+- `OutputView`: ๊ตฌ๋งค ๋ด์ญ, ๋น์ฒจ ํต๊ณ, ์์ต๋ฅ , ์๋ฌ ๋ฉ์์ง ๋ฑ ๋ชจ๋ ์ถ๋ ฅ ๋ด์ฉ์ ํ์์ ๋ง๊ฒ ๋ณด์ฌ์ฃผ๋ ์ฑ
์์ ๊ฐ์ง๋๋ค.
+- `InputValidator`: `InputView`๋ฅผ ํตํด ๋ค์ด์จ ์ฌ์ฉ์ ์
๋ ฅ ๊ฐ์ ํ์(์ซ์์ธ์ง, ์ผํ๋ก ๊ตฌ๋ถ๋๋์ง ๋ฑ)์ ๊ฒ์ฆํฉ๋๋ค.
+
+### **6๋จ๊ณ: ์ ํ๋ฆฌ์ผ์ด์
ํตํฉ ๋ฐ ์คํ**
+
+> ๊ตฌํ๋ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ์กฐ๋ฆฝํ์ฌ ํ๋ก๊ทธ๋จ์ ์์ฑํฉ๋๋ค.
+>
+- `LottoController`: ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์
์ ์คํ ํ๋ฆ(๋ก๋ ๊ตฌ๋งค โ ๋น์ฒจ ๋ฒํธ ์
๋ ฅ โ ๊ฒฐ๊ณผ ๋ฐํ)์ ์ ์ดํ๊ณ , ์์ธ ๋ฐ์ ์ ์ฌ์
๋ ฅ ๋ก์ง์ ์ฒ๋ฆฌํฉ๋๋ค.
+- `Application`: ํ๋ก๊ทธ๋จ์ ์์์ (`main` ๋ฉ์๋)์ผ๋ก, `LottoController`๋ฅผ ์์ฑํ๊ณ ์คํํฉ๋๋ค.
+
+### **7๋จ๊ณ: ๋ฆฌํฉํ ๋ง ๋ฐ ์ต์ข
๊ฒํ **
+
+> ์ฝ๋ ํ์ง์ ๊ฐ์ ํ๊ณ ์๊ตฌ์ฌํญ์ ์ต์ข
์ ๊ฒํฉ๋๋ค.
+>
+- `ValidationUtil`, `Retry` ๋ฑ ์ค๋ณต ๋ก์ง์ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ก ์ถ์ถํฉ๋๋ค.
+- ์ ์ฒด ์ฝ๋์ ๋ํด ํ๋ก๊ทธ๋๋ฐ ์ ์ฝ ์กฐ๊ฑด(๋ค์ฌ์ฐ๊ธฐ, ๋ฉ์๋ ๊ธธ์ด ๋ฑ) ์ค์ ์ฌ๋ถ๋ฅผ ๊ฒํ ํฉ๋๋ค.
+
+
+
+
+## ๐ ์์ธ ์ฒ๋ฆฌ
+
+์ฌ์ฉ์์ ์
๋ ฅ ์ค๋ฅ๋ก ์์ธ๊ฐ ๋ฐ์ํ๋ฉด **`[ERROR] ...` ๋ก ์์ํ๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ฌ์ฉ์์๊ฒ ์ถ๋ ฅํ๊ณ ํด๋น ์
๋ ฅ๋ถํฐ ๋ค์ ์
๋ ฅ์ ์งํํ ์ ์๋๋ก ํฉ๋๋ค.**
+
+์์ธ ์ฒ๋ฆฌ ๋ฉ์ธ์ง๋ ๊ตฌํํ๋ฉด์ ํ๋์ฉ ์ฑ์ ๋ฃ์ ์์ ์
๋๋ค.
+
+| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
+| --- | --- |
+| | |
+| | |
+| | |
+
+
+
+
+## โ๏ธ ๊ฐ๋ฐ ๋ฐ ๊ธฐ์ ์ ์ฝ
+
+- ์ด ํ๋ก๊ทธ๋จ์ **Java 21**์์ ์คํ๋์ด์ผ ํ๋ค.
+- ํ๋ก๊ทธ๋จ์ ์์์ ์ **`Application` ํด๋์ค์ `main()`** ๋ฉ์๋์ฌ์ผ ํ๋ค.
+- **์ ๊ณต๋ `build.gradle` ํ์ผ์ ์์ ํ ์ ์๋ค.** ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ์ง ์๋๋ค.
+- ๋ก๋ ๋ฒํธ ์์ฑ์ **`camp.nextstep.edu.missionutils.Randoms.pickUniqueNumbersInRange(1, 45, 6)`** ์ ์ฌ์ฉํ๋ค.
+- ์ฌ์ฉ์ ์
๋ ฅ์ **`camp.nextstep.edu.missionutils.Console.readLine()`** ์ผ๋ก๋ง ๋ฐ๋๋ค.
+- ํ๋ก๊ทธ๋จ ์ข
๋ฃ๋ฅผ ์ํด **`System.exit()`๋ฅผ ํธ์ถํด์๋ ์ ๋๋ค.**
+- ๋ค์ฌ์ฐ๊ธฐ๋ **2๋จ๊ณ ์ด๋ด**๋ก ์ ์งํ๋ค.
+- **`else` ๋ฌธ, `switch/case`, ์ผํญ ์ฐ์ฐ์**๋ ์ฌ์ฉํ์ง ์๋๋ค.
+- ํ๋์ ๋ฉ์๋๋ **ํ ๊ฐ์ง ์ผ๋ง** ํ๋๋ก ์์ฑํ๊ณ , **15์ค์ ๋๊ธฐ์ง ์๋๋ก** ํ๋ค.
+- ์ ๊ณต๋ `Lotto` ํด๋์ค์๋ **ํ๋๋ฅผ ์ถ๊ฐํ์ง ์๋๋ค.**
+
+
+
+
+## ๐ ๊ตฌํ ๊ธฐ๋ก / ๊ณ ๋ฏผ ์ ๋ณด
+
+๊ตฌํ ๊ณผ์ ์์ ๋ฐฐ์ฐ๊ณ ๊ณ ๋ฏผํ๋ ๊ฒ๋ค์ ๊ธฐ๋กํ๋ ๊ณต๊ฐ์
๋๋ค.
+
+- [๋๋ฉ์ธ ์ค๊ณ์ ๊ณ ๋ คํ๋ ๊ฒ](https://github.com/JohnPrk/java-lotto-8/issues/1)
+- **[Inside-Out vs Outside-In TDD ์ ํ ์ด์ ](**https://github.com/JohnPrk/java-lotto-8/issues/2**)**
+- **[Supplier๋ ๋ฌด์์ธ๊ฐ?](**https://github.com/JohnPrk/java-lotto-8/issues/3**)**
+- **[2023๋
๊ตฌํ vs ์ง๊ธ ๊ตฌํ ๋น๊ต[ํ๊ณ ]](**https://github.com/JohnPrk/java-lotto-8/issues/4**)**
+
+
+
From f6cf77a5dec468d9354f455210a1dbe963a05afb Mon Sep 17 00:00:00 2001
From: JohnPrk
Date: Sun, 2 Nov 2025 20:38:56 +0900
Subject: [PATCH 02/10] =?UTF-8?q?refactor:=20lotto.domain=20=ED=8C=A8?=
=?UTF-8?q?=ED=82=A4=EC=A7=80=EB=A1=9C=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?=
=?UTF-8?q?=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=81=B4=EB=9E=98?=
=?UTF-8?q?=EC=8A=A4=20=EC=9D=B4=EB=8F=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/main/java/lotto/{ => domain}/Lotto.java | 2 +-
src/test/java/lotto/{ => domain}/LottoTest.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
rename src/main/java/lotto/{ => domain}/Lotto.java (95%)
rename src/test/java/lotto/{ => domain}/LottoTest.java (97%)
diff --git a/src/main/java/lotto/Lotto.java b/src/main/java/lotto/domain/Lotto.java
similarity index 95%
rename from src/main/java/lotto/Lotto.java
rename to src/main/java/lotto/domain/Lotto.java
index 88fc5cf12b..d7797b2d7d 100644
--- a/src/main/java/lotto/Lotto.java
+++ b/src/main/java/lotto/domain/Lotto.java
@@ -1,4 +1,4 @@
-package lotto;
+package lotto.domain;
import java.util.List;
diff --git a/src/test/java/lotto/LottoTest.java b/src/test/java/lotto/domain/LottoTest.java
similarity index 97%
rename from src/test/java/lotto/LottoTest.java
rename to src/test/java/lotto/domain/LottoTest.java
index 309f4e50ae..2309a29ad5 100644
--- a/src/test/java/lotto/LottoTest.java
+++ b/src/test/java/lotto/domain/LottoTest.java
@@ -1,4 +1,4 @@
-package lotto;
+package lotto.domain;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
From a67a5728c99ca43eea22e780406cfb51bef6bbb3 Mon Sep 17 00:00:00 2001
From: JohnPrk
Date: Sun, 2 Nov 2025 20:59:20 +0900
Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=EA=B5=AC=EB=A7=A4=20=EA=B8=88?=
=?UTF-8?q?=EC=95=A1=EC=9D=84=20=ED=91=9C=ED=98=84=ED=95=98=EB=8A=94=20Mon?=
=?UTF-8?q?ey=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=ED=81=B4=EB=9E=98=EC=8A=A4?=
=?UTF-8?q?=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 1,000์ ๋จ์ ๊ฒ์ฆ
- 0์ ๋ฐ ์์ ๊ธ์ก ๋ฐฉ์ง๋ฅผ ์ํ ๊ฒ์ฆ
- ๊ตฌ๋งค ๊ฐ๋ฅํ ๋ก๋ ๊ฐ์ ๊ณ์ฐ
- IllegalArgumentException์ ํตํ ๋๋ฉ์ธ ์์ธ ์ฒ๋ฆฌ
- ์์ ๊ธฐ๋ฅ ๋จ์ ํ
์คํธ ์์ฑ
- README.md ์์ธ ์ฒ๋ฆฌ ํ์ Money ๊ด๋ จ ์์ธ ๋ฉ์์ง ์ถ๊ฐ
---
README.md | 57 ++++++++++++++---------
src/main/java/lotto/domain/Money.java | 29 ++++++++++++
src/test/java/lotto/domain/MoneyTest.java | 53 +++++++++++++++++++++
3 files changed, 117 insertions(+), 22 deletions(-)
create mode 100644 src/main/java/lotto/domain/Money.java
create mode 100644 src/test/java/lotto/domain/MoneyTest.java
diff --git a/README.md b/README.md
index a71d9a7ea2..2b621907dc 100644
--- a/README.md
+++ b/README.md
@@ -103,17 +103,17 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
## **๐งฑ ๊ฐ์ฒด ์ญํ ์์ฝ**
-| ๊ฐ์ฒด ์ด๋ฆ | ์ญํ (์ฑ
์) | ๋ณด์ ๊ฐ(์ํ) | ์ฃผ์ ํ์ |
-| --- | --- | --- | --- |
-| `Money` | ๊ตฌ์
๊ธ์ก์ ํํํ๊ณ ๊ด๋ จ ๊ท์น์ ๊ฒ์ฆํ๋ ๊ฐ ๊ฐ์ฒด | * ๊ตฌ์
๊ธ์ก | - ๊ธ์ก ์ ํจ์ฑ ๊ฒ์ฌ, ๊ตฌ๋งค ๊ฐ๋ฅํ ๋ก๋ ์ ๊ณ์ฐ |
-| `Lotto` | ๋ก๋ ํ ์ฅ์ ํํํ๋ฉฐ ๋ฒํธ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ๋ถ๋ณ์ฑ์ ๋ณด์ฅ | * 6๊ฐ์ ๋ก๋ ๋ฒํธ | - ๋ฒํธ ์ ๋ ฌ ๋ฐ ์ค๋ณต ๊ฒ์ฌ, ๋น์ฒจ ๋ฒํธ์ ์ผ์น ๊ฐ์ ๊ณ์ฐ, ๋ณด๋์ค ํฌํจ ์ฌ๋ถ ํ์ธ |
-| `LottoFactory` | ๋ก๋ ๊ท์น์ ๋ง๋ ๋๋ค ๋ฒํธ๋ฅผ ์์ฑํ์ฌย `Lotto`ย ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ์ฑ
์์ ์ง | | -`Randoms.pickUniqueNumbersInRange()`๋ฅผ ์ฌ์ฉํด ๋ก๋ ๋ฒํธ ์์ฑ |
-| `WinningNumbers` | ๋น์ฒจ ๋ฒํธ์ ๋ณด๋์ค ๋ฒํธ๋ฅผ ๊ฐ์ง๋ฉฐ ๊ด๋ จ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ์ฑ
์์ง | * 6๊ฐ ๋น์ฒจ ๋ฒํธ, 1๊ฐ ๋ณด๋์ค ๋ฒํธ | - ๋น์ฒจ ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ, ๋ณด๋์ค ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์ค๋ณต ํ์ธ |
-| `LottoRank` | ๋น์ฒจ ๋ฑ์(1~5๋ฑ, ๊ฝ)์ ์กฐ๊ฑด(์ผ์น ๊ฐ์, ๋ณด๋์ค)๊ณผ ์๊ธ์ ์ ์ | *Enum class(์ผ์น ๊ฐ์, ๋ณด๋์ค ํฌํจ์ฌ๋ถ,๋น์ฒจ ๊ธ์ก) | - ์ผ์น ์/๋ณด๋์ค ํฌํจ ์ฌ๋ถ๋ก ๋ฑ์ ๋ฐํ, ์๊ธ ๋ฐํ |
-| `LottoResults` | ์ ์ฒด ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐ | * ๋ฑ์๋ณ ๋น์ฒจ ํ์, ์ด ์์ต๋ฅ , ๋์ ์๊ธ | - ๊ฐ ๋ก๋์ ๋ํ ๋ฑ์ ๊ณ์ฐ, ๋น์ฒจ ๊ฒฐ๊ณผ ๋์ , ์์ต๋ฅ ๊ณ์ฐ |
-| `InputView` | ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์
๋ ฅ ์ ๋์ฌ | - ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ์, `camp.nextstep.edu.missionutils.Console`์ย `readLine()`์ ์ฌ์ฉ |
-| `OutputView` | ์ฌ์ฉ์์๊ฒ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์ถ๋ ฅ ์ ๋์ฌ | - ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก ์ถ๋ ฅ, ๋น์ฒจ ๊ฒฐ๊ณผ ์ถ๋ ฅ, ์์ต๋ฅ ์ถ๋ ฅ |
-| `LottoController` | ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฒด ์คํ ํ๋ฆ์ ์กฐ์จ. View์ Domain ๊ฐ์ฒด๋ค์ ์ฐ๊ฒฐ | | - ์ ์ฒด ํ๋ฆ ์ ์ด |
+| ๊ฐ์ฒด ์ด๋ฆ | ์ญํ (์ฑ
์) | ๋ณด์ ๊ฐ(์ํ) | ์ฃผ์ ํ์ |
+|-------------------|---------------------------------------------|------------------------------------|-----------------------------------------------------------------------------|
+| `Money` | ๊ตฌ์
๊ธ์ก์ ํํํ๊ณ ๊ด๋ จ ๊ท์น์ ๊ฒ์ฆํ๋ ๊ฐ ๊ฐ์ฒด | * ๊ตฌ์
๊ธ์ก | - ๊ธ์ก ์ ํจ์ฑ ๊ฒ์ฌ, ๊ตฌ๋งค ๊ฐ๋ฅํ ๋ก๋ ์ ๊ณ์ฐ |
+| `Lotto` | ๋ก๋ ํ ์ฅ์ ํํํ๋ฉฐ ๋ฒํธ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ๋ถ๋ณ์ฑ์ ๋ณด์ฅ | * 6๊ฐ์ ๋ก๋ ๋ฒํธ | - ๋ฒํธ ์ ๋ ฌ ๋ฐ ์ค๋ณต ๊ฒ์ฌ, ๋น์ฒจ ๋ฒํธ์ ์ผ์น ๊ฐ์ ๊ณ์ฐ, ๋ณด๋์ค ํฌํจ ์ฌ๋ถ ํ์ธ |
+| `LottoFactory` | ๋ก๋ ๊ท์น์ ๋ง๋ ๋๋ค ๋ฒํธ๋ฅผ ์์ฑํ์ฌย `Lotto`ย ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ์ฑ
์์ ์ง | | -`Randoms.pickUniqueNumbersInRange()`๋ฅผ ์ฌ์ฉํด ๋ก๋ ๋ฒํธ ์์ฑ |
+| `WinningNumbers` | ๋น์ฒจ ๋ฒํธ์ ๋ณด๋์ค ๋ฒํธ๋ฅผ ๊ฐ์ง๋ฉฐ ๊ด๋ จ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ์ฑ
์์ง | * 6๊ฐ ๋น์ฒจ ๋ฒํธ, 1๊ฐ ๋ณด๋์ค ๋ฒํธ | - ๋น์ฒจ ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ, ๋ณด๋์ค ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์ค๋ณต ํ์ธ |
+| `LottoRank` | ๋น์ฒจ ๋ฑ์(1~5๋ฑ, ๊ฝ)์ ์กฐ๊ฑด(์ผ์น ๊ฐ์, ๋ณด๋์ค)๊ณผ ์๊ธ์ ์ ์ | *Enum class(์ผ์น ๊ฐ์, ๋ณด๋์ค ํฌํจ์ฌ๋ถ,๋น์ฒจ ๊ธ์ก) | - ์ผ์น ์/๋ณด๋์ค ํฌํจ ์ฌ๋ถ๋ก ๋ฑ์ ๋ฐํ, ์๊ธ ๋ฐํ |
+| `LottoResults` | ์ ์ฒด ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐ | * ๋ฑ์๋ณ ๋น์ฒจ ํ์, ์ด ์์ต๋ฅ , ๋์ ์๊ธ | - ๊ฐ ๋ก๋์ ๋ํ ๋ฑ์ ๊ณ์ฐ, ๋น์ฒจ ๊ฒฐ๊ณผ ๋์ , ์์ต๋ฅ ๊ณ์ฐ |
+| `InputView` | ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์
๋ ฅ ์ ๋์ฌ | - ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ์, `camp.nextstep.edu.missionutils.Console`์ย `readLine()`์ ์ฌ์ฉ |
+| `OutputView` | ์ฌ์ฉ์์๊ฒ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์ถ๋ ฅ ์ ๋์ฌ | - ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก ์ถ๋ ฅ, ๋น์ฒจ ๊ฒฐ๊ณผ ์ถ๋ ฅ, ์์ต๋ฅ ์ถ๋ ฅ |
+| `LottoController` | ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฒด ์คํ ํ๋ฆ์ ์กฐ์จ. View์ Domain ๊ฐ์ฒด๋ค์ ์ฐ๊ฒฐ | | - ์ ์ฒด ํ๋ฆ ์ ์ด |
@@ -123,33 +123,38 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
### **1๋จ๊ณ: ํต์ฌ ๋๋ฉ์ธ ๋ชจ๋ธ ๊ตฌํ**
> ๋น์ฆ๋์ค์ ๊ฐ์ฅ ๋ณธ์ง์ ์ธ ๊ท์น๊ณผ ๋ฐ์ดํฐ๋ฅผ ์ ์ํ๊ณ ํ
์คํธํฉ๋๋ค.
->
+>
+
- `Money`: ๊ธ์ก์ ํํํ๊ณ , 1,000์ ๋จ์ ๊ฒ์ฆ ๋ฐ ๋ก๋ ๊ตฌ๋งค ๊ฐ๋ฅ ๊ฐ์ ๊ณ์ฐ ์ฑ
์์ ๊ฐ์ง๋๋ค.
- `Lotto`: ๋ก๋ ํ ์ฅ(6๊ฐ ๋ฒํธ)์ ํํํ๋ฉฐ, ๋ฒํธ ๊ฐ์, ๋ฒ์, ์ค๋ณต ๋ฑ ๊ท์น์ ๋ถ๋ณ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
### **2๋จ๊ณ: ๋น์ฒจ ๊ท์น ๋ฐ ํ์ ๋ก์ง ๊ตฌํ**
> ๋น์ฒจ์ ๊ฒฐ์ ํ๋ ๊ธฐ์ค๊ณผ ๋ก์ง์ ๊ตฌํํฉ๋๋ค.
->
+>
+
- `WinningNumbers`: ๋น์ฒจ ๋ฒํธ(6๊ฐ)์ ๋ณด๋์ค ๋ฒํธ(1๊ฐ)๋ฅผ ๊ฐ์ง๋ฉฐ, ๊ด๋ จ๋ ์ ํจ์ฑ ๊ฒ์ฆ ์ฑ
์์ ๊ฐ์ง๋๋ค.
- `LottoRank`: 5๊ฐ ๋ฑ์์ '๊ฝ'์ ๋ํ ์กฐ๊ฑด(์ผ์น ๊ฐ์, ๋ณด๋์ค ์ฌ๋ถ)๊ณผ ์๊ธ์ `enum`์ผ๋ก ์ ์ํฉ๋๋ค. **(๋ฑ์ ํ์ ๋ก์ง ํฌํจ)**
### **3๋จ๊ณ: ๊ฒฐ๊ณผ ์ง๊ณ ๋ฐ ๋ถ์ ๋ก์ง ๊ตฌํ**
> ๊ตฌ๋งคํ ๋ก๋๋ค์ ๊ฒฐ๊ณผ๋ฅผ ์ข
ํฉํ์ฌ ํต๊ณ๋ฅผ ๋ด๋ ์ฑ
์์ ๊ตฌํํฉ๋๋ค.
->
+>
+
- `LottoResults`: ๊ตฌ๋งคํ ๋ชจ๋ `Lotto`์ `WinningNumbers`๋ฅผ ๋น๊ตํ์ฌ, ๋ฑ์๋ณ ๋น์ฒจ ํ์๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐํฉ๋๋ค.
### **4๋จ๊ณ: ๋ก๋ ์์ฑ ๋ก์ง ๊ตฌํ**
> ๋๋ฉ์ธ ๊ท์น์ ๋ฐ๋ผ ๋ก๋๋ฅผ ์์ฑํ๋ ์ฑ
์์ ๊ตฌํํฉ๋๋ค.
->
+>
+
- `LottoFactory`: `Randoms` ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๋ ๋ฒํธ๋ฅผ ์์ฑํ๊ณ , ๊ฒ์ฆ๋ `Lotto` ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ฐํํฉ๋๋ค.
### **5๋จ๊ณ: ์
์ถ๋ ฅ(UI) ๊ณ์ธต ๊ตฌํ**
> ์ฌ์ฉ์์ ์ํธ์์ฉํ๋ ๋ถ๋ถ์ ๊ตฌํํฉ๋๋ค.
->
+>
+
- `InputView`: ์ฌ์ฉ์๋ก๋ถํฐ ๊ตฌ์
๊ธ์ก, ๋น์ฒจ ๋ฒํธ, ๋ณด๋์ค ๋ฒํธ๋ฅผ ์
๋ ฅ๋ฐ๋ ์ฑ
์์ ๊ฐ์ง๋๋ค.
- `OutputView`: ๊ตฌ๋งค ๋ด์ญ, ๋น์ฒจ ํต๊ณ, ์์ต๋ฅ , ์๋ฌ ๋ฉ์์ง ๋ฑ ๋ชจ๋ ์ถ๋ ฅ ๋ด์ฉ์ ํ์์ ๋ง๊ฒ ๋ณด์ฌ์ฃผ๋ ์ฑ
์์ ๊ฐ์ง๋๋ค.
- `InputValidator`: `InputView`๋ฅผ ํตํด ๋ค์ด์จ ์ฌ์ฉ์ ์
๋ ฅ ๊ฐ์ ํ์(์ซ์์ธ์ง, ์ผํ๋ก ๊ตฌ๋ถ๋๋์ง ๋ฑ)์ ๊ฒ์ฆํฉ๋๋ค.
@@ -157,14 +162,16 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
### **6๋จ๊ณ: ์ ํ๋ฆฌ์ผ์ด์
ํตํฉ ๋ฐ ์คํ**
> ๊ตฌํ๋ ๋ชจ๋ ๊ฐ์ฒด๋ฅผ ์กฐ๋ฆฝํ์ฌ ํ๋ก๊ทธ๋จ์ ์์ฑํฉ๋๋ค.
->
+>
+
- `LottoController`: ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์
์ ์คํ ํ๋ฆ(๋ก๋ ๊ตฌ๋งค โ ๋น์ฒจ ๋ฒํธ ์
๋ ฅ โ ๊ฒฐ๊ณผ ๋ฐํ)์ ์ ์ดํ๊ณ , ์์ธ ๋ฐ์ ์ ์ฌ์
๋ ฅ ๋ก์ง์ ์ฒ๋ฆฌํฉ๋๋ค.
- `Application`: ํ๋ก๊ทธ๋จ์ ์์์ (`main` ๋ฉ์๋)์ผ๋ก, `LottoController`๋ฅผ ์์ฑํ๊ณ ์คํํฉ๋๋ค.
### **7๋จ๊ณ: ๋ฆฌํฉํ ๋ง ๋ฐ ์ต์ข
๊ฒํ **
> ์ฝ๋ ํ์ง์ ๊ฐ์ ํ๊ณ ์๊ตฌ์ฌํญ์ ์ต์ข
์ ๊ฒํฉ๋๋ค.
->
+>
+
- `ValidationUtil`, `Retry` ๋ฑ ์ค๋ณต ๋ก์ง์ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ก ์ถ์ถํฉ๋๋ค.
- ์ ์ฒด ์ฝ๋์ ๋ํด ํ๋ก๊ทธ๋๋ฐ ์ ์ฝ ์กฐ๊ฑด(๋ค์ฌ์ฐ๊ธฐ, ๋ฉ์๋ ๊ธธ์ด ๋ฑ) ์ค์ ์ฌ๋ถ๋ฅผ ๊ฒํ ํฉ๋๋ค.
@@ -178,10 +185,16 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
์์ธ ์ฒ๋ฆฌ ๋ฉ์ธ์ง๋ ๊ตฌํํ๋ฉด์ ํ๋์ฉ ์ฑ์ ๋ฃ์ ์์ ์
๋๋ค.
| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
-| --- | --- |
-| | |
-| | |
-| | |
+|-------|--------|
+
+## ๐ ์์ธ ์ฒ๋ฆฌ
+
+์ฌ์ฉ์์ ์
๋ ฅ ์ค๋ฅ๋ก ์์ธ๊ฐ ๋ฐ์ํ๋ฉด **`[ERROR] ...` ๋ก ์์ํ๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ฌ์ฉ์์๊ฒ ์ถ๋ ฅํ๊ณ ํด๋น ์
๋ ฅ๋ถํฐ ๋ค์ ์
๋ ฅ์ ์งํํ ์ ์๋๋ก ํฉ๋๋ค.**
+
+| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
+|-------------------------|-------------------------------|
+| ๊ตฌ์
๊ธ์ก์ด 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.` |
+| ๊ตฌ์
๊ธ์ก์ด 1,000์ ๋จ์๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] 1,000์ ๋จ์๋ก ์
๋ ฅํด ์ฃผ์ธ์.` |
diff --git a/src/main/java/lotto/domain/Money.java b/src/main/java/lotto/domain/Money.java
new file mode 100644
index 0000000000..a564f220e7
--- /dev/null
+++ b/src/main/java/lotto/domain/Money.java
@@ -0,0 +1,29 @@
+package lotto.domain;
+
+public class Money {
+
+ private static final int UNIT_MONEY_FOR_BUY_LOTTO = 1000;
+ private final int amount;
+
+ public Money(int amount) {
+ validatePositive(amount);
+ validateUnit(amount);
+ this.amount = amount;
+ }
+
+ private void validatePositive(int amount) {
+ if (amount <= 0) {
+ throw new IllegalArgumentException("[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.");
+ }
+ }
+
+ private void validateUnit(int amount) {
+ if (amount % UNIT_MONEY_FOR_BUY_LOTTO != 0) {
+ throw new IllegalArgumentException("[ERROR] 1,000์ ๋จ์๋ก ์
๋ ฅํด ์ฃผ์ธ์.");
+ }
+ }
+
+ public int getLottoCount() {
+ return amount / UNIT_MONEY_FOR_BUY_LOTTO;
+ }
+}
diff --git a/src/test/java/lotto/domain/MoneyTest.java b/src/test/java/lotto/domain/MoneyTest.java
new file mode 100644
index 0000000000..f28728b1dc
--- /dev/null
+++ b/src/test/java/lotto/domain/MoneyTest.java
@@ -0,0 +1,53 @@
+package lotto.domain;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class MoneyTest {
+
+ private static final int UNIT_MONEY_FOR_BUY_LOTTO = 1000;
+
+ @ParameterizedTest
+ @ValueSource(ints = {1000, 5000, 1000000000})
+ void ๋ก๋_๊ตฌ๋งค_๊ธ์ก์ด_์ฒ_์์ผ๋ก_๋๋ ์ง๋ฉด_Money_๊ฐ์ฒด๊ฐ_์์ฑ๋๋ค(int amount) {
+ // when
+ Money money = new Money(amount);
+
+ // then
+ assertThat(money).isNotNull();
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {500, 1100, 2500})
+ void ๋ก๋_๊ตฌ๋งค_๊ธ์ก์ด_์ฒ_์์ผ๋ก_๋๋ ์ง์ง_์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(int amount) {
+ // when & then
+ assertThatThrownBy(() -> new Money(amount))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] 1,000์ ๋จ์๋ก ์
๋ ฅํด ์ฃผ์ธ์.");
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, -1000, -5000})
+ void ๋ก๋_๊ตฌ๋งค_๊ธ์ก์ด_0์_์ดํ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(int amount) {
+ // when & then
+ assertThatThrownBy(() -> new Money(amount))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.");
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {1000, 3000, 100000})
+ void ๋ก๋_๊ตฌ๋งค_๊ธ์ก์_์
๋ ฅํ๋ฉด_๊ตฌ๋งค_๊ฐ๋ฅํ_๋ก๋_๊ฐ์๋ฅผ_๋ฐํํ๋ค(int amount) {
+ // given
+ Money money = new Money(amount);
+
+ // when
+ int count = money.getLottoCount();
+
+ // then
+ assertThat(count).isEqualTo(amount / UNIT_MONEY_FOR_BUY_LOTTO);
+ }
+}
From 8679601c33afb5a632bcc063edb9cbc72a479961 Mon Sep 17 00:00:00 2001
From: JohnPrk
Date: Sun, 2 Nov 2025 22:02:28 +0900
Subject: [PATCH 04/10] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=ED=95=9C=20?=
=?UTF-8?q?=EC=9E=A5=EC=9D=84=20=ED=91=9C=ED=98=84=ED=95=98=EB=8A=94=20Lot?=
=?UTF-8?q?to=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=ED=81=B4=EB=9E=98=EC=8A=A4?=
=?UTF-8?q?=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- ๋ก๋ ๋ฒํธ ๊ฐ์(6๊ฐ) ๊ฒ์ฆ
- ๋ก๋ ๋ฒํธ ๋ฒ์(1~45) ๊ฒ์ฆ
- ๋ก๋ ๋ฒํธ ์ค๋ณต ๊ฒ์ฆ
- ๋ก๋ ๋ฒํธ ์ค๋ฆ์ฐจ์ ์๋ ์ ๋ ฌ ๋ฐ ๋ถ๋ณ ๋ฆฌ์คํธ ์ ์ฅ
- IllegalArgumentException์ ํตํ ๋๋ฉ์ธ ์์ธ ์ฒ๋ฆฌ
- ์์ ๊ฒ์ฆ ๋ฐ ๊ธฐ๋ฅ ๋จ์ ํ
์คํธ ์์ฑ
- README.md ์์ธ ์ฒ๋ฆฌ ํ์ Lotto ๊ด๋ จ ์์ธ ๋ฉ์์ง ์ถ๊ฐ
---
README.md | 11 ++-
src/main/java/lotto/domain/Lotto.java | 41 +++++++++--
src/test/java/lotto/domain/LottoTest.java | 90 +++++++++++++++++++++--
3 files changed, 125 insertions(+), 17 deletions(-)
diff --git a/README.md b/README.md
index 2b621907dc..4da6696200 100644
--- a/README.md
+++ b/README.md
@@ -191,10 +191,13 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
์ฌ์ฉ์์ ์
๋ ฅ ์ค๋ฅ๋ก ์์ธ๊ฐ ๋ฐ์ํ๋ฉด **`[ERROR] ...` ๋ก ์์ํ๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ฌ์ฉ์์๊ฒ ์ถ๋ ฅํ๊ณ ํด๋น ์
๋ ฅ๋ถํฐ ๋ค์ ์
๋ ฅ์ ์งํํ ์ ์๋๋ก ํฉ๋๋ค.**
-| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
-|-------------------------|-------------------------------|
-| ๊ตฌ์
๊ธ์ก์ด 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.` |
-| ๊ตฌ์
๊ธ์ก์ด 1,000์ ๋จ์๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] 1,000์ ๋จ์๋ก ์
๋ ฅํด ์ฃผ์ธ์.` |
+| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
+|-------------------------|-----------------------------------|
+| ๊ตฌ์
๊ธ์ก์ด 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.` |
+| ๊ตฌ์
๊ธ์ก์ด 1,000์ ๋จ์๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] 1,000์ ๋จ์๋ก ์
๋ ฅํด ์ฃผ์ธ์.` |
+| ๋ก๋ ๋ฒํธ๊ฐ 6๊ฐ๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 6๊ฐ์ฌ์ผ ํฉ๋๋ค.` |
+| ๋ก๋ ๋ฒํธ์ ์ค๋ณต์ด ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
+| ๋ก๋ ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
diff --git a/src/main/java/lotto/domain/Lotto.java b/src/main/java/lotto/domain/Lotto.java
index d7797b2d7d..f390874d89 100644
--- a/src/main/java/lotto/domain/Lotto.java
+++ b/src/main/java/lotto/domain/Lotto.java
@@ -1,20 +1,51 @@
package lotto.domain;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
public class Lotto {
+
+ private static final int LOTTO_SIZE = 6;
+ private static final int MIN_NUMBER = 1;
+ private static final int MAX_NUMBER = 45;
private final List numbers;
public Lotto(List numbers) {
- validate(numbers);
- this.numbers = numbers;
+ validateCount(numbers);
+ validateRange(numbers);
+ validateDuplicate(numbers);
+ this.numbers = sort(numbers);
+ }
+
+ public List getNumbers() {
+ return numbers;
}
- private void validate(List numbers) {
- if (numbers.size() != 6) {
+ private void validateCount(List numbers) {
+ if (numbers.size() != LOTTO_SIZE) {
throw new IllegalArgumentException("[ERROR] ๋ก๋ ๋ฒํธ๋ 6๊ฐ์ฌ์ผ ํฉ๋๋ค.");
}
}
- // TODO: ์ถ๊ฐ ๊ธฐ๋ฅ ๊ตฌํ
+ private void validateRange(List numbers) {
+ for (int number : numbers) {
+ if (number < MIN_NUMBER || number > MAX_NUMBER) {
+ throw new IllegalArgumentException("[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.");
+ }
+ }
+ }
+
+ private void validateDuplicate(List numbers) {
+ Set unique = new HashSet<>(numbers);
+ if (unique.size() != numbers.size()) {
+ throw new IllegalArgumentException("[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.");
+ }
+ }
+
+ private List sort(List numbers) {
+ return numbers.stream()
+ .sorted()
+ .toList();
+ }
}
diff --git a/src/test/java/lotto/domain/LottoTest.java b/src/test/java/lotto/domain/LottoTest.java
index 2309a29ad5..89d41a2c6e 100644
--- a/src/test/java/lotto/domain/LottoTest.java
+++ b/src/test/java/lotto/domain/LottoTest.java
@@ -1,25 +1,99 @@
package lotto.domain;
-import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class LottoTest {
+
+ @Test
+ void ๋ก๋_๋ฒํธ๊ฐ_6๊ฐ๋ณด๋ค_๋ง์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+
+ // given
+ List numbers = List.of(1, 2, 3, 4, 5, 6, 7);
+
+ // when & then
+ assertThatThrownBy(() -> new Lotto(numbers))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ 6๊ฐ์ฌ์ผ ํฉ๋๋ค.");
+ }
+
@Test
- void ๋ก๋_๋ฒํธ์_๊ฐ์๊ฐ_6๊ฐ๊ฐ_๋์ด๊ฐ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
- assertThatThrownBy(() -> new Lotto(List.of(1, 2, 3, 4, 5, 6, 7)))
- .isInstanceOf(IllegalArgumentException.class);
+ void ๋ก๋_๋ฒํธ๊ฐ_6๊ฐ๋ณด๋ค_์ ์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+
+ // given
+ List numbers = List.of(1, 2, 3, 4, 5);
+
+ // when & then
+ assertThatThrownBy(() -> new Lotto(numbers))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ 6๊ฐ์ฌ์ผ ํฉ๋๋ค.");
}
- @DisplayName("๋ก๋ ๋ฒํธ์ ์ค๋ณต๋ ์ซ์๊ฐ ์์ผ๋ฉด ์์ธ๊ฐ ๋ฐ์ํ๋ค.")
@Test
void ๋ก๋_๋ฒํธ์_์ค๋ณต๋_์ซ์๊ฐ_์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
- assertThatThrownBy(() -> new Lotto(List.of(1, 2, 3, 4, 5, 5)))
- .isInstanceOf(IllegalArgumentException.class);
+
+ // given
+ List numbers = List.of(1, 2, 3, 4, 5, 5);
+
+ // when & then
+ assertThatThrownBy(() -> new Lotto(numbers))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.");
+ }
+
+ @Test
+ void ๋ก๋_๋ฒํธ๊ฐ_1๋ณด๋ค_์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+
+ // given
+ List numbers = List.of(0, 2, 3, 4, 5, 6);
+
+ // when & then
+ assertThatThrownBy(() -> new Lotto(numbers))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.");
}
- // TODO: ์ถ๊ฐ ๊ธฐ๋ฅ ๊ตฌํ์ ๋ฐ๋ฅธ ํ
์คํธ ์ฝ๋ ์์ฑ
+ @Test
+ void ๋ก๋_๋ฒํธ๊ฐ_45๋ณด๋ค_ํฌ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+
+ // given
+ List numbers = List.of(1, 2, 3, 4, 5, 46);
+
+ // when & then
+ assertThatThrownBy(() -> new Lotto(numbers))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.");
+ }
+
+ @Test
+ void ์ฌ๋ฐ๋ฅธ_๋ก๋_๋ฒํธ_6๊ฐ๋ฉด_๋ก๋_๊ฐ์ฒด๊ฐ_์์ฑ๋๋ค() {
+
+ // given
+ List numbers = List.of(8, 1, 45, 3, 20, 10);
+
+ // when
+ Lotto lotto = new Lotto(numbers);
+
+ // then
+ assertThat(lotto).isNotNull();
+ }
+
+ @Test
+ void ๋ก๋_๋ฒํธ๋_์ค๋ฆ์ฐจ์์ผ๋ก_์ ๋ ฌ๋์ด_์ ์ฅ๋๋ค() {
+
+ // given
+ List numbers = List.of(8, 1, 45, 3, 20, 10);
+
+ // when
+ Lotto lotto = new Lotto(numbers);
+
+ // then
+ assertThat(lotto).isNotNull();
+ assertThat(lotto.getNumbers())
+ .containsExactly(1, 3, 8, 10, 20, 45);
+ }
}
From e61d56cab3019a0da8e5f911381b39a9cc17c4a9 Mon Sep 17 00:00:00 2001
From: JohnPrk
Date: Mon, 3 Nov 2025 01:42:04 +0900
Subject: [PATCH 05/10] =?UTF-8?q?feat:=20=EB=8B=B9=EC=B2=A8=20=EB=B2=88?=
=?UTF-8?q?=ED=98=B8=EC=99=80=20=EB=B3=B4=EB=84=88=EC=8A=A4=20=EB=B2=88?=
=?UTF-8?q?=ED=98=B8=EB=A5=BC=20=EA=B0=80=EC=A7=80=EB=8A=94=20WinningNumbe?=
=?UTF-8?q?rs=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=ED=81=B4=EB=9E=98=EC=8A=A4?=
=?UTF-8?q?=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20Lotto=20=ED=81=B4=EB=9E=98?=
=?UTF-8?q?=EC=8A=A4=20=ED=99=95=EC=9E=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Lotto๋ฅผ ํ์ฉํด ๋น์ฒจ ๋ฒํธ ๋ถ๋ณ์ฑ(๊ฐ์ 6๊ฐ, 1~45 ๋ฒ์, ์ค๋ณต ๋ถ๊ฐ) ์ ํ ๊ฒ์ฆ
- ๋ณด๋์ค ๋ฒํธ ๋ฒ์(1~45) ๋ฐ ๋น์ฒจ ๋ฒํธ์์ ์ค๋ณต ๊ฒ์ฆ
- ๊ตฌ๋งคํ ๋ก๋์์ ์ผ์น ๊ฐ์ ์กฐํ
- ๊ตฌ๋งคํ ๋ก๋๊ฐ ๋ณด๋์ค ๋ฒํธ๋ฅผ ํฌํจํ๋์ง ์ฌ๋ถ ํ์ธ
- [Lotto ํ์ฅ] ์์ฑ์์์ null ๋ฐฉ์ด
- [Lotto ํ์ฅ] ๋ฒํธ ํฌํจ ์ฌ๋ถ ์กฐํ
- [Lotto ํ์ฅ] ๋น๊ต ๋์ ๋ก๋๊ฐ null์ผ ๋ ์์ธ ๋ฐ์ํ๋๋ก ๋ฐฉ์ด
- ๋ก๋ ๋ฒํธ ๋ชฉ๋ก์ ๋ถ๋ณ ๋ฆฌ์คํธ๋ก ๋
ธ์ถํ๋๋ก ๋ณ๊ฒฝํด ์บก์ํ ๊ฐํ
- WinningNumbersTest, LottoTest์ ๊ฒฝ๊ณ๊ฐ/์ค๋ณต/null ๊ฒ์ฆ ๋ฐ ๊ธฐ๋ฅ ๋จ์ ํ
์คํธ ์ถ๊ฐ
- README.md ์์ธ ์ฒ๋ฆฌ ํ์ Lotto/WinningNumbers ๊ด๋ จ ์์ธ ๋ฉ์์ง ์ถ๊ฐ
---
README.md | 27 ++---
src/main/java/lotto/domain/Lotto.java | 39 ++++++-
.../java/lotto/domain/WinningNumbers.java | 45 ++++++++
src/test/java/lotto/domain/LottoTest.java | 106 +++++++++++++++---
.../java/lotto/domain/WinningNumbersTest.java | 106 ++++++++++++++++++
5 files changed, 287 insertions(+), 36 deletions(-)
create mode 100644 src/main/java/lotto/domain/WinningNumbers.java
create mode 100644 src/test/java/lotto/domain/WinningNumbersTest.java
diff --git a/README.md b/README.md
index 4da6696200..c2db501433 100644
--- a/README.md
+++ b/README.md
@@ -182,22 +182,17 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
์ฌ์ฉ์์ ์
๋ ฅ ์ค๋ฅ๋ก ์์ธ๊ฐ ๋ฐ์ํ๋ฉด **`[ERROR] ...` ๋ก ์์ํ๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ฌ์ฉ์์๊ฒ ์ถ๋ ฅํ๊ณ ํด๋น ์
๋ ฅ๋ถํฐ ๋ค์ ์
๋ ฅ์ ์งํํ ์ ์๋๋ก ํฉ๋๋ค.**
-์์ธ ์ฒ๋ฆฌ ๋ฉ์ธ์ง๋ ๊ตฌํํ๋ฉด์ ํ๋์ฉ ์ฑ์ ๋ฃ์ ์์ ์
๋๋ค.
-
-| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
-|-------|--------|
-
-## ๐ ์์ธ ์ฒ๋ฆฌ
-
-์ฌ์ฉ์์ ์
๋ ฅ ์ค๋ฅ๋ก ์์ธ๊ฐ ๋ฐ์ํ๋ฉด **`[ERROR] ...` ๋ก ์์ํ๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ฌ์ฉ์์๊ฒ ์ถ๋ ฅํ๊ณ ํด๋น ์
๋ ฅ๋ถํฐ ๋ค์ ์
๋ ฅ์ ์งํํ ์ ์๋๋ก ํฉ๋๋ค.**
-
-| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
-|-------------------------|-----------------------------------|
-| ๊ตฌ์
๊ธ์ก์ด 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.` |
-| ๊ตฌ์
๊ธ์ก์ด 1,000์ ๋จ์๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] 1,000์ ๋จ์๋ก ์
๋ ฅํด ์ฃผ์ธ์.` |
-| ๋ก๋ ๋ฒํธ๊ฐ 6๊ฐ๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 6๊ฐ์ฌ์ผ ํฉ๋๋ค.` |
-| ๋ก๋ ๋ฒํธ์ ์ค๋ณต์ด ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
-| ๋ก๋ ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
+| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
+|-------------------------|--------------------------------------|
+| ๊ตฌ์
๊ธ์ก์ด 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.` |
+| ๊ตฌ์
๊ธ์ก์ด 1,000์ ๋จ์๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] 1,000์ ๋จ์๋ก ์
๋ ฅํด ์ฃผ์ธ์.` |
+| ๋ก๋ ๋ฒํธ ๋ฆฌ์คํธ๊ฐ null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ null์ผ ์ ์์ต๋๋ค.` |
+| ๋น๊ตํ ๋ก๋ ๋ฒํธ ๋ฆฌ์คํธ๊ฐ null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋น๊ตํ ๋ก๋๊ฐ null์ผ ์ ์์ต๋๋ค.` |
+| ๋ก๋ ๋ฒํธ๊ฐ 6๊ฐ๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 6๊ฐ์ฌ์ผ ํฉ๋๋ค.` |
+| ๋ก๋ ๋ฒํธ์ ์ค๋ณต์ด ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
+| ๋ก๋ ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
+| ๋ณด๋์ค ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
+| ๋ณด๋์ค ๋ฒํธ๊ฐ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
diff --git a/src/main/java/lotto/domain/Lotto.java b/src/main/java/lotto/domain/Lotto.java
index f390874d89..18bdc0ef86 100644
--- a/src/main/java/lotto/domain/Lotto.java
+++ b/src/main/java/lotto/domain/Lotto.java
@@ -1,8 +1,10 @@
package lotto.domain;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
public class Lotto {
@@ -12,14 +14,39 @@ public class Lotto {
private final List numbers;
public Lotto(List numbers) {
+ validateNotNull(numbers);
validateCount(numbers);
validateRange(numbers);
validateDuplicate(numbers);
- this.numbers = sort(numbers);
+ this.numbers = sortNumbers(numbers);
}
public List getNumbers() {
- return numbers;
+ return Collections.unmodifiableList(numbers);
+ }
+
+ public boolean containsNumber(int number) {
+ return numbers.contains(number);
+ }
+
+ public int countMatchingNumbers(Lotto otherLotto) {
+ validateOtherLottoNotNull(otherLotto);
+ Set otherNumbers = new HashSet<>(otherLotto.numbers);
+ return (int) numbers.stream()
+ .filter(otherNumbers::contains)
+ .count();
+ }
+
+ private void validateOtherLottoNotNull(Lotto otherLotto) {
+ if (otherLotto == null) {
+ throw new IllegalArgumentException("[ERROR] ๋น๊ตํ ๋ก๋๊ฐ null์ผ ์ ์์ต๋๋ค.");
+ }
+ }
+
+ private void validateNotNull(List numbers) {
+ if (numbers == null) {
+ throw new IllegalArgumentException("[ERROR] ๋ก๋ ๋ฒํธ๋ null์ผ ์ ์์ต๋๋ค.");
+ }
}
private void validateCount(List numbers) {
@@ -37,15 +64,15 @@ private void validateRange(List numbers) {
}
private void validateDuplicate(List numbers) {
- Set unique = new HashSet<>(numbers);
- if (unique.size() != numbers.size()) {
+ Set uniqueNumbers = new HashSet<>(numbers);
+ if (uniqueNumbers.size() != LOTTO_SIZE) {
throw new IllegalArgumentException("[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.");
}
}
- private List sort(List numbers) {
+ private List sortNumbers(List numbers) {
return numbers.stream()
.sorted()
- .toList();
+ .collect(Collectors.toList());
}
}
diff --git a/src/main/java/lotto/domain/WinningNumbers.java b/src/main/java/lotto/domain/WinningNumbers.java
new file mode 100644
index 0000000000..b90dc0b219
--- /dev/null
+++ b/src/main/java/lotto/domain/WinningNumbers.java
@@ -0,0 +1,45 @@
+package lotto.domain;
+
+import java.util.List;
+
+public class WinningNumbers {
+
+ private final Lotto winningLotto;
+ private final int bonusNumber;
+
+ public WinningNumbers(List winningNumbers, int bonusNumber) {
+ Lotto lotto = new Lotto(winningNumbers);
+ validateBonusNumber(lotto, bonusNumber);
+ this.winningLotto = lotto;
+ this.bonusNumber = bonusNumber;
+ }
+
+ public int getBonusNumber() {
+ return bonusNumber;
+ }
+
+ public int countMatchingNumbers(Lotto lotto) {
+ return winningLotto.countMatchingNumbers(lotto);
+ }
+
+ public boolean containsBonusNumber(Lotto lotto) {
+ return lotto.containsNumber(bonusNumber);
+ }
+
+ private void validateBonusNumber(Lotto winningLotto, int bonusNumber) {
+ validateBonusRange(bonusNumber);
+ validateBonusDuplicate(winningLotto, bonusNumber);
+ }
+
+ private void validateBonusRange(int bonusNumber) {
+ if (bonusNumber < 1 || bonusNumber > 45) {
+ throw new IllegalArgumentException("[ERROR] ๋ณด๋์ค ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.");
+ }
+ }
+
+ private void validateBonusDuplicate(Lotto winningLotto, int bonusNumber) {
+ if (winningLotto.containsNumber(bonusNumber)) {
+ throw new IllegalArgumentException("[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋ ์ ์์ต๋๋ค.");
+ }
+ }
+}
diff --git a/src/test/java/lotto/domain/LottoTest.java b/src/test/java/lotto/domain/LottoTest.java
index 89d41a2c6e..d535420017 100644
--- a/src/test/java/lotto/domain/LottoTest.java
+++ b/src/test/java/lotto/domain/LottoTest.java
@@ -1,11 +1,16 @@
package lotto.domain;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
import java.util.List;
+import java.util.stream.Stream;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.*;
class LottoTest {
@@ -45,11 +50,12 @@ class LottoTest {
.hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.");
}
- @Test
- void ๋ก๋_๋ฒํธ๊ฐ_1๋ณด๋ค_์์ผ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ @ParameterizedTest()
+ @ValueSource(ints = {0, 46})
+ void ๋ก๋_๋ฒํธ๊ฐ_1๋ถํฐ_45_์ฌ์ด์_๊ฐ์ด_์๋๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(int invalidNumber) {
// given
- List numbers = List.of(0, 2, 3, 4, 5, 6);
+ List numbers = List.of(1, 2, 3, 4, 5, invalidNumber);
// when & then
assertThatThrownBy(() -> new Lotto(numbers))
@@ -57,20 +63,28 @@ class LottoTest {
.hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.");
}
+ @ParameterizedTest
+ @NullSource
+ void ๋ก๋_๋ฒํธ๊ฐ_null์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(List numbers) {
+
+ // when & then
+ assertThatThrownBy(() -> new Lotto(numbers))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ null์ผ ์ ์์ต๋๋ค.");
+ }
+
@Test
- void ๋ก๋_๋ฒํธ๊ฐ_45๋ณด๋ค_ํฌ๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ void ๋ก๋_๋ฒํธ๊ฐ_์ ์_๋ฒ์์์_๊ทน_๊ฐ์ธ_1๊ณผ_45๋ฅผ_ํฌํจํด๋_์์ธ๊ฐ_๋ฐ์ํ์ง_์๋๋ค() {
// given
- List numbers = List.of(1, 2, 3, 4, 5, 46);
+ List numbers = List.of(1, 2, 3, 4, 5, 45);
// when & then
- assertThatThrownBy(() -> new Lotto(numbers))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.");
+ assertThatNoException().isThrownBy(() -> new Lotto(numbers));
}
@Test
- void ์ฌ๋ฐ๋ฅธ_๋ก๋_๋ฒํธ_6๊ฐ๋ฉด_๋ก๋_๊ฐ์ฒด๊ฐ_์์ฑ๋๋ค() {
+ void ์ ์_๋ฒ์์_6๊ฐ_๊ฐ์_์ฌ์ฉํ๋ฉด_๊ฐ์ฒด_์์ฑ์ด_๊ฐ๋ฅํ๋ค() {
// given
List numbers = List.of(8, 1, 45, 3, 20, 10);
@@ -80,6 +94,7 @@ class LottoTest {
// then
assertThat(lotto).isNotNull();
+ assertThat(lotto.getNumbers()).hasSize(6);
}
@Test
@@ -92,8 +107,71 @@ class LottoTest {
Lotto lotto = new Lotto(numbers);
// then
- assertThat(lotto).isNotNull();
- assertThat(lotto.getNumbers())
- .containsExactly(1, 3, 8, 10, 20, 45);
+ assertThat(lotto.getNumbers()).containsExactly(1, 3, 8, 10, 20, 45);
+ }
+
+ @Test
+ void ๋ก๋๊ฐ_ํน์ _๋ฒํธ๋ฅผ_ํฌํจํ๋ฉด_true๋ฅผ_๋ฐํํ๋ค() {
+
+ // given
+ Lotto lotto = new Lotto(List.of(1, 3, 5, 10, 20, 45));
+
+ // when & then
+ assertThat(lotto.containsNumber(10)).isTrue();
+ assertThat(lotto.containsNumber(7)).isFalse();
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideLottoMatchScenarios")
+ void ๋ค๋ฅธ_๋ก๋์_์ผ์นํ๋_๋ฒํธ_๊ฐ์๋ฅผ_๊ณ์ฐํ _์_์๋ค(Lotto priorLotto, Lotto nextLotto, int expectedMatchCount) {
+
+ // when
+ int matchCount = priorLotto.countMatchingNumbers(nextLotto);
+
+ // then
+ assertThat(matchCount).isEqualTo(expectedMatchCount);
+ }
+
+ @Test
+ void ๋น๊ตํ _๋ก๋๊ฐ_null์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+
+ // given
+ Lotto lotto = new Lotto(List.of(1, 2, 3, 4, 5, 6));
+
+ // when & then
+ assertThatThrownBy(() -> lotto.countMatchingNumbers(null))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋น๊ตํ ๋ก๋๊ฐ null์ผ ์ ์์ต๋๋ค.");
+ }
+
+ @Test
+ void ๋ก๋_๋ฒํธ_๋ชฉ๋ก์_์ธ๋ถ์์_์์ ํ _์_์๋ค() {
+
+ // given
+ Lotto lotto = new Lotto(List.of(1, 2, 3, 4, 5, 6));
+
+ // when & then
+ assertThatThrownBy(() -> lotto.getNumbers().add(7))
+ .isInstanceOf(UnsupportedOperationException.class);
+ }
+
+ private static Stream provideLottoMatchScenarios() {
+ return Stream.of(
+ Arguments.of(
+ new Lotto(List.of(1, 2, 3, 4, 5, 6)),
+ new Lotto(List.of(4, 5, 6, 40, 41, 42)),
+ 3
+ ),
+ Arguments.of(
+ new Lotto(List.of(1, 2, 3, 4, 5, 6)),
+ new Lotto(List.of(7, 8, 9, 10, 11, 12)),
+ 0
+ ),
+ Arguments.of(
+ new Lotto(List.of(1, 2, 3, 4, 5, 6)),
+ new Lotto(List.of(1, 2, 3, 4, 5, 6)),
+ 6
+ )
+ );
}
}
diff --git a/src/test/java/lotto/domain/WinningNumbersTest.java b/src/test/java/lotto/domain/WinningNumbersTest.java
new file mode 100644
index 0000000000..f802764dc6
--- /dev/null
+++ b/src/test/java/lotto/domain/WinningNumbersTest.java
@@ -0,0 +1,106 @@
+package lotto.domain;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.*;
+
+class WinningNumbersTest {
+
+ @ParameterizedTest
+ @ValueSource(ints = {1, 45})
+ void ๋ณด๋์ค_๋ฒํธ๊ฐ_์ ์_๋ฒ์์์_๊ทน_๊ฐ์ธ_1๊ณผ_45_๊ฐ์ด_๋ค์ด๊ฐ๋_์์ธ๊ฐ_๋ฐ์ํ์ง_์๋๋ค(int validBonusNumber) {
+
+ // given
+ List numbers = List.of(2, 3, 4, 5, 6, 7);
+
+ // when & then
+ assertThatNoException()
+ .isThrownBy(() -> new WinningNumbers(numbers, validBonusNumber));
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, 46})
+ void ๋ณด๋์ค_๋ฒํธ๊ฐ_์ ์_๋ฒ์๋ฅผ_๋ฒ์ด๋_1๋ถํฐ_45_์ฌ์ด์_๊ฐ์ด_์๋๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(int invalidBonusNumber) {
+
+ // given
+ List numbers = List.of(1, 2, 3, 4, 5, 6);
+
+ // when & then
+ assertThatThrownBy(() -> new WinningNumbers(numbers, invalidBonusNumber))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ณด๋์ค ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.");
+ }
+
+ @Test
+ void ๋ณด๋์ค_๋ฒํธ๊ฐ_๋น์ฒจ_๋ฒํธ์_์ค๋ณต๋๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+
+ // given
+ List numbers = List.of(1, 2, 3, 4, 5, 6);
+
+ // when & then
+ assertThatThrownBy(() -> new WinningNumbers(numbers, 6))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋ ์ ์์ต๋๋ค.");
+ }
+
+ @Test
+ void ๋น์ฒจ_๋ฒํธ_๋ก๋์_์์ฑ์_๊ฒ์ฆ์ด_๋ณด๋์ค_๋ฒํธ_๊ฒ์ฆ๋ณด๋ค_๋จผ์ _์ํ๋๋ค() {
+
+ // given
+ List invalidNumbers = List.of(1, 2, 3, 4, 5, 5);
+
+ // when & then
+ assertThatThrownBy(() -> new WinningNumbers(invalidNumbers, 7))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.");
+ }
+
+ @Test
+ void ๋น์ฒจ_๋ฒํธ์_๋ณด๋์ค_๋ฒํธ๊ฐ_๋ชจ๋_์ ํจํ๋ฉด_์์ฑ๋๋ค() {
+
+ // given
+ List lottoNumbers = List.of(4, 36, 3, 28, 44, 11);
+ int bonusNumber = 7;
+
+ // when
+ WinningNumbers winningNumbers = new WinningNumbers(lottoNumbers, bonusNumber);
+
+ // then
+ assertThat(winningNumbers).isNotNull();
+ assertThat(winningNumbers.getBonusNumber()).isEqualTo(bonusNumber);
+
+ Lotto testLotto = new Lotto(lottoNumbers);
+ assertThat(winningNumbers.countMatchingNumbers(testLotto)).isEqualTo(6);
+ }
+
+ @Test
+ void ๋น์ฒจ_๋ฒํธ_๋ก๋์_๋น๊ตํ _๋ก๋์_๊ฐ_์ผ์น_๊ฐ์๋ฅผ_๊ตฌํ _์_์๋ค() {
+
+ // given
+ WinningNumbers winningNumbers = new WinningNumbers(List.of(1, 2, 3, 4, 5, 6), 7);
+ Lotto lotto = new Lotto(List.of(1, 2, 10, 11, 12, 13));
+
+ // when
+ int matchCount = winningNumbers.countMatchingNumbers(lotto);
+
+ // then
+ assertThat(matchCount).isEqualTo(2);
+ }
+
+ @Test
+ void ๋ณด๋์ค_๋ฒํธ๋ฅผ_ํฌํจํ๋์ง_ํ์ธํ _์_์๋ค() {
+
+ // given
+ WinningNumbers winningNumbers = new WinningNumbers(List.of(1, 2, 3, 4, 5, 6), 7);
+ Lotto containsBonus = new Lotto(List.of(7, 10, 20, 30, 40, 45));
+ Lotto notContainsBonus = new Lotto(List.of(8, 10, 20, 30, 40, 45));
+
+ // when & then
+ assertThat(winningNumbers.containsBonusNumber(containsBonus)).isTrue();
+ assertThat(winningNumbers.containsBonusNumber(notContainsBonus)).isFalse();
+ }
+}
From c354951e6882c0ef446f7a2a5ac00f38e4b2f8e0 Mon Sep 17 00:00:00 2001
From: JohnPrk
Date: Mon, 3 Nov 2025 03:39:39 +0900
Subject: [PATCH 06/10] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=8B=B9?=
=?UTF-8?q?=EC=B2=A8=20=EB=93=B1=EC=88=98=EC=99=80=20=EC=83=81=EA=B8=88?=
=?UTF-8?q?=EC=9D=84=20=EC=A0=95=EC=9D=98=ED=95=98=EB=8A=94=20LottoRank=20?=
=?UTF-8?q?enum=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 1๋ฑ๋ถํฐ 5๋ฑ ๋ฐ ๊ฝ์ ๋ํ ๋ฑ์ ์กฐ๊ฑด ์ ์
- ๋ฑ์๋ณ ์๊ธ ์ ๊ณต ๊ธฐ๋ฅ
- ์ผ์น ๊ฐ์์ ๋ณด๋์ค ์ผ์น ์ฌ๋ถ ๊ธฐ๋ฐ ๋ฑ์ ํ์ ๋ก์ง ๊ตฌํ
- ๋ฑ์ ํ์ ๋ฐ ์๊ธ ์ ๊ณต ๊ธฐ๋ฅ์ ๋ํ ๋จ์ ํ
์คํธ
- ๋ณด๋์ค ๋ฒํธ๊ฐ ๋ฑ์์ ๋ฏธ์น๋ ์ํฅ ๋ฒ์ ๊ฒ์ฆ
---
src/main/java/lotto/domain/LottoRank.java | 37 +++++
src/test/java/lotto/domain/LottoRankTest.java | 152 ++++++++++++++++++
2 files changed, 189 insertions(+)
create mode 100644 src/main/java/lotto/domain/LottoRank.java
create mode 100644 src/test/java/lotto/domain/LottoRankTest.java
diff --git a/src/main/java/lotto/domain/LottoRank.java b/src/main/java/lotto/domain/LottoRank.java
new file mode 100644
index 0000000000..d2496e1afe
--- /dev/null
+++ b/src/main/java/lotto/domain/LottoRank.java
@@ -0,0 +1,37 @@
+package lotto.domain;
+
+import java.util.Arrays;
+
+public enum LottoRank {
+
+ FIRST(6, false, 2_000_000_000L),
+ SECOND(5, true, 30_000_000L),
+ THIRD(5, false, 1_500_000L),
+ FOURTH(4, false, 50_000L),
+ FIFTH(3, false, 5_000L),
+ NONE(0, false, 0L);
+
+ private final int matchCount;
+ private final boolean requiresBonus;
+ private final long prize;
+
+ LottoRank(int matchCount, boolean requiresBonus, long prize) {
+ this.matchCount = matchCount;
+ this.requiresBonus = requiresBonus;
+ this.prize = prize;
+ }
+
+ public long getPrize() {
+ return prize;
+ }
+
+ public static LottoRank from(int matchCount, boolean bonusMatched) {
+ if (matchCount == 5) {
+ return bonusMatched ? SECOND : THIRD;
+ }
+ return Arrays.stream(values())
+ .filter(rank -> rank.matchCount == matchCount)
+ .findFirst()
+ .orElse(NONE);
+ }
+}
diff --git a/src/test/java/lotto/domain/LottoRankTest.java b/src/test/java/lotto/domain/LottoRankTest.java
new file mode 100644
index 0000000000..ffbb85c6a7
--- /dev/null
+++ b/src/test/java/lotto/domain/LottoRankTest.java
@@ -0,0 +1,152 @@
+package lotto.domain;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class LottoRankTest {
+
+ @Test
+ void ์ฌ์ฏ_๊ฐ๊ฐ_๋ชจ๋_์ผ์นํ๋ฉด_1๋ฑ์ด๋ค() {
+
+ // given
+ int matchCount = 6;
+ boolean bonusMatched = false;
+
+ // when
+ LottoRank rank = LottoRank.from(matchCount, bonusMatched);
+
+ // then
+ assertThat(rank).isEqualTo(LottoRank.FIRST);
+ }
+
+ @Test
+ void ๋ค์ฏ_๊ฐ์_๋ณด๋์ค๊น์ง_์ผ์นํ๋ฉด_2๋ฑ์ด๋ค() {
+
+ // given
+ int matchCount = 5;
+ boolean bonusMatched = true;
+
+ // when
+ LottoRank rank = LottoRank.from(matchCount, bonusMatched);
+
+ // then
+ assertThat(rank).isEqualTo(LottoRank.SECOND);
+ }
+
+ @Test
+ void ๋ค์ฏ_๊ฐ๋ง_์ผ์นํ๊ณ _๋ณด๋์ค๋_๋ค๋ฅด๋ฉด_3๋ฑ์ด๋ค() {
+
+ // given
+ int matchCount = 5;
+ boolean bonusMatched = false;
+
+ // when
+ LottoRank rank = LottoRank.from(matchCount, bonusMatched);
+
+ // then
+ assertThat(rank).isEqualTo(LottoRank.THIRD);
+ }
+
+ @Test
+ void ๋ค_๊ฐ๊ฐ_์ผ์นํ๋ฉด_4๋ฑ์ด๋ค() {
+
+ // given
+ int matchCount = 4;
+
+ // when
+ LottoRank rank = LottoRank.from(matchCount, false);
+
+ // then
+ assertThat(rank).isEqualTo(LottoRank.FOURTH);
+ }
+
+ @Test
+ void ์ธ_๊ฐ๊ฐ_์ผ์นํ๋ฉด_5๋ฑ์ด๋ค() {
+
+ // given
+ int matchCount = 3;
+
+ // when
+ LottoRank rank = LottoRank.from(matchCount, false);
+
+ // then
+ assertThat(rank).isEqualTo(LottoRank.FIFTH);
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, 1, 2})
+ void ๋_๊ฐ_์ดํ๋ก_์ผ์นํ๋ฉด_๊ฝ์ด๋ค(int matchCount) {
+
+ // when
+ LottoRank rank = LottoRank.from(matchCount, false);
+
+ // then
+ assertThat(rank).isEqualTo(LottoRank.NONE);
+ }
+
+ @ParameterizedTest
+ @MethodSource("providePrizePerRank")
+ void ๋ฑ์๋ณ_๋น์ฒจ๊ธ์_๋ฐํํ๋ค(LottoRank rank, long expectedPrize) {
+
+ //when
+ long prize = rank.getPrize();
+
+ // then
+ assertThat(prize).isEqualTo(expectedPrize);
+ }
+
+
+ @ParameterizedTest
+ @MethodSource("bonusShouldBeIgnoredCases")
+ void ๋ณด๋์ค๋_๋ค์ฏ_๊ฐ๊ฐ_๋ง์_๋๋ฅผ_์ ์ธํ๊ณ ๋_์ํฅ์_์ฃผ์ง_์๋๋ค(int matchCount) {
+
+ // when
+ LottoRank withBonus = LottoRank.from(matchCount, true);
+ LottoRank withoutBonus = LottoRank.from(matchCount, false);
+
+ // then
+ assertThat(withBonus).isEqualTo(withoutBonus);
+ }
+
+ @Test
+ void ๋ค์ฏ_๊ฐ_์ผ์น_์_๋ณด๋์ค_์ฌ๋ถ์_๋ฐ๋ผ_๋ฑ์๊ฐ_๋ฐ๋๋ค() {
+
+ // when
+ LottoRank withBonus = LottoRank.from(5, true);
+ LottoRank withoutBonus = LottoRank.from(5, false);
+
+ // then
+ assertThat(withBonus).isEqualTo(LottoRank.SECOND);
+ assertThat(withoutBonus).isEqualTo(LottoRank.THIRD);
+ assertThat(withBonus).isNotEqualTo(withoutBonus);
+ }
+
+ private static Stream bonusShouldBeIgnoredCases() {
+ return Stream.of(
+ Arguments.of(0),
+ Arguments.of(1),
+ Arguments.of(2),
+ Arguments.of(3),
+ Arguments.of(4),
+ Arguments.of(6)
+ );
+ }
+
+ private static Stream providePrizePerRank() {
+ return Stream.of(
+ Arguments.of(LottoRank.FIRST, 2_000_000_000L),
+ Arguments.of(LottoRank.SECOND, 30_000_000L),
+ Arguments.of(LottoRank.THIRD, 1_500_000L),
+ Arguments.of(LottoRank.FOURTH, 50_000L),
+ Arguments.of(LottoRank.FIFTH, 5_000L),
+ Arguments.of(LottoRank.NONE, 0L)
+ );
+ }
+}
From 24c96805b1084a274cc5683ef98e3cb98c02e792 Mon Sep 17 00:00:00 2001
From: JohnPrk
Date: Mon, 3 Nov 2025 20:06:35 +0900
Subject: [PATCH 07/10] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EB=8B=B9?=
=?UTF-8?q?=EC=B2=A8=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EC=A7=91=EA=B3=84?=
=?UTF-8?q?=ED=95=98=EB=8A=94=20LottoResults=20=EB=8F=84=EB=A9=94=EC=9D=B8?=
=?UTF-8?q?=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก๊ณผ ๋น์ฒจ ๋ฒํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ฑ์๋ณ ๋น์ฒจ ๊ฐ์ ์ง๊ณ
- ๋ฑ์๋ณ ์๊ธ์ ๋์ ํด ์ด ๋น์ฒจ ๊ธ์ก ๊ณ์ฐ
- ๊ตฌ์
๊ธ์ก์ ์ธ์๋ก ๋ฐ์ ์์ต๋ฅ (์ด ๋น์ฒจ๊ธ / ๊ตฌ์
๊ธ์ก) ๊ณ์ฐ
- ๋ก๋ ๋ชฉ๋ก ๋ฐ ๊ฐ ์์, ๋น์ฒจ ๋ฒํธ์ ๋ํ null ๋ฐฉ์ด ๋ก์ง๊ณผ ์์ธ ๋ฉ์์ง ์ ์
- ๊ฒ์ฆ ๋ฐ ์ด ๋น์ฒจ๊ธ ์ง๊ณ, ์์ต๋ฅ ์กฐํ ๊ธฐ๋ฅ ๊ด๋ จ ๋จ์ ํ
์คํธ ์์ฑ
- README.md ์์ธ ์ฒ๋ฆฌ ํ์ LottoResults ๊ด๋ จ ์์ธ ๋ฉ์์ง ์ถ๊ฐ
---
README.md | 34 ++--
src/main/java/lotto/domain/LottoResults.java | 71 ++++++++
.../java/lotto/domain/LottoResultsTest.java | 157 ++++++++++++++++++
3 files changed, 247 insertions(+), 15 deletions(-)
create mode 100644 src/main/java/lotto/domain/LottoResults.java
create mode 100644 src/test/java/lotto/domain/LottoResultsTest.java
diff --git a/README.md b/README.md
index c2db501433..f3c7d6e20e 100644
--- a/README.md
+++ b/README.md
@@ -110,7 +110,7 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
| `LottoFactory` | ๋ก๋ ๊ท์น์ ๋ง๋ ๋๋ค ๋ฒํธ๋ฅผ ์์ฑํ์ฌย `Lotto`ย ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ์ฑ
์์ ์ง | | -`Randoms.pickUniqueNumbersInRange()`๋ฅผ ์ฌ์ฉํด ๋ก๋ ๋ฒํธ ์์ฑ |
| `WinningNumbers` | ๋น์ฒจ ๋ฒํธ์ ๋ณด๋์ค ๋ฒํธ๋ฅผ ๊ฐ์ง๋ฉฐ ๊ด๋ จ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ์ฑ
์์ง | * 6๊ฐ ๋น์ฒจ ๋ฒํธ, 1๊ฐ ๋ณด๋์ค ๋ฒํธ | - ๋น์ฒจ ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ, ๋ณด๋์ค ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์ค๋ณต ํ์ธ |
| `LottoRank` | ๋น์ฒจ ๋ฑ์(1~5๋ฑ, ๊ฝ)์ ์กฐ๊ฑด(์ผ์น ๊ฐ์, ๋ณด๋์ค)๊ณผ ์๊ธ์ ์ ์ | *Enum class(์ผ์น ๊ฐ์, ๋ณด๋์ค ํฌํจ์ฌ๋ถ,๋น์ฒจ ๊ธ์ก) | - ์ผ์น ์/๋ณด๋์ค ํฌํจ ์ฌ๋ถ๋ก ๋ฑ์ ๋ฐํ, ์๊ธ ๋ฐํ |
-| `LottoResults` | ์ ์ฒด ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐ | * ๋ฑ์๋ณ ๋น์ฒจ ํ์, ์ด ์์ต๋ฅ , ๋์ ์๊ธ | - ๊ฐ ๋ก๋์ ๋ํ ๋ฑ์ ๊ณ์ฐ, ๋น์ฒจ ๊ฒฐ๊ณผ ๋์ , ์์ต๋ฅ ๊ณ์ฐ |
+| `LottoResults` | ์ ์ฒด ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐ | * ๋ฑ์๋ณ ๋น์ฒจ ํ์, ๋์ ์๊ธ | - ๊ฐ ๋ก๋์ ๋ํ ๋ฑ์ ๊ณ์ฐ, ๋น์ฒจ ๊ฒฐ๊ณผ ๋์ , ์์ต๋ฅ ๊ณ์ฐ |
| `InputView` | ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์
๋ ฅ ์ ๋์ฌ | - ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ์, `camp.nextstep.edu.missionutils.Console`์ย `readLine()`์ ์ฌ์ฉ |
| `OutputView` | ์ฌ์ฉ์์๊ฒ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์ถ๋ ฅ ์ ๋์ฌ | - ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก ์ถ๋ ฅ, ๋น์ฒจ ๊ฒฐ๊ณผ ์ถ๋ ฅ, ์์ต๋ฅ ์ถ๋ ฅ |
| `LottoController` | ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฒด ์คํ ํ๋ฆ์ ์กฐ์จ. View์ Domain ๊ฐ์ฒด๋ค์ ์ฐ๊ฒฐ | | - ์ ์ฒด ํ๋ฆ ์ ์ด |
@@ -182,17 +182,21 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
์ฌ์ฉ์์ ์
๋ ฅ ์ค๋ฅ๋ก ์์ธ๊ฐ ๋ฐ์ํ๋ฉด **`[ERROR] ...` ๋ก ์์ํ๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ฌ์ฉ์์๊ฒ ์ถ๋ ฅํ๊ณ ํด๋น ์
๋ ฅ๋ถํฐ ๋ค์ ์
๋ ฅ์ ์งํํ ์ ์๋๋ก ํฉ๋๋ค.**
-| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
-|-------------------------|--------------------------------------|
-| ๊ตฌ์
๊ธ์ก์ด 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.` |
-| ๊ตฌ์
๊ธ์ก์ด 1,000์ ๋จ์๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] 1,000์ ๋จ์๋ก ์
๋ ฅํด ์ฃผ์ธ์.` |
-| ๋ก๋ ๋ฒํธ ๋ฆฌ์คํธ๊ฐ null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ null์ผ ์ ์์ต๋๋ค.` |
-| ๋น๊ตํ ๋ก๋ ๋ฒํธ ๋ฆฌ์คํธ๊ฐ null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋น๊ตํ ๋ก๋๊ฐ null์ผ ์ ์์ต๋๋ค.` |
-| ๋ก๋ ๋ฒํธ๊ฐ 6๊ฐ๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 6๊ฐ์ฌ์ผ ํฉ๋๋ค.` |
-| ๋ก๋ ๋ฒํธ์ ์ค๋ณต์ด ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
-| ๋ก๋ ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
-| ๋ณด๋์ค ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
-| ๋ณด๋์ค ๋ฒํธ๊ฐ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
+| ์์ธ ์ํฉ | ์๋ฌ ๋ฉ์์ง |
+|----------------------------|-------------------------------------------|
+| ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ฐํ ๋ก๋ ๋ชฉ๋ก์ด null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ฐํ ๋ก๋ ๋ชฉ๋ก์ null์ผ ์ ์์ต๋๋ค.` |
+| ๋ก๋ ๋ชฉ๋ก์ null์ด ํฌํจ๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ชฉ๋ก์ null์ด ํฌํจ๋ ์ ์์ต๋๋ค.` |
+| ๋น์ฒจ ๋ฒํธ๊ฐ null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋น์ฒจ ๋ฒํธ๋ null์ผ ์ ์์ต๋๋ค.` |
+| ์์ต๋ฅ ๊ณ์ฐ์ ๊ตฌ์
๊ธ์ก์ด 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.` |
+| ๊ตฌ์
๊ธ์ก์ด 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.` |
+| ๊ตฌ์
๊ธ์ก์ด 1,000์ ๋จ์๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] 1,000์ ๋จ์๋ก ์
๋ ฅํด ์ฃผ์ธ์.` |
+| ๋ก๋ ๋ฒํธ ๋ฆฌ์คํธ๊ฐ null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ null์ผ ์ ์์ต๋๋ค.` |
+| ๋น๊ตํ ๋ก๋ ๋ฒํธ ๋ฆฌ์คํธ๊ฐ null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋น๊ตํ ๋ก๋๊ฐ null์ผ ์ ์์ต๋๋ค.` |
+| ๋ก๋ ๋ฒํธ๊ฐ 6๊ฐ๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 6๊ฐ์ฌ์ผ ํฉ๋๋ค.` |
+| ๋ก๋ ๋ฒํธ์ ์ค๋ณต์ด ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
+| ๋ก๋ ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
+| ๋ณด๋์ค ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
+| ๋ณด๋์ค ๋ฒํธ๊ฐ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
@@ -218,9 +222,9 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
๊ตฌํ ๊ณผ์ ์์ ๋ฐฐ์ฐ๊ณ ๊ณ ๋ฏผํ๋ ๊ฒ๋ค์ ๊ธฐ๋กํ๋ ๊ณต๊ฐ์
๋๋ค.
- [๋๋ฉ์ธ ์ค๊ณ์ ๊ณ ๋ คํ๋ ๊ฒ](https://github.com/JohnPrk/java-lotto-8/issues/1)
-- **[Inside-Out vs Outside-In TDD ์ ํ ์ด์ ](**https://github.com/JohnPrk/java-lotto-8/issues/2**)**
-- **[Supplier๋ ๋ฌด์์ธ๊ฐ?](**https://github.com/JohnPrk/java-lotto-8/issues/3**)**
-- **[2023๋
๊ตฌํ vs ์ง๊ธ ๊ตฌํ ๋น๊ต[ํ๊ณ ]](**https://github.com/JohnPrk/java-lotto-8/issues/4**)**
+- [Inside-Out vs Outside-In TDD ์ ํ ์ด์ ](https://github.com/JohnPrk/java-lotto-8/issues/2**)
+- [Supplier๋ ๋ฌด์์ธ๊ฐ?](https://github.com/JohnPrk/java-lotto-8/issues/3**)
+- [2023๋
๊ตฌํ vs ์ง๊ธ ๊ตฌํ ๋น๊ต[ํ๊ณ ]](https://github.com/JohnPrk/java-lotto-8/issues/4**)
diff --git a/src/main/java/lotto/domain/LottoResults.java b/src/main/java/lotto/domain/LottoResults.java
new file mode 100644
index 0000000000..9a512b497c
--- /dev/null
+++ b/src/main/java/lotto/domain/LottoResults.java
@@ -0,0 +1,71 @@
+package lotto.domain;
+
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+
+public class LottoResults {
+
+ private final Map results = new EnumMap<>(LottoRank.class);
+ private long totalPrize;
+
+ public LottoResults(List lottos, WinningNumbers winningNumbers) {
+ validateLottos(lottos);
+ validateLottoElements(lottos);
+ validateWinningNumbers(winningNumbers);
+ countResults(lottos, winningNumbers);
+ }
+
+ public int getCountOf(LottoRank rank) {
+ return results.getOrDefault(rank, 0);
+ }
+
+ public long getTotalPrize() {
+ return totalPrize;
+ }
+
+ public double calculateYield(long purchaseAmount) {
+ if (purchaseAmount <= 0) {
+ throw new IllegalArgumentException("[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.");
+ }
+ return (double) totalPrize / purchaseAmount;
+ }
+
+ private void validateLottos(List lottos) {
+ if (lottos == null) {
+ throw new IllegalArgumentException("[ERROR] ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ฐํ ๋ก๋ ๋ชฉ๋ก์ null์ผ ์ ์์ต๋๋ค.");
+ }
+ }
+
+ private void validateLottoElements(List lottos) {
+ for (Lotto lotto : lottos) {
+ if (lotto == null) {
+ throw new IllegalArgumentException("[ERROR] ๋ก๋ ๋ชฉ๋ก์ null์ด ํฌํจ๋ ์ ์์ต๋๋ค.");
+ }
+ }
+ }
+
+ private void validateWinningNumbers(WinningNumbers winningNumbers) {
+ if (winningNumbers == null) {
+ throw new IllegalArgumentException("[ERROR] ๋น์ฒจ ๋ฒํธ๋ null์ผ ์ ์์ต๋๋ค.");
+ }
+ }
+
+ private void countResults(List lottos, WinningNumbers winningNumbers) {
+ for (Lotto lotto : lottos) {
+ LottoRank rank = toRank(lotto, winningNumbers);
+ incrementRankCount(rank);
+ totalPrize += rank.getPrize();
+ }
+ }
+
+ private LottoRank toRank(Lotto lotto, WinningNumbers winningNumbers) {
+ int matchCount = winningNumbers.countMatchingNumbers(lotto);
+ boolean bonusMatched = winningNumbers.containsBonusNumber(lotto);
+ return LottoRank.from(matchCount, bonusMatched);
+ }
+
+ private void incrementRankCount(LottoRank rank) {
+ results.put(rank, results.getOrDefault(rank, 0) + 1);
+ }
+}
diff --git a/src/test/java/lotto/domain/LottoResultsTest.java b/src/test/java/lotto/domain/LottoResultsTest.java
new file mode 100644
index 0000000000..fbd85777bf
--- /dev/null
+++ b/src/test/java/lotto/domain/LottoResultsTest.java
@@ -0,0 +1,157 @@
+package lotto.domain;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class LottoResultsTest {
+
+ @Test
+ void ์ฃผ์ด์ง_๋ก๋๋ค๊ณผ_๋น์ฒจ_๋ฒํธ_๋ก๋๋ฅผ_๋น๊ตํ์ฌ_์์๋ฅผ_์ฌ๋ฆฌ๊ณ _์ง๊ณํ _์_์๋ค() {
+
+ // given
+ WinningNumbers winningNumbers = new WinningNumbers(List.of(1, 2, 3, 4, 5, 6), 7);
+ Lotto first = new Lotto(List.of(1, 2, 3, 4, 5, 6));
+ Lotto second = new Lotto(List.of(1, 2, 3, 4, 5, 7));
+ Lotto third = new Lotto(List.of(1, 2, 3, 4, 5, 45));
+ Lotto fourth = new Lotto(List.of(1, 2, 3, 4, 11, 45));
+ Lotto fifth = new Lotto(List.of(1, 2, 3, 7, 11, 45));
+ Lotto none = new Lotto(List.of(10, 11, 12, 13, 14, 15));
+ List lottos = List.of(first, second, third, fourth, fifth, none);
+
+ // when
+ LottoResults results = new LottoResults(lottos, winningNumbers);
+
+ // then
+ assertThat(results.getCountOf(LottoRank.FIRST)).isEqualTo(1);
+ assertThat(results.getCountOf(LottoRank.SECOND)).isEqualTo(1);
+ assertThat(results.getCountOf(LottoRank.THIRD)).isEqualTo(1);
+ assertThat(results.getCountOf(LottoRank.FOURTH)).isEqualTo(1);
+ assertThat(results.getCountOf(LottoRank.FIFTH)).isEqualTo(1);
+ assertThat(results.getCountOf(LottoRank.NONE)).isEqualTo(1);
+ }
+
+ @Test
+ void ์ฃผ์ด์ง_๋ก๋๋ค๊ณผ_๋น์ฒจ_๋ฒํธ_๋ก๋์_์ผ์น_๊ฐ์๊ฐ_2_์ดํ๋ผ๋ฉด_NONE๋ง_์ฆ๊ฐํ๋ค() {
+
+ // given
+ WinningNumbers winningNumbers = new WinningNumbers(List.of(1, 2, 3, 4, 5, 6), 7);
+ List lottos = List.of(
+ new Lotto(List.of(10, 11, 12, 13, 14, 15)),
+ new Lotto(List.of(20, 21, 22, 23, 24, 25)),
+ new Lotto(List.of(1, 2, 22, 23, 24, 25)),
+ new Lotto(List.of(20, 21, 3, 23, 24, 25)),
+ new Lotto(List.of(20, 21, 3, 4, 24, 25)),
+ new Lotto(List.of(20, 21, 10, 11, 5, 25)),
+ new Lotto(List.of(20, 21, 10, 11, 5, 6))
+ );
+
+ // when
+ LottoResults results = new LottoResults(lottos, winningNumbers);
+
+ // then
+ for (LottoRank rank : LottoRank.values()) {
+ if (rank == LottoRank.NONE) {
+ assertThat(results.getCountOf(rank)).isEqualTo(7);
+ continue;
+ }
+ assertThat(results.getCountOf(rank)).isEqualTo(0);
+ }
+ }
+
+ @Test
+ void ๋น์ฒจ๋_๋ก๋๋ค์_์ด_๋น์ฒจ๊ธ์_ํฉ์ฐํ๋ค() {
+
+ // given
+ WinningNumbers winningNumbers = new WinningNumbers(List.of(1, 2, 3, 4, 5, 6), 7);
+ Lotto first = new Lotto(List.of(1, 2, 3, 4, 5, 6));
+ Lotto fifth = new Lotto(List.of(1, 2, 3, 40, 41, 42));
+ List lottos = List.of(first, fifth);
+
+ // when
+ LottoResults results = new LottoResults(lottos, winningNumbers);
+
+ // then
+ assertThat(results.getTotalPrize()).isEqualTo(2_000_005_000L);
+ }
+
+ @Test
+ void ์์ต๋ฅ ์_๊ตฌ์
๊ธ์ก์ผ๋ก_๊ณ์ฐํ๋ค() {
+
+ // given
+ WinningNumbers winningNumbers = new WinningNumbers(List.of(1, 2, 3, 4, 5, 6), 7);
+ Lotto first = new Lotto(List.of(1, 2, 3, 4, 5, 6));
+ Lotto third = new Lotto(List.of(1, 2, 3, 4, 17, 6));
+ List lottos = List.of(first, third);
+ LottoResults results = new LottoResults(lottos, winningNumbers);
+
+ // when
+ double yield = results.calculateYield(lottos.size() * 1000);
+
+ // then
+ assertThat(yield).isEqualTo(2_001_500_000D / 2_000D);
+ }
+
+ @ParameterizedTest
+ @NullSource
+ void ๋ก๋_๋ชฉ๋ก์ด_null์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(List lottos) {
+
+ // given
+ WinningNumbers winningNumbers = new WinningNumbers(List.of(1, 2, 3, 4, 5, 6), 7);
+
+ // when & then
+ assertThatThrownBy(() -> new LottoResults(lottos, winningNumbers))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ฐํ ๋ก๋ ๋ชฉ๋ก์ null์ผ ์ ์์ต๋๋ค.");
+ }
+
+ @Test
+ void ๋ก๋_๋ชฉ๋ก์_null์ด_ํฌํจ๋๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+
+ // given
+ WinningNumbers winningNumbers = new WinningNumbers(List.of(1, 2, 3, 4, 5, 6), 7);
+ List lottos = new ArrayList<>();
+ lottos.add(new Lotto(List.of(1, 2, 3, 4, 5, 6)));
+ lottos.add(null);
+
+ // when & then
+ assertThatThrownBy(() -> new LottoResults(lottos, winningNumbers))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ๋ชฉ๋ก์ null์ด ํฌํจ๋ ์ ์์ต๋๋ค.");
+ }
+
+ @Test
+ void ๋น์ฒจ๋ฒํธ๊ฐ_null์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ // given
+ List lottos = List.of(new Lotto(List.of(1, 2, 3, 4, 5, 6)));
+
+ // when & then
+ assertThatThrownBy(() -> new LottoResults(lottos, null))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋น์ฒจ ๋ฒํธ๋ null์ผ ์ ์์ต๋๋ค.");
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, -10})
+ void ์์ต๋ฅ _๊ณ์ฐ์_๊ตฌ์
๊ธ์ก์ด_0_์ดํ์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(int purchaseAmount) {
+
+ // given
+ WinningNumbers winningNumbers = new WinningNumbers(List.of(1, 2, 3, 4, 5, 6), 7);
+ LottoResults results = new LottoResults(
+ List.of(new Lotto(List.of(1, 2, 3, 4, 5, 6))),
+ winningNumbers
+ );
+
+ // when & then
+ assertThatThrownBy(() -> results.calculateYield(purchaseAmount))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.");
+ }
+}
From 1cae4118be792e982302caade5d1b292d4d136f9 Mon Sep 17 00:00:00 2001
From: JohnPrk
Date: Mon, 3 Nov 2025 22:35:18 +0900
Subject: [PATCH 08/10] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EC=83=9D?=
=?UTF-8?q?=EC=84=B1=20=EC=B1=85=EC=9E=84=20=EB=B0=8F=20=EA=B2=80=EC=A6=9D?=
=?UTF-8?q?=EC=9D=84=20=EB=8B=B4=EB=8B=B9=ED=95=98=EB=8A=94=20LottoFactory?=
=?UTF-8?q?=20=EB=B0=8F=20LottoGenerator=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- ๋ก๋ ์์ฑ ๋ก์ง์ LottoGenerator ์ธํฐํ์ด์ค๋ก ์ถ์ํ
- Randoms ์ ํธ์ ์ฌ์ฉํ๋ RandomLottoGenerator ๊ตฌํ
- LottoFactory๊ฐ LottoGenerator์ ์์กดํ๋๋ก ์์ (DIP)
- LottoFactory์ ์์ฑ ๊ฐ์(count) ์ ํจ์ฑ ๊ฒ์ฆ
- ํ
์คํธ ๋๋ธ FakeLottoGenerator ๊ตฌํ
- FakeLottoGenerator๋ฅผ ์ฌ์ฉํ LottoFactory ๋จ์ ํ
์คํธ ์์ฑ
- LottoGenerator ์ธํฐํ์ด์ค์ ๊ตฌํ ํด๋์ค ๊ด๋ จ ๋จ์ ํ
์คํธ ์์ฑ
- README.md ์์ธ ์ฒ๋ฆฌ ํ์ LottoGenerator, LottoFactory ๊ด๋ จ ์์ธ ๋ฉ์์ง ์ถ๊ฐ
- README.md ์ํ์ค ๋ค์ด์ด๊ทธ๋จ ๋ฐ ๊ฐ์ฒด ์ญํ ์์ฝ ์ถ๊ฐ
---
README.md | 61 ++++++++++--------
src/main/java/lotto/domain/LottoFactory.java | 30 +++++++++
.../java/lotto/domain/LottoGenerator.java | 9 +++
.../lotto/domain/RandomLottoGenerator.java | 23 +++++++
.../lotto/domain/FakeLottoGeneratorTest.java | 62 +++++++++++++++++++
.../java/lotto/domain/LottoFactoryTest.java | 61 ++++++++++++++++++
.../domain/RandomLottoGeneratorTest.java | 25 ++++++++
.../domain/testDouble/FakeLottoGenerator.java | 31 ++++++++++
8 files changed, 276 insertions(+), 26 deletions(-)
create mode 100644 src/main/java/lotto/domain/LottoFactory.java
create mode 100644 src/main/java/lotto/domain/LottoGenerator.java
create mode 100644 src/main/java/lotto/domain/RandomLottoGenerator.java
create mode 100644 src/test/java/lotto/domain/FakeLottoGeneratorTest.java
create mode 100644 src/test/java/lotto/domain/LottoFactoryTest.java
create mode 100644 src/test/java/lotto/domain/RandomLottoGeneratorTest.java
create mode 100644 src/test/java/lotto/domain/testDouble/FakeLottoGenerator.java
diff --git a/README.md b/README.md
index f3c7d6e20e..b4ed73b18e 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@ sequenceDiagram
participant C as LottoController
participant M as Money
participant F as LottoFactory
+ participant G as LottoGenerator
participant L as Lotto
participant W as WinningNumbers
participant R as LottoResults
@@ -41,19 +42,24 @@ Note over U,C: ๐ซ 1๋จ๊ณ: ๋ก๋ ๊ตฌ๋งค
M-->>C: ์ ํจํ Money ๊ฐ์ฒด
else ๊ฒ์ฆ ์คํจ
M-->>C: IllegalArgumentException
- C->>O: ๋ฉ์์ง ์ถ๋ ฅ
+ C->>O: ์๋ฌ ๋ฉ์์ง ์ถ๋ ฅ
O->>U: ์๋ฌ ํ์
end
end
C->>M: getLottoCount() ํธ์ถ
- M-->>C: ๊ตฌ๋งค ๊ฐ๋ฅํ ๋ก๋ ๊ฐ์
- loop N๋ฒ (๋ก๋ ๊ฐ์๋งํผ)
- C->>F: generateLotto() ํธ์ถ
- F->>F: Randoms.pickUniqueNumbersInRange(1,45,6)
- F-->>C: ์์ฑ๋ ๋ฒํธ ๋ชฉ๋ก
- C->>L: Lotto ๊ฐ์ฒด ์์ฑ
+ M-->>C: ๊ตฌ๋งค ๊ฐ๋ฅํ ๋ก๋ ๊ฐ์(count)
+
+ C->>F: generate(count) ํธ์ถ
+ F->>G: generate(count) ์์
+
+ loop count๋ฒ
+ G->>G: Randoms.pickUniqueNumbersInRange(1,45,6)
+ G->>L: Lotto(numbers) ์์ฑ
end
+ G-->>F: List ๋ฐํ
+ F-->>C: List ๋ฐํ
+
C->>O: ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก ์ถ๋ ฅ
O->>U: ๋ก๋ ๋ชฉ๋ก ํ์
@@ -66,7 +72,7 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
W-->>C: ๋น์ฒจ ๋ฒํธ ๊ฐ์ฒด ์์ฑ๋จ
else ๊ฒ์ฆ ์คํจ
W-->>C: IllegalArgumentException
- C->>O: ๋ฉ์์ง ์ถ๋ ฅ
+ C->>O: ์๋ฌ ๋ฉ์์ง ์ถ๋ ฅ
O->>U: ์๋ฌ ํ์
end
end
@@ -79,19 +85,18 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
W-->>C: ์ต์ข
๋น์ฒจ ๋ฒํธ ๊ฐ์ฒด ์์ฑ
else ๊ฒ์ฆ ์คํจ
W-->>C: IllegalArgumentException
- C->>O: ๋ฉ์์ง ์ถ๋ ฅ
+ C->>O: ์๋ฌ ๋ฉ์์ง ์ถ๋ ฅ
O->>U: ์๋ฌ ํ์
end
end
Note over U,C: ๐ 3๋จ๊ณ: ๊ฒฐ๊ณผ ๋ถ์ ๋ฐ ์ถ๋ ฅ
C->>R: LottoResults ์์ฑ (List, WinningNumbers)
loop ๊ฐ ๋ก๋์ ๋ํด
- R->>R: calculateRank(lotto, winningNumbers)
R->>R: ๋ฑ์๋ณ ์นด์ดํธ ์ฆ๊ฐ
R->>R: ์ด ์๊ธ ๋์
end
- R->>R: ์์ต๋ฅ ๊ณ์ฐ
- R-->>C: ๋ถ์ ๊ฒฐ๊ณผ
+ C->>R: calculateYield(๊ตฌ์
๊ธ์ก) ํธ์ถ
+ R-->>C: ์์ต๋ฅ ๋ฐํ
C->>O: ๋น์ฒจ ํต๊ณ ์ถ๋ ฅ
O->>U: ํต๊ณ ํ์
C->>O: ์์ต๋ฅ ์ถ๋ ฅ
@@ -103,17 +108,19 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
## **๐งฑ ๊ฐ์ฒด ์ญํ ์์ฝ**
-| ๊ฐ์ฒด ์ด๋ฆ | ์ญํ (์ฑ
์) | ๋ณด์ ๊ฐ(์ํ) | ์ฃผ์ ํ์ |
-|-------------------|---------------------------------------------|------------------------------------|-----------------------------------------------------------------------------|
-| `Money` | ๊ตฌ์
๊ธ์ก์ ํํํ๊ณ ๊ด๋ จ ๊ท์น์ ๊ฒ์ฆํ๋ ๊ฐ ๊ฐ์ฒด | * ๊ตฌ์
๊ธ์ก | - ๊ธ์ก ์ ํจ์ฑ ๊ฒ์ฌ, ๊ตฌ๋งค ๊ฐ๋ฅํ ๋ก๋ ์ ๊ณ์ฐ |
-| `Lotto` | ๋ก๋ ํ ์ฅ์ ํํํ๋ฉฐ ๋ฒํธ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ๋ถ๋ณ์ฑ์ ๋ณด์ฅ | * 6๊ฐ์ ๋ก๋ ๋ฒํธ | - ๋ฒํธ ์ ๋ ฌ ๋ฐ ์ค๋ณต ๊ฒ์ฌ, ๋น์ฒจ ๋ฒํธ์ ์ผ์น ๊ฐ์ ๊ณ์ฐ, ๋ณด๋์ค ํฌํจ ์ฌ๋ถ ํ์ธ |
-| `LottoFactory` | ๋ก๋ ๊ท์น์ ๋ง๋ ๋๋ค ๋ฒํธ๋ฅผ ์์ฑํ์ฌย `Lotto`ย ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ์ฑ
์์ ์ง | | -`Randoms.pickUniqueNumbersInRange()`๋ฅผ ์ฌ์ฉํด ๋ก๋ ๋ฒํธ ์์ฑ |
-| `WinningNumbers` | ๋น์ฒจ ๋ฒํธ์ ๋ณด๋์ค ๋ฒํธ๋ฅผ ๊ฐ์ง๋ฉฐ ๊ด๋ จ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ์ฑ
์์ง | * 6๊ฐ ๋น์ฒจ ๋ฒํธ, 1๊ฐ ๋ณด๋์ค ๋ฒํธ | - ๋น์ฒจ ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ, ๋ณด๋์ค ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์ค๋ณต ํ์ธ |
-| `LottoRank` | ๋น์ฒจ ๋ฑ์(1~5๋ฑ, ๊ฝ)์ ์กฐ๊ฑด(์ผ์น ๊ฐ์, ๋ณด๋์ค)๊ณผ ์๊ธ์ ์ ์ | *Enum class(์ผ์น ๊ฐ์, ๋ณด๋์ค ํฌํจ์ฌ๋ถ,๋น์ฒจ ๊ธ์ก) | - ์ผ์น ์/๋ณด๋์ค ํฌํจ ์ฌ๋ถ๋ก ๋ฑ์ ๋ฐํ, ์๊ธ ๋ฐํ |
-| `LottoResults` | ์ ์ฒด ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐ | * ๋ฑ์๋ณ ๋น์ฒจ ํ์, ๋์ ์๊ธ | - ๊ฐ ๋ก๋์ ๋ํ ๋ฑ์ ๊ณ์ฐ, ๋น์ฒจ ๊ฒฐ๊ณผ ๋์ , ์์ต๋ฅ ๊ณ์ฐ |
-| `InputView` | ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์
๋ ฅ ์ ๋์ฌ | - ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ์, `camp.nextstep.edu.missionutils.Console`์ย `readLine()`์ ์ฌ์ฉ |
-| `OutputView` | ์ฌ์ฉ์์๊ฒ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์ถ๋ ฅ ์ ๋์ฌ | - ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก ์ถ๋ ฅ, ๋น์ฒจ ๊ฒฐ๊ณผ ์ถ๋ ฅ, ์์ต๋ฅ ์ถ๋ ฅ |
-| `LottoController` | ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฒด ์คํ ํ๋ฆ์ ์กฐ์จ. View์ Domain ๊ฐ์ฒด๋ค์ ์ฐ๊ฒฐ | | - ์ ์ฒด ํ๋ฆ ์ ์ด |
+| ๊ฐ์ฒด ์ด๋ฆ | ์ญํ (์ฑ
์) | ๋ณด์ ๊ฐ(์ํ) | ์ฃผ์ ํ์ |
+|------------------------|---------------------------------------------|---------------------------------|------------------------------------------------------------------|
+| `Money` | ๊ตฌ์
๊ธ์ก์ ํํํ๊ณ ๊ด๋ จ ๊ท์น์ ๊ฒ์ฆํ๋ ๊ฐ ๊ฐ์ฒด | * ๊ตฌ์
๊ธ์ก | - ๊ธ์ก ์ ํจ์ฑ ๊ฒ์ฌ, ๊ตฌ๋งค ๊ฐ๋ฅํ ๋ก๋ ์ ๊ณ์ฐ |
+| `Lotto` | ๋ก๋ ํ ์ฅ์ ํํํ๋ฉฐ ๋ฒํธ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ๋ถ๋ณ์ฑ์ ๋ณด์ฅ | * 6๊ฐ์ ๋ก๋ ๋ฒํธ | - ๋ฒํธ ์ ๋ ฌ ๋ฐ ์ค๋ณต ๊ฒ์ฌ, ๋น์ฒจ ๋ฒํธ์ ์ผ์น ๊ฐ์ ๊ณ์ฐ, ๋ณด๋์ค ํฌํจ ์ฌ๋ถ ํ์ธ |
+| `LottoGenerator` | ๋ก๋ ๋ฒํธ ์์ฑ ์ ๋ต์ ์ถ์ํํ๋ ์ธํฐํ์ด์ค | | - ์์ฒญ๋ ๊ฐ์๋งํผ `Lotto` ๋ฆฌ์คํธ ์์ฑ |
+| `RandomLottoGenerator` | ๋๋ค ์ ๋ต์ผ๋ก ๋ก๋ ๊ท์น์ ๋ง๋ ๋ฒํธ๋ฅผ ์์ฑ | | - `Randoms.pickUniqueNumbersInRange()`๋ฅผ ์ฌ์ฉํด ๋ฒํธ ์์ฑ, `Lotto` ๊ฐ์ฒด ์์ฑ |
+| `LottoFactory` | ๋ก๋ ์์ฑ ์ ๋ต(`LottoGenerator`)์ ์์ฑ ์์ฒญ์ ์์ํ๋ ํฉํ ๋ฆฌ | * `LottoGenerator` ๊ตฌํ์ฒด | - ์์ฑ๊ธฐ null ๊ฒ์ฆ, ์์ฑ ๊ฐ์ ๊ฒ์ฆ, ์์ฑ๊ธฐ์ ๋ก๋ ์์ฑ ์์ |
+| `WinningNumbers` | ๋น์ฒจ ๋ฒํธ์ ๋ณด๋์ค ๋ฒํธ๋ฅผ ๊ฐ์ง๋ฉฐ ๊ด๋ จ ๊ท์น(๊ฐ์, ๋ฒ์, ์ค๋ณต)์ ์ฑ
์์ง | * 6๊ฐ ๋น์ฒจ ๋ฒํธ, 1๊ฐ ๋ณด๋์ค ๋ฒํธ | - ๋น์ฒจ ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ, ๋ณด๋์ค ๋ฒํธ ์ ํจ์ฑ ๊ฒ์ฌ ๋ฐ ์ค๋ณต ํ์ธ |
+| `LottoRank` | ๋น์ฒจ ๋ฑ์(1~5๋ฑ, ๊ฝ)์ ์กฐ๊ฑด(์ผ์น ๊ฐ์, ๋ณด๋์ค)๊ณผ ์๊ธ์ ์ ์ | * Enum(์ผ์น ๊ฐ์, ๋ณด๋์ค ํฌํจ ์ฌ๋ถ, ๋น์ฒจ ๊ธ์ก) | - ์ผ์น ์/๋ณด๋์ค ํฌํจ ์ฌ๋ถ๋ก ๋ฑ์ ๋ฐํ, ์๊ธ ๋ฐํ |
+| `LottoResults` | ์ ์ฒด ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐ | * ๋ฑ์๋ณ ๋น์ฒจ ํ์, ๋์ ์๊ธ | - ๊ฐ ๋ก๋์ ๋ํ ๋ฑ์ ๊ณ์ฐ, ๋น์ฒจ ๊ฒฐ๊ณผ ๋์ , ์์ต๋ฅ ๊ณ์ฐ |
+| `InputView` | ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์
๋ ฅ ์ ๋์ฌ | - ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ์, `Console.readLine()` ์ฌ์ฉ |
+| `OutputView` | ์ฌ์ฉ์์๊ฒ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์ถ๋ ฅ ์ ๋์ฌ | - ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก ์ถ๋ ฅ, ๋น์ฒจ ๊ฒฐ๊ณผ ์ถ๋ ฅ, ์์ต๋ฅ ์ถ๋ ฅ |
+| `LottoController` | ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฒด ์คํ ํ๋ฆ์ ์กฐ์จ. View์ Domain ๊ฐ์ฒด๋ค์ ์ฐ๊ฒฐ | | - ์ ์ฒด ํ๋ฆ ์ ์ด |
@@ -197,6 +204,8 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
| ๋ก๋ ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
| ๋ณด๋์ค ๋ฒํธ๊ฐ 1~45 ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ 1๋ถํฐ 45 ์ฌ์ด์ฌ์ผ ํฉ๋๋ค.` |
| ๋ณด๋์ค ๋ฒํธ๊ฐ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
+| ๋ก๋ ์์ฑ๊ธฐ๊ฐ null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ์์ฑ๊ธฐ๋ null์ผ ์ ์์ต๋๋ค.` |
+| ๋ก๋ ์์ฑ ๊ฐ์๊ฐ 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ์์ฑ ๊ฐ์๋ 1๊ฐ ์ด์์ด์ด์ผ ํฉ๋๋ค.` |
@@ -222,9 +231,9 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
๊ตฌํ ๊ณผ์ ์์ ๋ฐฐ์ฐ๊ณ ๊ณ ๋ฏผํ๋ ๊ฒ๋ค์ ๊ธฐ๋กํ๋ ๊ณต๊ฐ์
๋๋ค.
- [๋๋ฉ์ธ ์ค๊ณ์ ๊ณ ๋ คํ๋ ๊ฒ](https://github.com/JohnPrk/java-lotto-8/issues/1)
-- [Inside-Out vs Outside-In TDD ์ ํ ์ด์ ](https://github.com/JohnPrk/java-lotto-8/issues/2**)
-- [Supplier๋ ๋ฌด์์ธ๊ฐ?](https://github.com/JohnPrk/java-lotto-8/issues/3**)
-- [2023๋
๊ตฌํ vs ์ง๊ธ ๊ตฌํ ๋น๊ต[ํ๊ณ ]](https://github.com/JohnPrk/java-lotto-8/issues/4**)
+- [Inside-Out vs Outside-In TDD ์ ํ ์ด์ ](https://github.com/JohnPrk/java-lotto-8/issues/2)
+- [Supplier๋ ๋ฌด์์ธ๊ฐ?](https://github.com/JohnPrk/java-lotto-8/issues/3)
+- [2023๋
๊ตฌํ vs ์ง๊ธ ๊ตฌํ ๋น๊ต[ํ๊ณ ]](https://github.com/JohnPrk/java-lotto-8/issues/4)
diff --git a/src/main/java/lotto/domain/LottoFactory.java b/src/main/java/lotto/domain/LottoFactory.java
new file mode 100644
index 0000000000..8315a0c24b
--- /dev/null
+++ b/src/main/java/lotto/domain/LottoFactory.java
@@ -0,0 +1,30 @@
+package lotto.domain;
+
+import java.util.List;
+
+public class LottoFactory {
+
+ private final LottoGenerator generator;
+
+ public LottoFactory(LottoGenerator generator) {
+ validateGenerator(generator);
+ this.generator = generator;
+ }
+
+ public List generate(int count) {
+ validateCount(count);
+ return generator.generate(count);
+ }
+
+ private void validateGenerator(LottoGenerator generator) {
+ if (generator == null) {
+ throw new IllegalArgumentException("[ERROR] ๋ก๋ ์์ฑ๊ธฐ๋ null์ผ ์ ์์ต๋๋ค.");
+ }
+ }
+
+ private void validateCount(int count) {
+ if (count <= 0) {
+ throw new IllegalArgumentException("[ERROR] ๋ก๋ ์์ฑ ๊ฐ์๋ 1๊ฐ ์ด์์ด์ด์ผ ํฉ๋๋ค.");
+ }
+ }
+}
diff --git a/src/main/java/lotto/domain/LottoGenerator.java b/src/main/java/lotto/domain/LottoGenerator.java
new file mode 100644
index 0000000000..d3e9241185
--- /dev/null
+++ b/src/main/java/lotto/domain/LottoGenerator.java
@@ -0,0 +1,9 @@
+package lotto.domain;
+
+import java.util.List;
+
+public interface LottoGenerator {
+
+ List generate(int count);
+
+}
diff --git a/src/main/java/lotto/domain/RandomLottoGenerator.java b/src/main/java/lotto/domain/RandomLottoGenerator.java
new file mode 100644
index 0000000000..4897ff372b
--- /dev/null
+++ b/src/main/java/lotto/domain/RandomLottoGenerator.java
@@ -0,0 +1,23 @@
+package lotto.domain;
+
+import camp.nextstep.edu.missionutils.Randoms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RandomLottoGenerator implements LottoGenerator {
+
+ private static final int LOTTO_NUMBER_MIN = 1;
+ private static final int LOTTO_NUMBER_MAX = 45;
+ private static final int LOTTO_SIZE = 6;
+
+ @Override
+ public List generate(int count) {
+ List lottos = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ List numbers = Randoms.pickUniqueNumbersInRange(LOTTO_NUMBER_MIN, LOTTO_NUMBER_MAX, LOTTO_SIZE);
+ lottos.add(new Lotto(numbers));
+ }
+ return lottos;
+ }
+}
diff --git a/src/test/java/lotto/domain/FakeLottoGeneratorTest.java b/src/test/java/lotto/domain/FakeLottoGeneratorTest.java
new file mode 100644
index 0000000000..13a66540ee
--- /dev/null
+++ b/src/test/java/lotto/domain/FakeLottoGeneratorTest.java
@@ -0,0 +1,62 @@
+package lotto.domain;
+
+import lotto.domain.testDouble.FakeLottoGenerator;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class FakeLottoGeneratorTest {
+
+ @Test
+ void ์ค๋น๋_๋ฒํธ_์ํ์ค๋ฅผ_์ฌ์ฉํด_์์ฒญํ_๊ฐ์๋งํผ_๋ก๋๋ฅผ_์์ฑํ๋ค() {
+
+ // given
+ List> numbersSequences = List.of(
+ List.of(1, 2, 3, 4, 5, 6),
+ List.of(7, 8, 9, 10, 11, 12)
+ );
+ LottoGenerator generator = new FakeLottoGenerator(numbersSequences);
+
+ // when
+ List lottos = generator.generate(2);
+
+ // then
+ assertThat(lottos).hasSize(2);
+ assertThat(lottos.get(0).getNumbers()).containsExactly(1, 2, 3, 4, 5, 6);
+ assertThat(lottos.get(1).getNumbers()).containsExactly(7, 8, 9, 10, 11, 12);
+ }
+
+ @Test
+ void ์ค๋น๋_๋ฒํธ๋ณด๋ค_๋ง์_๊ฐ์๋ฅผ_์์ฒญํ๋ฉด_NoSuchElementException์ด_๋ฐ์ํ๋ค() {
+
+ // given
+ List> numbersSequences = List.of(
+ List.of(1, 2, 3, 4, 5, 6)
+ );
+ LottoGenerator generator = new FakeLottoGenerator(numbersSequences);
+
+ // when & then
+ assertThatThrownBy(() -> generator.generate(2))
+ .isInstanceOf(NoSuchElementException.class);
+ }
+
+ @Test
+ void of_์ ์ _ํฉํฐ๋ฆฌ_๋ฉ์๋๋_๋จ์ผ_๋ฒํธ_์ธํธ๋ก_๋ก๋๋ฅผ_์์ฑํ๋ค() {
+
+ // given
+ FakeLottoGenerator generator = FakeLottoGenerator.of(
+ List.of(1, 2, 3, 4, 5, 6)
+ );
+
+ // when
+ List lottos = generator.generate(1);
+
+ // then
+ assertThat(lottos).hasSize(1);
+ assertThat(lottos.get(0).getNumbers()).containsExactly(1, 2, 3, 4, 5, 6);
+ }
+}
diff --git a/src/test/java/lotto/domain/LottoFactoryTest.java b/src/test/java/lotto/domain/LottoFactoryTest.java
new file mode 100644
index 0000000000..a2f0bd5791
--- /dev/null
+++ b/src/test/java/lotto/domain/LottoFactoryTest.java
@@ -0,0 +1,61 @@
+package lotto.domain;
+
+import lotto.domain.testDouble.FakeLottoGenerator;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class LottoFactoryTest {
+
+ @Test
+ void ์ ํจํ_์์ฑ๊ธฐ์_๊ฐ์๋ก_๋ก๋_๋ชฉ๋ก์_์์ฑํ๋ค() {
+
+ // given
+ FakeLottoGenerator generator = new FakeLottoGenerator(
+ List.of(
+ List.of(1, 2, 3, 4, 5, 6),
+ List.of(7, 8, 9, 10, 11, 12),
+ List.of(13, 14, 15, 16, 17, 18)
+ )
+ );
+ LottoFactory factory = new LottoFactory(generator);
+ int count = 3;
+
+ // when
+ List lottos = factory.generate(count);
+
+ // then
+ assertThat(lottos).hasSize(count);
+ assertThat(lottos).allSatisfy(lotto -> assertThat(lotto).isNotNull());
+ }
+
+ @ParameterizedTest
+ @NullSource
+ void ์์ฑ๊ธฐ๊ฐ_null์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(LottoGenerator generator) {
+
+ // when & then
+ assertThatThrownBy(() -> new LottoFactory(generator))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ์์ฑ๊ธฐ๋ null์ผ ์ ์์ต๋๋ค.");
+ }
+
+ @ParameterizedTest
+ @ValueSource(ints = {0, -1, -10})
+ void ์์ฑ_๊ฐ์๊ฐ_0_์ดํ์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(int count) {
+
+ // given
+ LottoGenerator generator = FakeLottoGenerator.of(List.of(1, 2, 3, 4, 5, 6));
+ LottoFactory factory = new LottoFactory(generator);
+
+ // when & then
+ assertThatThrownBy(() -> factory.generate(count))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ก๋ ์์ฑ ๊ฐ์๋ 1๊ฐ ์ด์์ด์ด์ผ ํฉ๋๋ค.");
+ }
+}
diff --git a/src/test/java/lotto/domain/RandomLottoGeneratorTest.java b/src/test/java/lotto/domain/RandomLottoGeneratorTest.java
new file mode 100644
index 0000000000..18d47aa941
--- /dev/null
+++ b/src/test/java/lotto/domain/RandomLottoGeneratorTest.java
@@ -0,0 +1,25 @@
+package lotto.domain;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class RandomLottoGeneratorTest {
+
+ @Test
+ void ๋ก๋_์์ฑ_์์ฒญ_๊ฐ์๋งํผ_๋๋ค_๋ก๋๋ฅผ_์์ฑํ๋ค() {
+
+ // given
+ LottoGenerator generator = new RandomLottoGenerator();
+ int count = 5;
+
+ // when
+ List lottos = generator.generate(count);
+
+ // then
+ assertThat(lottos).hasSize(count)
+ .doesNotContainNull();
+ }
+}
diff --git a/src/test/java/lotto/domain/testDouble/FakeLottoGenerator.java b/src/test/java/lotto/domain/testDouble/FakeLottoGenerator.java
new file mode 100644
index 0000000000..012f2aed3c
--- /dev/null
+++ b/src/test/java/lotto/domain/testDouble/FakeLottoGenerator.java
@@ -0,0 +1,31 @@
+package lotto.domain.testDouble;
+
+import lotto.domain.Lotto;
+import lotto.domain.LottoGenerator;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class FakeLottoGenerator implements LottoGenerator {
+
+ private final Iterator> numbersIterator;
+
+ public FakeLottoGenerator(List> numbersSequences) {
+ this.numbersIterator = numbersSequences.iterator();
+ }
+
+ @Override
+ public List generate(int count) {
+ List lottos = new ArrayList<>();
+ for (int i = 0; i < count; i++) {
+ List numbers = numbersIterator.next();
+ lottos.add(new Lotto(numbers));
+ }
+ return lottos;
+ }
+
+ public static FakeLottoGenerator of(List numbers) {
+ return new FakeLottoGenerator(List.of(numbers));
+ }
+}
From e4cd27c750a04949163455ed758eb68d0c299b1f Mon Sep 17 00:00:00 2001
From: JohnPrk
Date: Mon, 3 Nov 2025 23:03:42 +0900
Subject: [PATCH 09/10] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?=
=?UTF-8?q?=EC=9E=85=EC=B6=9C=EB=A0=A5=EC=9D=84=20=EB=8B=B4=EB=8B=B9?=
=?UTF-8?q?=ED=95=98=EB=8A=94=20View=20=EB=B0=8F=20InputValidator=20?=
=?UTF-8?q?=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- InputView: ๊ตฌ์
๊ธ์ก, ๋น์ฒจ ๋ฒํธ, ๋ณด๋์ค ๋ฒํธ ์
๋ ฅ ๊ธฐ๋ฅ ๊ตฌํ
- OutputView: ๊ตฌ๋งค ๋ก๋, ๋น์ฒจ ํต๊ณ, ์์ต๋ฅ , ์๋ฌ ๋ฉ์์ง ์ถ๋ ฅ ๊ธฐ๋ฅ ๊ตฌํ
- InputValidator: View๋ก๋ถํฐ ๋ฐ์ ์
๋ ฅ์ ํ์(๊ณต๋ฐฑ, ์ซ์) ๊ฒ์ฆ ๋ก์ง ๋ถ๋ฆฌ
- InputValidator ๊ด๋ จ ๋จ์ ํ
์คํธ ์์ฑ
- README.md ์์ธ ์ฒ๋ฆฌ ํ์ InputValidator ๊ด๋ จ ์์ธ ๋ฉ์์ง ์ถ๊ฐ
---
README.md | 7 +-
src/main/java/lotto/view/InputValidator.java | 54 +++++++
src/main/java/lotto/view/InputView.java | 29 ++++
src/main/java/lotto/view/OutputView.java | 41 ++++++
.../java/lotto/view/InputValidatorTest.java | 132 ++++++++++++++++++
5 files changed, 262 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/lotto/view/InputValidator.java
create mode 100644 src/main/java/lotto/view/InputView.java
create mode 100644 src/main/java/lotto/view/OutputView.java
create mode 100644 src/test/java/lotto/view/InputValidatorTest.java
diff --git a/README.md b/README.md
index b4ed73b18e..b90b672af2 100644
--- a/README.md
+++ b/README.md
@@ -120,6 +120,7 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
| `LottoResults` | ์ ์ฒด ๋น์ฒจ ๊ฒฐ๊ณผ๋ฅผ ์ง๊ณํ๊ณ ์ต์ข
์์ต๋ฅ ์ ๊ณ์ฐ | * ๋ฑ์๋ณ ๋น์ฒจ ํ์, ๋์ ์๊ธ | - ๊ฐ ๋ก๋์ ๋ํ ๋ฑ์ ๊ณ์ฐ, ๋น์ฒจ ๊ฒฐ๊ณผ ๋์ , ์์ต๋ฅ ๊ณ์ฐ |
| `InputView` | ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์
๋ ฅ ์ ๋์ฌ | - ์ฌ์ฉ์๋ก๋ถํฐ ์
๋ ฅ์ ๋ฐ์, `Console.readLine()` ์ฌ์ฉ |
| `OutputView` | ์ฌ์ฉ์์๊ฒ ์ ๋ณด๋ฅผ ์ถ๋ ฅํ๋ ๋ชจ๋ ๋ก์ง์ ๋ด๋น | * ์ถ๋ ฅ ์ ๋์ฌ | - ๊ตฌ๋งคํ ๋ก๋ ๋ชฉ๋ก ์ถ๋ ฅ, ๋น์ฒจ ๊ฒฐ๊ณผ ์ถ๋ ฅ, ์์ต๋ฅ ์ถ๋ ฅ |
+| `InputValidator` | ๋ฌธ์์ด ์
๋ ฅ์ ์ซ์/๋ฆฌ์คํธ๋ก ๋ณํํ๊ณ ํ์์ ๊ฒ์ฆํ๋ ์ ํธ๋ฆฌํฐ | - | - ๊ตฌ์
๊ธ์ก/๋น์ฒจ ๋ฒํธ/๋ณด๋์ค ๋ฒํธ ๋ฌธ์์ด ํ์ฑ, ๊ณต๋ฐฑ ๋ฐ ์ซ์ ํ์ ๊ฒ์ฆ |
| `LottoController` | ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฒด ์คํ ํ๋ฆ์ ์กฐ์จ. View์ Domain ๊ฐ์ฒด๋ค์ ์ฐ๊ฒฐ | | - ์ ์ฒด ํ๋ฆ ์ ์ด |
@@ -155,7 +156,7 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
> ๋๋ฉ์ธ ๊ท์น์ ๋ฐ๋ผ ๋ก๋๋ฅผ ์์ฑํ๋ ์ฑ
์์ ๊ตฌํํฉ๋๋ค.
>
-- `LottoFactory`: `Randoms` ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๋ ๋ฒํธ๋ฅผ ์์ฑํ๊ณ , ๊ฒ์ฆ๋ `Lotto` ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ฐํํฉ๋๋ค.
+- `LottoFactory`: `LottoGenerator`๋ฅผ ์ฌ์ฉํด ๊ท์น์ ๋ง๋ ๋ก๋ ๋ชฉ๋ก์ ์์ฑํฉ๋๋ค.
### **5๋จ๊ณ: ์
์ถ๋ ฅ(UI) ๊ณ์ธต ๊ตฌํ**
@@ -206,6 +207,10 @@ Note over U,C: ๐ 2๋จ๊ณ: ๋น์ฒจ ๋ฒํธ ์
๋ ฅ
| ๋ณด๋์ค ๋ฒํธ๊ฐ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ๋น์ฒจ ๋ฒํธ์ ์ค๋ณต๋ ์ ์์ต๋๋ค.` |
| ๋ก๋ ์์ฑ๊ธฐ๊ฐ null์ธ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ์์ฑ๊ธฐ๋ null์ผ ์ ์์ต๋๋ค.` |
| ๋ก๋ ์์ฑ ๊ฐ์๊ฐ 0 ์ดํ์ธ ๊ฒฝ์ฐ | `[ERROR] ๋ก๋ ์์ฑ ๊ฐ์๋ 1๊ฐ ์ด์์ด์ด์ผ ํฉ๋๋ค.` |
+| ์
๋ ฅ ๋ฌธ์์ด์ด null ๋๋ ๊ณต๋ฐฑ์ธ ๊ฒฝ์ฐ | `[ERROR] ์
๋ ฅ์ ๋น์ด ์์ ์ ์์ต๋๋ค.` |
+| ๊ตฌ์
๊ธ์ก ์
๋ ฅ์ด ์ซ์๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] ๊ตฌ์
๊ธ์ก์ ์ซ์์ฌ์ผ ํฉ๋๋ค.` |
+| ๋น์ฒจ ๋ฒํธ ์
๋ ฅ์ ์ซ์๊ฐ ์๋ ๊ฐ์ด ํฌํจ๋ ๊ฒฝ์ฐ | `[ERROR] ๋น์ฒจ ๋ฒํธ๋ ์ซ์์ฌ์ผ ํฉ๋๋ค.` |
+| ๋ณด๋์ค ๋ฒํธ ์
๋ ฅ์ด ์ซ์๊ฐ ์๋ ๊ฒฝ์ฐ | `[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ์ซ์์ฌ์ผ ํฉ๋๋ค.` |
diff --git a/src/main/java/lotto/view/InputValidator.java b/src/main/java/lotto/view/InputValidator.java
new file mode 100644
index 0000000000..17c772e86b
--- /dev/null
+++ b/src/main/java/lotto/view/InputValidator.java
@@ -0,0 +1,54 @@
+package lotto.view;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class InputValidator {
+
+ private static final String NUMBER_DELIMITER = ",";
+
+ private InputValidator() {
+ }
+
+ public static int parsePurchaseAmount(String input) {
+ validateNotBlank(input);
+ String trimmed = input.trim();
+ try {
+ return Integer.parseInt(trimmed);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("[ERROR] ๊ตฌ์
๊ธ์ก์ ์ซ์์ฌ์ผ ํฉ๋๋ค.");
+ }
+ }
+
+ public static List parseWinningNumbers(String input) {
+ validateNotBlank(input);
+ String[] parts = input.split(NUMBER_DELIMITER);
+ return Arrays.stream(parts)
+ .map(String::trim)
+ .map(part -> parseNumber(part, "[ERROR] ๋น์ฒจ ๋ฒํธ๋ ์ซ์์ฌ์ผ ํฉ๋๋ค."))
+ .toList();
+ }
+
+ public static int parseBonusNumber(String input) {
+ validateNotBlank(input);
+ String trimmed = input.trim();
+ return parseNumber(trimmed, "[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ์ซ์์ฌ์ผ ํฉ๋๋ค.");
+ }
+
+ private static void validateNotBlank(String input) {
+ if (input == null) {
+ throw new IllegalArgumentException("[ERROR] ์
๋ ฅ์ ๋น์ด ์์ ์ ์์ต๋๋ค.");
+ }
+ if (input.trim().isEmpty()) {
+ throw new IllegalArgumentException("[ERROR] ์
๋ ฅ์ ๋น์ด ์์ ์ ์์ต๋๋ค.");
+ }
+ }
+
+ private static int parseNumber(String value, String errorMessage) {
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException(errorMessage);
+ }
+ }
+}
diff --git a/src/main/java/lotto/view/InputView.java b/src/main/java/lotto/view/InputView.java
new file mode 100644
index 0000000000..6d48cbfb6f
--- /dev/null
+++ b/src/main/java/lotto/view/InputView.java
@@ -0,0 +1,29 @@
+package lotto.view;
+
+import camp.nextstep.edu.missionutils.Console;
+
+import java.util.List;
+
+public class InputView {
+
+ public static int readPurchaseAmount() {
+ System.out.println("๊ตฌ์
๊ธ์ก์ ์
๋ ฅํด ์ฃผ์ธ์.");
+ String input = Console.readLine();
+ System.out.println();
+ return InputValidator.parsePurchaseAmount(input);
+ }
+
+ public static List readWinningNumbers() {
+ System.out.println("๋น์ฒจ ๋ฒํธ๋ฅผ ์
๋ ฅํด ์ฃผ์ธ์.");
+ String input = Console.readLine();
+ System.out.println();
+ return InputValidator.parseWinningNumbers(input);
+ }
+
+ public static int readBonusNumber() {
+ System.out.println("๋ณด๋์ค ๋ฒํธ๋ฅผ ์
๋ ฅํด ์ฃผ์ธ์.");
+ String input = Console.readLine();
+ System.out.println();
+ return InputValidator.parseBonusNumber(input);
+ }
+}
diff --git a/src/main/java/lotto/view/OutputView.java b/src/main/java/lotto/view/OutputView.java
new file mode 100644
index 0000000000..60569371a9
--- /dev/null
+++ b/src/main/java/lotto/view/OutputView.java
@@ -0,0 +1,41 @@
+package lotto.view;
+
+import lotto.domain.Lotto;
+import lotto.domain.LottoRank;
+import lotto.domain.LottoResults;
+
+import java.util.List;
+
+public class OutputView {
+
+ public static void printLottos(List lottos) {
+ System.out.printf("%d๊ฐ๋ฅผ ๊ตฌ๋งคํ์ต๋๋ค.%n", lottos.size());
+ for (Lotto lotto : lottos) {
+ System.out.println(lotto.getNumbers());
+ }
+ }
+
+ public static void printStatistics(LottoResults results) {
+ System.out.println("๋น์ฒจ ํต๊ณ");
+ System.out.println("---");
+ printRankResult(results, LottoRank.FIFTH, "3๊ฐ ์ผ์น (5,000์) - %d๊ฐ");
+ printRankResult(results, LottoRank.FOURTH, "4๊ฐ ์ผ์น (50,000์) - %d๊ฐ");
+ printRankResult(results, LottoRank.THIRD, "5๊ฐ ์ผ์น (1,500,000์) - %d๊ฐ");
+ printRankResult(results, LottoRank.SECOND, "5๊ฐ ์ผ์น, ๋ณด๋์ค ๋ณผ ์ผ์น (30,000,000์) - %d๊ฐ");
+ printRankResult(results, LottoRank.FIRST, "6๊ฐ ์ผ์น (2,000,000,000์) - %d๊ฐ");
+ }
+
+ private static void printRankResult(LottoResults results, LottoRank rank, String format) {
+ int count = results.getCountOf(rank);
+ System.out.printf(format + "%n", count);
+ }
+
+ public static void printYield(double yield) {
+ double percentage = yield * 100;
+ System.out.printf("์ด ์์ต๋ฅ ์ %.1f%%์
๋๋ค.%n", percentage);
+ }
+
+ public static void printError(String message) {
+ System.out.println(message);
+ }
+}
diff --git a/src/test/java/lotto/view/InputValidatorTest.java b/src/test/java/lotto/view/InputValidatorTest.java
new file mode 100644
index 0000000000..e6da7d9c90
--- /dev/null
+++ b/src/test/java/lotto/view/InputValidatorTest.java
@@ -0,0 +1,132 @@
+package lotto.view;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class InputValidatorTest {
+
+ @Test
+ void ๊ตฌ์
_๊ธ์ก_๋ฌธ์์ด์_์ ์๋ก_ํ์ฑํ๋ค() {
+
+ // given
+ String input = "3000";
+
+ // when
+ int amount = InputValidator.parsePurchaseAmount(input);
+
+ // then
+ assertThat(amount).isEqualTo(3000);
+ }
+
+ @ParameterizedTest
+ @NullSource
+ @ValueSource(strings = {"", " ", " "})
+ void ๊ตฌ์
_๊ธ์ก_์
๋ ฅ์ด_null_๋๋_๊ณต๋ฐฑ์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(String input) {
+
+ // when & then
+ assertThatThrownBy(() -> InputValidator.parsePurchaseAmount(input))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ์
๋ ฅ์ ๋น์ด ์์ ์ ์์ต๋๋ค.");
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"abc", "1000์", "1 000", "1,000"})
+ void ๊ตฌ์
_๊ธ์ก์_์ซ์๊ฐ_์๋_๊ฐ์ด_ํฌํจ๋๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(String input) {
+
+ // when & then
+ assertThatThrownBy(() -> InputValidator.parsePurchaseAmount(input))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๊ตฌ์
๊ธ์ก์ ์ซ์์ฌ์ผ ํฉ๋๋ค.");
+ }
+
+ @Test
+ void ์ผํ๋ก_๊ตฌ๋ถ๋_๋น์ฒจ_๋ฒํธ๋ฅผ_์ ์_๋ฆฌ์คํธ๋ก_ํ์ฑํ๋ค() {
+
+ // given
+ String input = "1,2,3,4,5,6";
+
+ // when
+ List numbers = InputValidator.parseWinningNumbers(input);
+
+ // then
+ assertThat(numbers).containsExactly(1, 2, 3, 4, 5, 6);
+ }
+
+ @Test
+ void ๋น์ฒจ_๋ฒํธ_ํ์ฑ์_๊ณต๋ฐฑ์_๋ฌด์ํ๋ค() {
+
+ // given
+ String input = " 1, 2 ,3 , 4,5 ,6 ";
+
+ // when
+ List numbers = InputValidator.parseWinningNumbers(input);
+
+ // then
+ assertThat(numbers).containsExactly(1, 2, 3, 4, 5, 6);
+ }
+
+ @ParameterizedTest
+ @NullSource
+ @ValueSource(strings = {"", " ", " "})
+ void ๋น์ฒจ_๋ฒํธ_์
๋ ฅ์ด_null_๋๋_๊ณต๋ฐฑ์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(String input) {
+
+ // when & then
+ assertThatThrownBy(() -> InputValidator.parseWinningNumbers(input))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ์
๋ ฅ์ ๋น์ด ์์ ์ ์์ต๋๋ค.");
+ }
+
+ @Test
+ void ๋น์ฒจ_๋ฒํธ์_์ซ์๊ฐ_์๋_๊ฐ์ด_ํฌํจ๋๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+
+ // given
+ String input = "1, 2, ์ธ, 4, 5, 6";
+
+ // when & then
+ assertThatThrownBy(() -> InputValidator.parseWinningNumbers(input))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋น์ฒจ ๋ฒํธ๋ ์ซ์์ฌ์ผ ํฉ๋๋ค.");
+ }
+
+ @Test
+ void ๋ณด๋์ค_๋ฒํธ_๋ฌธ์์ด์_์ ์๋ก_ํ์ฑํ๋ค() {
+
+ // given
+ String input = "7";
+
+ // when
+ int bonus = InputValidator.parseBonusNumber(input);
+
+ // then
+ assertThat(bonus).isEqualTo(7);
+ }
+
+ @ParameterizedTest
+ @NullSource
+ @ValueSource(strings = {"", " ", " "})
+ void ๋ณด๋์ค_๋ฒํธ_์
๋ ฅ์ด_null_๋๋_๊ณต๋ฐฑ์ด๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค(String input) {
+
+ // when & then
+ assertThatThrownBy(() -> InputValidator.parseBonusNumber(input))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ์
๋ ฅ์ ๋น์ด ์์ ์ ์์ต๋๋ค.");
+ }
+
+ @Test
+ void ๋ณด๋์ค_๋ฒํธ์_์ซ์๊ฐ_์๋_๊ฐ์ด_๋ค์ด์ค๋ฉด_์์ธ๊ฐ_๋ฐ์ํ๋ค() {
+ // given
+ String input = "๋ณด๋์ค";
+
+ // when & then
+ assertThatThrownBy(() -> InputValidator.parseBonusNumber(input))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("[ERROR] ๋ณด๋์ค ๋ฒํธ๋ ์ซ์์ฌ์ผ ํฉ๋๋ค.");
+ }
+}
From a6c5c18dae9633a04ebba72f6d3a3f85345ca0fa Mon Sep 17 00:00:00 2001
From: JohnPrk
Date: Mon, 3 Nov 2025 23:38:27 +0900
Subject: [PATCH 10/10] =?UTF-8?q?feat:=20=EB=A1=9C=EB=98=90=20=EA=B2=8C?=
=?UTF-8?q?=EC=9E=84=20=EC=A0=84=EC=B2=B4=20=EC=8B=A4=ED=96=89=20=ED=9D=90?=
=?UTF-8?q?=EB=A6=84=EC=9D=84=20=EC=A0=9C=EC=96=B4=ED=95=98=EB=8A=94=20Lot?=
=?UTF-8?q?toController=20=EB=B0=8F=20Application=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- LottoController์์ ๊ตฌ์
๊ธ์ก ์
๋ ฅ โ ๋ก๋ ์์ฑ โ ๋น์ฒจ ๋ฒํธ ์
๋ ฅ โ ๊ฒฐ๊ณผ ์ง๊ณ โ ์์ต๋ฅ ์ถ๋ ฅ๊น์ง ์ ์ฒด ์๋๋ฆฌ์ค ์ ์ด
- ์๋ชป๋ ์
๋ ฅ, ๊ธ์ก, ๋น์ฒจ ๋ฒํธ, ๋ณด๋์ค ๋ฒํธ์ ๋ํด ์์ธ ๋ฉ์์ง ์ถ๋ ฅ ํ ์ฌ์
๋ ฅ ๋ฐ๋๋ก ๋ฐ๋ณต ์ฒ๋ฆฌ
- Money ๊ฐ์ ํ์ฉํด ๊ตฌ๋งค ๊ฐ๋ฅ ๋ก๋ ์ ๊ณ์ฐ ๋ฐ ์์ต๋ฅ ๊ณ์ฐ ์ ๊ตฌ์
๊ธ์ก ์ ๋ฌ
- Application main์์ LottoFactory, RandomLottoGenerator, LottoController๋ฅผ ์กฐ๋ฆฝํด ํ๋ก๊ทธ๋จ ์คํ ์ง์
์ ๊ตฌ์ฑ
---
src/main/java/lotto/Application.java | 9 ++-
.../lotto/controller/LottoController.java | 71 +++++++++++++++++++
src/main/java/lotto/domain/Money.java | 4 ++
3 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/lotto/controller/LottoController.java
diff --git a/src/main/java/lotto/Application.java b/src/main/java/lotto/Application.java
index d190922ba4..14e77be8a8 100644
--- a/src/main/java/lotto/Application.java
+++ b/src/main/java/lotto/Application.java
@@ -1,7 +1,14 @@
package lotto;
+import lotto.controller.LottoController;
+import lotto.domain.LottoFactory;
+import lotto.domain.RandomLottoGenerator;
+
public class Application {
+
public static void main(String[] args) {
- // TODO: ํ๋ก๊ทธ๋จ ๊ตฌํ
+ LottoFactory lottoFactory = new LottoFactory(new RandomLottoGenerator());
+ LottoController controller = new LottoController(lottoFactory);
+ controller.run();
}
}
diff --git a/src/main/java/lotto/controller/LottoController.java b/src/main/java/lotto/controller/LottoController.java
new file mode 100644
index 0000000000..5864bd78c5
--- /dev/null
+++ b/src/main/java/lotto/controller/LottoController.java
@@ -0,0 +1,71 @@
+package lotto.controller;
+
+import lotto.domain.*;
+import lotto.view.InputView;
+import lotto.view.OutputView;
+
+import java.util.List;
+
+public class LottoController {
+
+ private final LottoFactory lottoFactory;
+
+ public LottoController(LottoFactory lottoFactory) {
+ this.lottoFactory = lottoFactory;
+ }
+
+ public void run() {
+ Money money = readMoney();
+ int lottoCount = money.getLottoCount();
+ List lottos = lottoFactory.generate(lottoCount);
+ OutputView.printLottos(lottos);
+ WinningNumbers winningNumbers = readWinningNumbers();
+ LottoResults results = new LottoResults(lottos, winningNumbers);
+ OutputView.printStatistics(results);
+ double yield = results.calculateYield(money.getAmount());
+ OutputView.printYield(yield);
+ }
+
+ private Money readMoney() {
+ while (true) {
+ try {
+ int purchaseAmount = InputView.readPurchaseAmount();
+ return new Money(purchaseAmount);
+ } catch (IllegalArgumentException e) {
+ OutputView.printError(e.getMessage());
+ }
+ }
+ }
+
+ private WinningNumbers readWinningNumbers() {
+ while (true) {
+ try {
+ List numbers = readWinningNumberList();
+ int bonus = readBonusNumber();
+ return new WinningNumbers(numbers, bonus);
+ } catch (IllegalArgumentException e) {
+ OutputView.printError(e.getMessage());
+ }
+ }
+ }
+
+ private List readWinningNumberList() {
+ while (true) {
+ try {
+ return InputView.readWinningNumbers();
+ } catch (IllegalArgumentException e) {
+ OutputView.printError(e.getMessage());
+ }
+ }
+ }
+
+ private int readBonusNumber() {
+ while (true) {
+ try {
+ return InputView.readBonusNumber();
+ } catch (IllegalArgumentException e) {
+ OutputView.printError(e.getMessage());
+ }
+ }
+ }
+}
diff --git a/src/main/java/lotto/domain/Money.java b/src/main/java/lotto/domain/Money.java
index a564f220e7..257fdfee61 100644
--- a/src/main/java/lotto/domain/Money.java
+++ b/src/main/java/lotto/domain/Money.java
@@ -11,6 +11,10 @@ public Money(int amount) {
this.amount = amount;
}
+ public int getAmount() {
+ return amount;
+ }
+
private void validatePositive(int amount) {
if (amount <= 0) {
throw new IllegalArgumentException("[ERROR] ๊ตฌ์
๊ธ์ก์ 0๋ณด๋ค ์ปค์ผ ํฉ๋๋ค.");