-
Notifications
You must be signed in to change notification settings - Fork 248
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: 구입 금액 검증(단위, 문자열) 구입 금액이 1000원 단위로 들어오는 경우 예외처리 구입 금액에 문자열을 입력받은 경우 예외처리 * feat : 로또 한장을 의미하는 Number 객체 검증 * feat : Lotto 한장을 담당하는 객체 검증 * feat : LottoFactory 및 Lottos 구현 및 검증 * feat : 보너스번호와 당첨번호를 관리하기 위한 객체 추가 * feat : 당첨 통계를 위한 클래스 추가 * docs : WinningNumber와 BonusNumber 관련 할 일 추가 * feat : 보너스넘버가 당첨번호와 중첩되지 않도록 개발 * refactor : equals를 사용해서 객체간의 비교 * copy branch * refactor : BonusNumber 클래스 삭제 및 리팩토링 * refactor : WinningNumbers 클래스 삭제 및 리팩토링 * refactor : 객체의 역할에 맞게 기능 재 분배 * refactor : 리팩토링한 클래스 및 테스트 추가 * 임시커밋 * refactor : 피드백 반영 Lotto 숫자 갯수 상수화 Lottos 생성 과정 중복 제거 (create()) 처리불가능한 에러 제거(Rank의 DEFAULT 추가) Count 클래스 구현을 통해 멀티스레딩환경에서의 enum의 문제점 보완 Number 클래스 내의 NumberPool을 NumberFactory로 이동 세미콜론제거 숫자리터럴 자릿수 구분 Rank 보너스 일치 여부 추가 Lottos 테스트 위치 변경 * refactor: 컨벤션 맞춤 * refactor: 피드백 반영 Profit을 return 하는 메서드 구현 후 필드에서 제거 checkBonus 메서드를 통해 중복 제거 GameResult 디폴트생성자로 변경 enum 메소드 수정 Co-authored-by: KIMSIYOUNG <[email protected]>
- Loading branch information
1 parent
e984845
commit 01f8895
Showing
31 changed files
with
1,194 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,109 @@ | ||
# java-lotto | ||
로또 미션 진행을 위한 저장소 | ||
## 로또 미션을 위한 저장소 | ||
|
||
--- | ||
|
||
## 게임 순서 | ||
|
||
- 구입 금액을 입력 받는다. | ||
|
||
- 1000단위가 아닌 경우는 예외처리 | ||
- 문자열이 포함되는 경우 예외처리 | ||
- 공백 및 NULL 예외처리 | ||
- 1000원 ~ 100,000원까지만 가능 | ||
- 구입 금액 또한 클래스로 분리하고 | ||
- 기능은 생성자를 통한 검증 | ||
- 장수를 계산해서 보내는 부분도 | ||
|
||
- 금액 / 1000 의 갯수만큼 로또를 자동으로 생성 및 출력한다. | ||
|
||
- Number : 각각의 수 | ||
- 1~45 사이의 값인지 | ||
- 문자열이 포함되는 경우 예외처리 | ||
- 공백 및 NULL 예외처리 | ||
- Number를 6개 가지고 있는 로또 한 장을 지칭하는 객체(Lotto) | ||
- `Lotto.size()` = 6 | ||
- 중복된 수가 있으면 안된다. | ||
- Lotto 를 금액 / 1000만큼 생성한다. | ||
- Lotto를 구매한 만큼 가지고 있는 Lottos 객체를 생성한다. | ||
- 금액 / 1000 == Lottos.size() | ||
- 이렇게 생성된 Lottos 를 출력한다. | ||
|
||
- 당첨번호(보너스 번호 제외) 6자리를 `,` 를 기준으로 분리한다. | ||
- 싱글톤 ? | ||
- 당첨번호를 담당하는 WinningLotto 객체를 생성한다. | ||
- 공백 및 NULL 예외처리 | ||
- 데이터 타입 처리 | ||
- 갯수 6개 | ||
- 번호의 범위 | ||
- 각각 다른 번호인지 | ||
|
||
- 보너스 볼 하나를 입력한다 | ||
- 보너스 볼 객체 Bonus | ||
- Number 하나를 갖는 객체 | ||
|
||
- 당첨 통계를 출력한다 | ||
- LottoModel ← Lottos , Winning | ||
- OutputView | ||
- Enum 에서 맞힌 갯수, 금액, 몇장인지를 가지는 Enum에서 처리 | ||
|
||
- 참고 | ||
- 숫자를 생성할 때 그리고 보너스 넘버를 생성할 때 로직이 겹치니까 해결책으로 | ||
- Validator를 따로 둔다. | ||
- Number를 상속받는다. | ||
|
||
### 구현 순서 | ||
|
||
- 구입 금액 테스트 | ||
- [x] 1000단위가 아닌 경우는 예외처리 | ||
- [x] 문자열이 포함되는 경우 예외처리 | ||
- [x] 공백 및 NULL 예외처리 | ||
- [x] 1000원 ~ 100,000원까지만 가능 | ||
- [x] 장수로 변환하는 매소드 추가 | ||
- Utility 클래스 검증 | ||
- [x] 공백 제거 | ||
- [x] `,` Parsing 검증 | ||
|
||
- Number | ||
- [x] 1~45 사이의 값인지 | ||
- [x] 문자열이 포함되는 경우 예외처리 | ||
- [x] 공백 및 NULL 예외처리 | ||
- Enum을 통해서 Number 기능을 같이 하는 방안 고려 (현재 static 부분) | ||
|
||
- LottoFactory | ||
|
||
- Lotto | ||
- [x] `Lotto.size()` = 6 | ||
- [x] 중복된 수가 있으면 안된다. | ||
|
||
- Lottos | ||
- [x] Lotto를 구매한 만큼 가지고 있는 Lottos 객체를 생성한다 | ||
- [x] 금액 / 1000 == Lottos.size() | ||
|
||
- WinningLotto | ||
- [x] 보너스넘버와 WinningNumbers의 값이 겹치지 않아야 한다. | ||
- [x] BonusNumber (상속 : Number) | ||
- [x] WinningNumbers | ||
- [x] 상속받고 있고 (Lotto) : 로직이 같고, 로또와 의미를 구분하기 위함 | ||
|
||
- [x] Result | ||
- 인자 : WinningLotto, Lottos | ||
- 기능 | ||
- [x] 맞힌 갯수별로 장수 + 수익금 계산 | ||
- [x] 수익률 | ||
- [x] OutputView 보내기 | ||
|
||
### 프로그래밍 요구사항 | ||
|
||
- indent(인덴트, 들여쓰기) depth를 2단계에서 1단계로 줄여라. | ||
- depth의 경우 if문을 사용하는 경우 1단계의 depth가 증가한다. if문 안에 while문을 사용한다면 depth가 2단계가 된다. | ||
- else를 사용하지 마라. | ||
- 메소드의 크기가 최대 10라인을 넘지 않도록 구현한다. | ||
- method가 한 가지 일만 하도록 최대한 작게 만들어라. | ||
- **배열 대신 ArrayList를 사용한다.** | ||
- enum을 적용해 프로그래밍을 구현한다. | ||
|
||
### 힌트 | ||
|
||
- 로또 자동 생성은 Collections.shuffle() 메소드 활용한다. | ||
- Collections.sort() 메소드를 활용해 정렬 가능하다. | ||
- ArrayList의 contains() 메소드를 활용하면 어떤 값이 존재하는지 유무를 판단할 수 있다. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package lotto; | ||
|
||
import lotto.domain.controller.LottoController; | ||
|
||
public class Application { | ||
public static void main(String[] args) { | ||
new LottoController().run(); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package lotto.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
|
||
import lotto.exception.InvalidLottoException; | ||
|
||
public class Lotto { | ||
public static final int COUNT_LOTTO_NUMBER = 6; | ||
private final List<Number> numbers; | ||
|
||
public Lotto(List<Number> numbers) { | ||
validate(numbers); | ||
Collections.sort(numbers); | ||
this.numbers = new ArrayList<>(numbers); | ||
} | ||
|
||
private void validate(List<Number> numbers) { | ||
checkSize(numbers); | ||
checkDuplication(numbers); | ||
} | ||
|
||
private void checkDuplication(List<Number> numbers) { | ||
if (new HashSet<>(numbers).size() != numbers.size()) { | ||
throw new InvalidLottoException("로또 번호는 중복 될 수 없습니다."); | ||
} | ||
} | ||
|
||
private void checkSize(List<Number> numbers) { | ||
if (numbers.size() != COUNT_LOTTO_NUMBER) { | ||
throw new InvalidLottoException("로또는 6개의 수를 가져야 합니다."); | ||
} | ||
} | ||
|
||
public int compare(Lotto winningNumbers) { | ||
return (int) numbers.stream() | ||
.filter(winningNumbers::contains) | ||
.count(); | ||
} | ||
|
||
public boolean contains(Number number) { | ||
return numbers.contains(number); | ||
} | ||
|
||
public List<Number> getNumbers() { | ||
return Collections.unmodifiableList(numbers); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package lotto.domain; | ||
|
||
import java.util.*; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
import java.util.stream.Collectors; | ||
|
||
import lotto.util.StringUtil; | ||
|
||
import static lotto.domain.Number.MAX_LOTTO_NUMBER; | ||
import static lotto.domain.Number.MIN_LOTTO_NUMBER; | ||
|
||
public class LottoFactory { | ||
public static final int LOWER_BOUND = 0; | ||
public static final int UPPER_BOUND = 6; | ||
|
||
private static final Map<Integer, Number> numberPool = new ConcurrentHashMap<>(); | ||
|
||
static { | ||
for (int i = MIN_LOTTO_NUMBER; i <= MAX_LOTTO_NUMBER; i++) { | ||
numberPool.put(i, new Number(Integer.toString(i))); | ||
} | ||
} | ||
|
||
public static List<Number> getNumberPool() { | ||
return new ArrayList<>(numberPool.values()); | ||
} | ||
|
||
public static Number of(String number) { | ||
Number.validate(number); | ||
return numberPool.get(Integer.parseInt(number)); | ||
} | ||
|
||
/** | ||
* 로또 한장을 만드는 메소드 | ||
* | ||
* @return Lotto | ||
*/ | ||
public static Lotto create() { | ||
List<Number> numbers = getNumberPool(); | ||
Collections.shuffle(numbers); | ||
return new Lotto(numbers.subList(LOWER_BOUND, UPPER_BOUND)); | ||
} | ||
|
||
/** | ||
* 당첨 로또를 생성하는 메소 | ||
* | ||
* @param winningNumbers | ||
* @return Lotto | ||
*/ | ||
public static Lotto create(String winningNumbers) { | ||
List<String> numbers | ||
= StringUtil.parseByComma(StringUtil.removeBlank(winningNumbers)); | ||
List<Number> lotto = numbers.stream() | ||
.map(LottoFactory::of) | ||
.collect(Collectors.toList()); | ||
Collections.shuffle(lotto); | ||
return new Lotto(lotto); | ||
} | ||
|
||
/** | ||
* 구매한 금액만큼 자동으로 로또 여러장을 생성하는 메소드 | ||
* | ||
* @param count | ||
* @return Lottos | ||
*/ | ||
public static Lottos create(int count) { | ||
List<Lotto> lottos = new ArrayList<>(); | ||
for (int i = 0; i < count; i++) { | ||
lottos.add(create()); | ||
} | ||
return new Lottos(lottos); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package lotto.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
|
||
public class Lottos implements Iterable<Lotto> { | ||
private final List<Lotto> lottos; | ||
|
||
public Lottos(List<Lotto> lottos) { | ||
this.lottos = new ArrayList<>(lottos); | ||
} | ||
|
||
public int getSize() { | ||
return lottos.size(); | ||
} | ||
|
||
@Override | ||
public Iterator<Lotto> iterator() { | ||
return lottos.iterator(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package lotto.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
import lotto.exception.InvalidNumberException; | ||
|
||
import static javax.management.Query.value; | ||
|
||
public class Number implements Comparable<Number> { | ||
public static final int MIN_LOTTO_NUMBER = 1; | ||
public static final int MAX_LOTTO_NUMBER = 45; | ||
|
||
private final int number; | ||
|
||
public Number(String number) { | ||
validate(number); | ||
this.number = Integer.parseInt(number); | ||
} | ||
|
||
public Number(int number) { | ||
this.number = number; | ||
} | ||
|
||
public static void validate(String value) { | ||
checkNull(value); | ||
checkBlank(value); | ||
checkNumberFormat(value); | ||
checkRange(value); | ||
} | ||
|
||
private static void checkNumberFormat(String value) { | ||
try { | ||
Integer.parseInt(value); | ||
} catch (NumberFormatException e) { | ||
throw new InvalidNumberException("문자는 사용이 불가능합니다."); | ||
} | ||
} | ||
|
||
private static void checkRange(String value) { | ||
int number = Integer.parseInt(value); | ||
if (number > MAX_LOTTO_NUMBER || number < MIN_LOTTO_NUMBER) { | ||
throw new InvalidNumberException("로또 번호는 1에서 45까지만 가능합니다"); | ||
} | ||
} | ||
|
||
private static void checkBlank(String value) { | ||
if (value.trim().isEmpty()) { | ||
throw new InvalidNumberException("공백은 사용이 불가능합니다."); | ||
} | ||
} | ||
|
||
private static void checkNull(String value) { | ||
if (Objects.isNull(value)) { | ||
throw new InvalidNumberException("Null문자열은 사용이 불가능합니다."); | ||
} | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return Integer.toString(number); | ||
} | ||
|
||
@Override | ||
public int compareTo(Number o) { | ||
return Integer.compare(this.number, o.number); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Integer.hashCode(number); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (obj instanceof Number) { | ||
return this.number == ((Number) obj).number; | ||
} | ||
return false; | ||
} | ||
} |
Oops, something went wrong.