Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[디디] 로또 미션 제출합니다. #129

Merged
merged 18 commits into from
Feb 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 109 additions & 2 deletions README.md
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() 메소드를 활용하면 어떤 값이 존재하는지 유무를 판단할 수 있다.
9 changes: 9 additions & 0 deletions src/main/java/lotto/Application.java
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();
}
}
22 changes: 0 additions & 22 deletions src/main/java/lotto/WebUILottoApplication.java

This file was deleted.

50 changes: 50 additions & 0 deletions src/main/java/lotto/domain/Lotto.java
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);
}
}
73 changes: 73 additions & 0 deletions src/main/java/lotto/domain/LottoFactory.java
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);
}
}
22 changes: 22 additions & 0 deletions src/main/java/lotto/domain/Lottos.java
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();
}
}
84 changes: 84 additions & 0 deletions src/main/java/lotto/domain/Number.java
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;
}
}
Loading