Skip to content
Open
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
47 changes: 47 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## 설계 고민
- 객체간의 종속성을 줄이는 방향
- 객체의 기능과 책임을 어떻게 나눌 것인가..
- 되도록이면 하나의 객체는 하나의 책임을!
- 정보를 많이 알고 있는 객체가 행위를!
- 직접 가져와서 쓰지 말고 요청을!

validator를 따로 빼서 클래스로 갖고 있어야하나..
그런데 그럼 검증은 정보를 가지고 있는 객체가 하기로 한 원칙을 위배해야 하는데..

* 참고 코드 = mjucraft -> recruit / 김영한 app config

## 흐름 정리
1. [Input]: 구입 금액 입력 -> [User] 전달
2. [User]: 로또 개수 확정,
3. 각 로또의 번호 확정
4. 당첨 번호 입력
5. 보너스 번호 입력
6. 당첨 여부 확정
7. 수익률 계산

## 기능 정리
1. 금액 -> 개수
2. 랜덤 넘버 생성: random number creator
3. 당첨 넘버 생성
4. [ 로또 넘버 <-> 당첨 넘버 체크 ] -> 각 당첨 등수별 개수
5. 각 당첨 등수 개수 -> 금액
6. 수익률 계산
7. Error 발생

## 객체 정리
### 1. Lotto
- 번호 6개
- 번호 검증 함수(개수, 중복)
- 번호 일치 함수(순서 무관)


### 2. WinningLotto
- 번호 6개 + 보너스 1개
- 번호 검증 함수(중복)



### 5. Input / Output
- 입력과 출력만 담당
- 그 이상의 책임을 가지지 않는다.

4 changes: 3 additions & 1 deletion src/main/java/lotto/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
Controller controller = new Controller();

controller.run();
}
}
24 changes: 24 additions & 0 deletions src/main/java/lotto/Calculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package lotto;

import java.util.Map;

public class Calculator {

public int calculateAmountOfLotteriesWithMoney(int money) {
return money / Receipt.LOTTO_PRICE;
}

public Long calculatePrize(Map<Rank, Integer> rankCount) {
Long prize = 0L;

for (Rank rank : Rank.values()) {
prize += rankCount.get(rank).intValue() * rank.getPrize();
}

return prize;
}

public double calculateProfitRate(int amountOfMoney, Long prize) {
return (double) amountOfMoney / prize;
}
}
72 changes: 72 additions & 0 deletions src/main/java/lotto/Controller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package lotto;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Controller {
private Input input = new Input();
private Output output = new Output();
private Service service = new Service();

public void run() {
Receipt receipt = createReceipt();
int amountOfLotteries = receipt.getAmountOfLotteries();
List<Lotto> lotteries = createLotteries(amountOfLotteries);

WinningLotto winningLotto = createWinningLotto();

Map<Rank, Integer> rankCounts = createRankCount(winningLotto, lotteries);
Result result = createResult(rankCounts, receipt);

showProfitRate(result);
}

private Receipt createReceipt() {
int purchaseAmount = input.readPurchaseAmount();
Receipt receipt = service.createReceipt(purchaseAmount);

int amountOfLotteries = receipt.getAmountOfLotteries();
output.printPurchasedCount(amountOfLotteries);

return receipt;
}

private List<Lotto> createLotteries(int amountOfLotteries) {
List<Lotto> lotteries = service.createLotteries(amountOfLotteries);
List<List<Integer>> lotteryNumbers = new ArrayList<>();

for (Lotto lotto : lotteries) {
lotteryNumbers.add(lotto.getNumbers());
}

output.printLotteries(lotteryNumbers);

return lotteries;
}

private WinningLotto createWinningLotto() {
List<Integer> winningNumbers = input.readWinningNumbers();
int bonusNumber = input.readBonusNumber();

return service.createWinningLotto(winningNumbers, bonusNumber);
}

private Map<Rank, Integer> createRankCount(WinningLotto winningLotto, List<Lotto> lotteries) {
Map<Rank, Integer> rankCounts = service.createRankCounts(winningLotto, lotteries);
output.printWinningStatistics(rankCounts);

return rankCounts;
}

private Result createResult(Map<Rank, Integer> rankCount,Receipt receipt) {
int amountOfMoney = receipt.getAmountOfMoney();
return service.createResult(rankCount, amountOfMoney);
}

private void showProfitRate(Result result) {
output.printProfitRate(result.profitRate);
}


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

public enum ErrorType {

// TODO: Error Type 설정 및 Handler 구현

DUPLICATED_NUMBERS("[ERROR] 중복된 숫자는 허용되지 않습니다"),
LOTTO_COUNTS("[ERROR] 로또 번호는 6개여야 합니다."),
WRONG_AMOUNT_OF_MONEY("[ERROR] 금액은 1000원 단위여야 합니다.");

private final String message;

ErrorType(String message) {
this.message = message;
}
}
78 changes: 78 additions & 0 deletions src/main/java/lotto/Input.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package lotto;

import camp.nextstep.edu.missionutils.Console;

import java.util.ArrayList;
import java.util.List;

public class Input {

public int readPurchaseAmount() {
System.out.println("구입금액을 입력해 주세요.");
String input = Console.readLine();

if (input == null || input.isBlank()) {
throw new IllegalArgumentException("[ERROR] 구입 금액은 숫자여야 합니다.");
}

if (!input.matches("\\d+")) {
throw new IllegalArgumentException("[ERROR] 구입 금액은 숫자여야 합니다.");
}

int amountOfMoney = Integer.parseInt(input);

if (amountOfMoney % Receipt.LOTTO_PRICE !=0) {
throw new IllegalArgumentException("[ERROR] 구입 금액은 1000원 단위여야 합니다.");
}
return amountOfMoney;
}

public List<Integer> readWinningNumbers() {
System.out.println("당첨 번호를 입력해 주세요.");
String input = Console.readLine();

if (input == null || input.isBlank()) {
throw new IllegalArgumentException("[ERROR] 당첨 번호 입력이 올바르지 않습니다.");
}

String[] tokens = input.split(",");
if (tokens.length != Lotto.NUMBERS_COUNT) {
throw new IllegalArgumentException("[ERROR] 당첨 번호는 6개여야 합니다.");
}

List<Integer> numbers = new ArrayList<>();
for (String token : tokens) {
String value = token.trim();
if (!value.matches("\\d+")) {
throw new IllegalArgumentException("[ERROR] 당첨 번호는 숫자여야 합니다.");
}
numbers.add(Integer.parseInt(value));
}

for (int i = 0; i < numbers.size() - 1; i++) {
List<Integer> restNumbers = numbers.subList(i + 1, numbers.size() - 1);

if (restNumbers.contains(numbers.get(i))) {
throw new IllegalArgumentException("[ERROR] 당첨 번호들은 중복되면 안됩니다.");
}
}

return numbers;
}

public int readBonusNumber() {
System.out.println("보너스 번호를 입력해 주세요.");
String input = Console.readLine();

if (input == null || input.isBlank()) {
throw new IllegalArgumentException("[ERROR] 보너스 번호는 숫자여야 합니다.");
}

if (!input.matches("\\d+")) {
throw new IllegalArgumentException("[ERROR] 보너스 번호는 숫자여야 합니다.");
}

return Integer.parseInt(input);
}

}
49 changes: 45 additions & 4 deletions src/main/java/lotto/Lotto.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,57 @@
public class Lotto {
private final List<Integer> numbers;

public static final int MINIMUM_NUMBER = 1;
public static final int MAXIMUM_NUMBER = 45;
public static final int NUMBERS_COUNT = 6;

// TODO: Lotto랑 WinningLotto가 유사한 면이 있음. abstract class나 interface를 사용하는 것을 고민해봐야 함.

public Lotto(List<Integer> numbers) {
validate(numbers);
validateCount(numbers);
validateDuplication();
this.numbers = numbers;
}

private void validate(List<Integer> numbers) {
if (numbers.size() != 6) {
public List<Integer> getNumbers() {
return numbers;
}

public int matchWinningNumbers(List<Integer> winningNumbers) {
int count = 0;

for (int number : numbers) {
if (winningNumbers.contains(number)) {
count++;
}
}

return count;
}

public boolean matchBonusNumber(int bonusNumber) {
for(int number : numbers){
if(number == bonusNumber){
return true;
}
}

return false;
}

private void validateCount(List<Integer> numbers) {
if (numbers.size() != NUMBERS_COUNT) {
throw new IllegalArgumentException("[ERROR] 로또 번호는 6개여야 합니다.");
}
}

// TODO: 추가 기능 구현
private void validateDuplication() {
for (int i = 0; i < numbers.size() -1 ; i++) {
List<Integer> restNumbers = numbers.subList(i + 1, numbers.size() -1);
if (restNumbers.contains(numbers.get(i))) {
throw new IllegalArgumentException("[ERROR] 겹치는 로또 번호가 있습니다.");
}
}
}

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

import java.util.List;
import java.util.Map;

public class Output {

public void printPurchasedCount(int count) {
System.out.println(count + "개를 구매했습니다.");
}

public void printLotteries(List<List<Integer>> lotteries) {
for (List<Integer> numbers : lotteries) {
System.out.println(numbers);
}
}

public void printWinningStatistics(Map<Rank, Integer> rankCounts) {

System.out.println();
System.out.println("당첨 통계");
System.out.println("---");

System.out.println("3개 일치 (5,000원) - " + rankCounts.getOrDefault(Rank.Fifth, 0) + "개");
System.out.println("4개 일치 (50,000원) - " + rankCounts.getOrDefault(Rank.Fourth, 0) + "개");
System.out.println("5개 일치 (1,500,000원) - " + rankCounts.getOrDefault(Rank.Third, 0) + "개");
System.out.println("5개 일치, 보너스 볼 일치 (30,000,000원) - " + rankCounts.getOrDefault(Rank.Second, 0) + "개");
System.out.println("6개 일치 (2,000,000,000원) - " + rankCounts.getOrDefault(Rank.First, 0) + "개");
}

public void printProfitRate(double profitRatePercent) {
System.out.printf("총 수익률은 %.1f%%입니다.%n", profitRatePercent);
}
}
11 changes: 11 additions & 0 deletions src/main/java/lotto/RandomNumberCreator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package lotto;

import java.util.List;

public class RandomNumberCreator {
public List<Integer> createRandomLottoNumbers() {
List<Integer> numbers = camp.nextstep.edu.missionutils.Randoms.pickUniqueNumbersInRange(Lotto.MINIMUM_NUMBER,Lotto.MAXIMUM_NUMBER,Lotto.NUMBERS_COUNT);

return numbers;
}
}
31 changes: 31 additions & 0 deletions src/main/java/lotto/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package lotto;

public enum Rank {
First(6, false, 2000000000,"6개 일치 - 1등"),
Second(5, true, 30000000, "5개 일치 + 보너스 일치 - 2등"),
Third(5, false, 1500000, "5개 일치 + 보너스 불일치 - 3등"),
Fourth(4, false, 50000, "4개 일치 - 4등"),
Fifth(3,false, 5000, "3개 일치 - 5등"),
MISS(0, false, 0,""); // 굳이?


private final int matchCount;
private final boolean requiresBonus;
private final long prize;
private final String message;

Rank(int matchCount, boolean requiresBonus, long prize, String message) {
this.matchCount = matchCount;
this.requiresBonus = requiresBonus;
this.prize = prize;
this.message = message;
}

public long getPrize() {
return prize;
}

public int getMatchCount() {
return matchCount;
}
}
Loading