이번 미션 진행하면서 dto, enum, interface 등 새로운 기술들을 많이 사용하였고 이에 따라 많은 피드백을 받을 수 있었다. 근데 정말 피드백이 너무 많아서 하나 하나 다 설명하기엔 양이 너어어어어~~~~무 많으므로 최종적인 코드를 첨부하고자 한다 !! start!
*LottoContorller
package controller;
import domain.*;
import view.InputView;
import view.LottoRankDto;
import view.OutputView;
import java.util.ArrayList;
import java.util.List;
public class LottoController {
private static final int RESET_NUMBER = 0;
private final InputView inputView;
private final OutputView outputView;
public LottoController(InputView inputView, OutputView outputView) {
this.inputView = inputView;
this.outputView = outputView;
}
public void startLotto() {
int lottoMoney = getLottoMoney();
Lottos lottos = buyLotto(lottoMoney);
List<Integer> lastWeekLottoNumber = getLastWeekLottoNumber();
rankLotto(lottos, lastWeekLottoNumber, lottoMoney);
}
private int getLottoMoney() {
outputView.printGetLottoMoney();
return inputView.getLottoMoney();
}
private Lottos buyLotto(int getLottoMoney) {
outputView.printPassiveLottoCount();
int passiveLottoNumberCount = inputView.getPassiveLottoCount();
outputView.printPassiveLottoNumber();
List<String> passiveLottoNumbers = new ArrayList<>();
for (int i = RESET_NUMBER; i < passiveLottoNumberCount; i++) {
String passiveLottoNumber = inputView.inputLottoNumber();
passiveLottoNumbers.add(passiveLottoNumber);
}
PassiveLottoNumber passiveLottoNumber = new PassiveLottoNumber(passiveLottoNumbers);
outputView.printLottoCount(getLottoMoney, passiveLottoNumberCount);
CreateLottoNumber createLottoNumber = new LottoNumberGenerator();
Lottos lottos = new Lottos(createLottoNumber, passiveLottoNumber.getPassiveLottoNumbers(), getLottoMoney);
for (Lotto lotto : lottos.getLottos()) {
List<Integer> lottoNumber = lotto.getLottoNumber().stream().map(LottoNumber::getLottoNumber).toList();
outputView.printLotto(lottoNumber);
}
return lottos;
}
private List<Integer> getLastWeekLottoNumber() {
outputView.LastWeekLottoNumber();
String inputLastWeekLottoNumber = inputView.inputLottoNumber();
LottoNumberParser lottoNumberParser = new LottoNumberParser(inputLastWeekLottoNumber);
int bonusBall = getBonusBall();
lottoNumberParser.addBonusBall(bonusBall);
return lottoNumberParser.getRealLottoNumber();
}
private int getBonusBall() {
outputView.inputBonusBall();
return inputView.inputBonusBall();
}
private void rankLotto(Lottos lottos, List<Integer> lastWeekLottoNumber, int getLottoMoney) {
LottoRankBundle lottoRankBundle = new LottoRankBundle(lottos, lastWeekLottoNumber);
LottoReturnRate lottoReturnRate = new LottoReturnRate(lottoRankBundle.getLottoRank(), getLottoMoney);
outputView.printLottoStatistics();
for(LottoRank lottoRank : lottoRankBundle.getLottoRank()){
LottoRankDto lottoRankDto = new LottoRankDto(lottoRank.getLottoRank(), lottoRank.getLottoRankNumber());
outputView.printLottoRank(lottoRankDto.toString());
}
outputView.printRateOfReturn(lottoReturnRate.getLottoReturnRate());
}
}
*CreateLottoNumber(interface)
package domain;
import java.util.List;
public interface CreateLottoNumber {
List<Integer> getRandomLottoNumber();
}
*Lotto
package domain;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
public class Lotto {
private final List<LottoNumber> lottoNumber;
public Lotto(CreateLottoNumber createLottoNumber) {
this.lottoNumber = makeAutoLotto(createLottoNumber);
}
public Lotto(List<Integer> inputPassiveLottoNumber) {
this.lottoNumber = makePassiveLotto(inputPassiveLottoNumber);
}
public List<LottoNumber> getLottoNumber() {
return lottoNumber;
}
private List<LottoNumber> makeAutoLotto(CreateLottoNumber createLottoNumber) {
List<Integer> singleLotto = new ArrayList<>(createLottoNumber.getRandomLottoNumber());
sortLottoNumber(singleLotto);
List<LottoNumber> lottoNumbers = new ArrayList<>();
for (int lottoNumberElement : singleLotto) {
LottoNumber lottoNumber = new LottoNumber(lottoNumberElement);
lottoNumbers.add(lottoNumber);
}
return lottoNumbers;
}
private List<LottoNumber> makePassiveLotto(List<Integer> inputPassiveLottoNumber) {
List<Integer> passiveLottoNumber = new ArrayList<>(inputPassiveLottoNumber);
List<LottoNumber> lottoNumbers = new ArrayList<>();
for (int lottoNumberElement : passiveLottoNumber) {
LottoNumber lottoNumber = new LottoNumber(lottoNumberElement);
lottoNumbers.add(lottoNumber);
}
return lottoNumbers;
}
private void sortLottoNumber(List<Integer> lottoNumber) {
Collections.sort(lottoNumber);
}
}
*Lottos
package domain;
import java.util.ArrayList;
import java.util.List;
public class Lottos {
private static final int INITIAL_NUMBER = 0;
private static final int LOTTO_COUNT_NUMBER = 1000;
private final List<Lotto> lottos;
public Lottos(CreateLottoNumber createLottoNumber, List<LottoNumberParser> inputPassiveLottoNumber, int lottoMoney) {
this.lottos = makeLottos(createLottoNumber, inputPassiveLottoNumber, lottoMoney);
}
public List<Lotto> getLottos() {
return lottos;
}
private List<Lotto> makeLottos(CreateLottoNumber createLottoNumber, List<LottoNumberParser> inputPassiveLottoNumbers, int lottoMoney) {
List<Lotto> lottosBundle = new ArrayList<>();
makePassiveLotto(inputPassiveLottoNumbers, lottosBundle);
makeAutoLotto(createLottoNumber, inputPassiveLottoNumbers, lottoMoney, lottosBundle);
return lottosBundle;
}
private void makeAutoLotto(CreateLottoNumber createLottoNumber, List<LottoNumberParser> inputPassiveLottoNumbers, int lottoMoney, List<Lotto> lottosBundle) {
for (int i = INITIAL_NUMBER; i < (lottoMoney / LOTTO_COUNT_NUMBER) - inputPassiveLottoNumbers.size(); i++) {
Lotto lotto = new Lotto(createLottoNumber);
lottosBundle.add(lotto);
}
}
private void makePassiveLotto(List<LottoNumberParser> inputPassiveLottoNumbers, List<Lotto> lottosBundle) {
for (LottoNumberParser passiveLottoNumber : inputPassiveLottoNumbers) {
Lotto lotto = new Lotto(passiveLottoNumber.getRealLottoNumber());
lottosBundle.add(lotto);
}
}
}
*LottoNumber
package domain;
public class LottoNumber {
private static final int FIRST_LOTTO_NUMBER = 1;
private static final int LAST_LOTTO_NUMBER = 45;
private static final String EXCEPTION_LOTTO_RANGE = "로또 범위 아님";
private final int lottoNumber;
public LottoNumber(int lottoNumber) {
validateLottoNumberRange(lottoNumber);
this.lottoNumber = lottoNumber;
}
public int getLottoNumber() {
return lottoNumber;
}
private void validateLottoNumberRange(int realLottoNumber) {
if (realLottoNumber < FIRST_LOTTO_NUMBER || realLottoNumber > LAST_LOTTO_NUMBER) {
throw new RuntimeException(EXCEPTION_LOTTO_RANGE);
}
}
}
로또 넘버 전체를 원시값 포장해줌!!
*PassiveLottoNumber(수동 로또 넘버)
package domain;
import java.util.ArrayList;
import java.util.List;
public class PassiveLottoNumber {
private final List<LottoNumberParser> passiveLottoNumbers;
public PassiveLottoNumber(List<String> passiveLottoNumber) {
this.passiveLottoNumbers = makePassiveLottoNumbers(passiveLottoNumber);
}
public List<LottoNumberParser> getPassiveLottoNumbers() {
return passiveLottoNumbers;
}
private List<LottoNumberParser> makePassiveLottoNumbers(List<String> passiveLottoNumbers) {
List<LottoNumberParser> lottoNumbers = new ArrayList<>();
for (String passiveLottoNumber : passiveLottoNumbers) {
LottoNumberParser lottoNumberParser = new LottoNumberParser(passiveLottoNumber);
lottoNumbers.add(lottoNumberParser);
}
return lottoNumbers;
}
}
*LottoNumberGenerator(인터페이스 상속받은 클래스)
package domain;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class LottoNumberGenerator implements CreateLottoNumber {
private static final int INITIAL_NUMBER = 0;
private static final int FIRST_LOTTO_NUMBER = 1;
private static final int LAST_LOTTO_NUMBER = 45;
private static final int LOTTO_NUMBER_LENGTH_BOUNDARY = 6;
private static final Random randomNumberGenerator = new Random();
@Override
public List<Integer> getRandomLottoNumber() {
List<Integer> getLotto = new ArrayList<>();
for (int i = INITIAL_NUMBER; i < LOTTO_NUMBER_LENGTH_BOUNDARY; i++) {
int randomLottoNumber = checkDuplicateNumber(getLotto, randomNumberGenerator.nextInt(FIRST_LOTTO_NUMBER, LAST_LOTTO_NUMBER));
getLotto.add(randomLottoNumber);
}
return getLotto;
}
private int generateRandomNumber() {
return randomNumberGenerator.nextInt(FIRST_LOTTO_NUMBER, LAST_LOTTO_NUMBER);
}
private int checkDuplicateNumber(List<Integer> getLotto, int randomLottoNumber) {
if (getLotto.contains(randomLottoNumber)) {
return checkDuplicateNumber(getLotto, generateRandomNumber());
}
return randomLottoNumber;
}
}
*LottoNumberParser
package domain;
import java.util.List;
import java.util.ArrayList;
public class LottoNumberParser {
private static final String SPLIT_STRING_DELIMITER = ",";
private static final String EXCEPTION_NUMBER = "올바른 숫자 입력하세요.";
private final List<Integer> realLottoNumber;
public LottoNumberParser(String lottoNumber) {
this.realLottoNumber = makeRealLottoNumber(lottoNumber);
}
public List<Integer> getRealLottoNumber() {
return realLottoNumber;
}
public void addBonusBall(int bonusBall) {
realLottoNumber.add(bonusBall);
}
private List<Integer> makeRealLottoNumber(String lottoNumber) {
List<String> inputLottoNumber = parseLottoNumber(lottoNumber);
List<Integer> realLottoNumber = new ArrayList<>();
for (String lottoNumberElement : inputLottoNumber) {
validateLottoNumber(lottoNumberElement);
int realLottoNumberElement = Integer.parseInt(lottoNumberElement);
realLottoNumber.add(realLottoNumberElement);
}
return realLottoNumber;
}
private List<String> parseLottoNumber(String lottoNumber) {
String[] parseLottoNumber = lottoNumber.split(SPLIT_STRING_DELIMITER);
return List.of(parseLottoNumber);
}
private void validateLottoNumber(String lottoNumber) {
try {
Integer.parseInt(lottoNumber);
} catch (NumberFormatException exception) {
throw new RuntimeException(EXCEPTION_NUMBER);
}
}
}
*LottoPrice(enum)
package domain;
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;
public enum LottoPrice {
THREE("3", 5000),
FOUR("4", 50000),
FIVE("5", 1500000),
BONUS("5BONUS", 30000000),
SIX("6", 2000000000);
private static final int MAKE_FIRST_INDEX = 3;
private static final String LAST_INDEX_NUMBER = "6";
private final String sameLottoNumber;
private final int lottoPrice;
LottoPrice(String sameLottoNumber, int lottoPrice) {
this.sameLottoNumber = sameLottoNumber;
this.lottoPrice = lottoPrice;
}
public static List<Integer> getLottoPriceBundle() {
List<Integer> lottoPrices = new ArrayList<>();
for (LottoPrice lottoPrice : LottoPrice.values()) {
lottoPrices.add(lottoPrice.getLottoPrice());
}
return lottoPrices;
}
public static int getLottoPrice(String sameLottoNumber) {
if (Objects.equals(sameLottoNumber, BONUS.getSameLottoNumber())) {
return BONUS.getLottoPrice();
}
if (Objects.equals(sameLottoNumber, LAST_INDEX_NUMBER)) {
return SIX.getLottoPrice();
}
LottoPrice[] lottoPrices = LottoPrice.values();
return lottoPrices[Integer.parseInt(sameLottoNumber) - MAKE_FIRST_INDEX].getLottoPrice();
}
public static List<String> getSameLottoNumberBundle() {
List<String> sameLottoNumbers = new ArrayList<>();
for (LottoPrice lottoPrice : LottoPrice.values()) {
sameLottoNumbers.add(lottoPrice.getSameLottoNumber());
}
return sameLottoNumbers;
}
public static String getBonusSameLottoNumber() {
return BONUS.getSameLottoNumber();
}
private String getSameLottoNumber() {
return sameLottoNumber;
}
private int getLottoPrice() {
return lottoPrice;
}
}
*LottoRank
package domain;
public class LottoRank {
private final String lottoRank;
private final int lottoRankNumber;
public LottoRank(String lottoRank, int lottoRankNumber) {
this.lottoRank = lottoRank;
this.lottoRankNumber = lottoRankNumber;
}
public String getLottoRank() {
return lottoRank;
}
public int getLottoRankNumber() {
return lottoRankNumber;
}
}
*LottoRankBundle
package domain;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import java.util.HashMap;
public class LottoRankBundle {
private static final int RESET_NUMBER = 0;
private static final int INITIAL_NUMBER = 1;
private static final int BONUS_COUNT = 5;
private final List<LottoRank> lottoRank;
public LottoRankBundle(Lottos lottos, List<Integer> lastWeekLottoNumber) {
this.lottoRank = makeLottoRankBundle(lottos, lastWeekLottoNumber);
}
public List<LottoRank> getLottoRank() {
return lottoRank;
}
private List<LottoRank> makeLottoRankBundle(Lottos lottos, List<Integer> lastWeekLottoNumber) {
List<LottoRank> lottoRanks = new ArrayList<>();
for (Map.Entry<String, Integer> entry : makeLottoRank(lottos, lastWeekLottoNumber).entrySet()) {
lottoRanks.add(new LottoRank(entry.getKey(), entry.getValue()));
}
return lottoRanks;
}
private Map<String, Integer> makeLottoRank(Lottos lottos, List<Integer> lastWeekLottoNumber) {
Map<String, Integer> rankLotto = checkCorrespondingLottosNumber(lottos, lastWeekLottoNumber);
List<String> sameLottoNumbers = LottoPrice.getSameLottoNumberBundle();
Map<String, Integer> sortedRankLotto = new HashMap<>();
for (String sameLottoNumber : sameLottoNumbers) {
rankLotto.put(sameLottoNumber, rankLotto.getOrDefault(sameLottoNumber, RESET_NUMBER) + RESET_NUMBER);
sortedRankLotto.put(sameLottoNumber, rankLotto.getOrDefault(sameLottoNumber, rankLotto.get(sameLottoNumber)));
}
return new TreeMap<>(sortedRankLotto);
}
private Map<String, Integer> checkCorrespondingLottosNumber(Lottos lottos, List<Integer> lastWeekLottoNumber) {
Map<String, Integer> rankLotto = new HashMap<>();
for (Lotto lotto : lottos.getLottos()) {
List<Integer> lottoNumber = lotto.getLottoNumber().stream().map(LottoNumber::getLottoNumber).toList();
String sameLottoNumber = checkCorrespondingLottoNumber(lottoNumber, lastWeekLottoNumber);
rankLotto.put(sameLottoNumber, rankLotto.getOrDefault(sameLottoNumber, RESET_NUMBER) + INITIAL_NUMBER);
}
return rankLotto;
}
private String checkCorrespondingLottoNumber(List<Integer> lottoNumber, List<Integer> lastWeekLottoNumber) {
int sameLottoNumber = (int) lastWeekLottoNumber.stream().filter(lottoNumber::contains).count();
if (isBonusNumber(lottoNumber, lastWeekLottoNumber, sameLottoNumber)) {
return LottoPrice.getBonusSameLottoNumber();
}
return Integer.toString(sameLottoNumber);
}
private boolean isBonusNumber(List<Integer> lottoNumber, List<Integer> lastWeekLottoNumber, int sameLottoNumber) {
return lottoNumber.contains(lastWeekLottoNumber.get(lastWeekLottoNumber.size() - INITIAL_NUMBER)) && sameLottoNumber == BONUS_COUNT;
}
}
*LottoReturnRate
package domain;
import java.util.List;
public class LottoReturnRate {
private static final int RESET_NUMBER = 0;
private static final double MAKE_RETURN_RATE_DEVIDE_NUMBER = 100.0;
private static final int MAKE_RETURN_RATE_MULTIPLE_NUMBER = 100;
private final double lottoReturnRate;
public LottoReturnRate(List<LottoRank> lottoRanks, int getLottoMoney) {
this.lottoReturnRate = calculateLottoReturnRate(lottoRanks, getLottoMoney);
}
public double getLottoReturnRate() {
return lottoReturnRate;
}
private double calculateLottoReturnRate(List<LottoRank> lottoRanks, int getLottoMoney) {
List<Integer> lottoRankPrice = LottoPrice.getLottoPriceBundle();
int sumOfLottoMoney = RESET_NUMBER;
int count = RESET_NUMBER;
for (LottoRank lottoRank : lottoRanks) {
sumOfLottoMoney += lottoRank.getLottoRankNumber() * lottoRankPrice.get(count);
count++;
}
double lottoReturnRate = (double) sumOfLottoMoney / getLottoMoney;
return Math.floor(lottoReturnRate * MAKE_RETURN_RATE_MULTIPLE_NUMBER) / MAKE_RETURN_RATE_DEVIDE_NUMBER;
}
}
*InputView
package view;
import java.util.Scanner;
public class InputView {
private final Scanner input = new Scanner(System.in);
public int getLottoMoney() {
return input.nextInt();
}
public int getPassiveLottoCount() {
return input.nextInt();
}
public String inputLottoNumber() {
return input.next();
}
public int inputBonusBall() {
return input.nextInt();
}
}
*LottoRankDto
package view;
import domain.LottoPrice;
public class LottoRankDto {
private final String lottoRank;
private final int lottoRankerNumber;
public LottoRankDto(String lottoRank, int lottoRankerNumber) {
this.lottoRank = lottoRank;
this.lottoRankerNumber = lottoRankerNumber;
}
@Override
public String toString() {
if (lottoRank.equals("5BONUS")) {
return "5개 일치, 보너스 볼 일치(" + LottoPrice.getLottoPrice(lottoRank) + ")- " + lottoRankerNumber + "개";
}
return lottoRank + "개 일치 (" + LottoPrice.getLottoPrice(lottoRank) + ")- " + lottoRankerNumber + "개";
}
}
*OutputView
package view;
import java.util.List;
public class OutputView {
private static final int DEVIDE_LOTTO_COUNT_NUMBER = 1000;
public void printGetLottoMoney() {
System.out.println("구입금액을 입력해 주세요.");
}
public void printPassiveLottoCount() {
System.out.println("\n수동으로 구매할 로또 수를 입력해 주세요.");
}
public void printPassiveLottoNumber() {
System.out.println("\n수동으로 구매할 번호를 입력해 주세요.");
}
public void printLottoCount(int lottoCount, int passiveLottoNumberCount) {
System.out.println("\n수동으로 " + passiveLottoNumberCount + "장, 자동으로 " + ((lottoCount / DEVIDE_LOTTO_COUNT_NUMBER) - passiveLottoNumberCount) + "개를 구매했습니다.");
}
public void printLotto(List<Integer> lottoNumber) {
System.out.println(lottoNumber);
}
public void LastWeekLottoNumber() {
System.out.println("\n" + "지난 주 당첨 번호를 입력해 주세요.");
}
public void inputBonusBall() {
System.out.println("\n보너스 볼을 입력해주세요.");
}
public void printLottoStatistics() {
System.out.println("\n당첨 통계");
System.out.println("---------");
}
public void printLottoRank(String lottoRank) {
System.out.println(lottoRank);
}
public void printRateOfReturn(double rateOfReturn) {
System.out.println("총 수익률은 " + rateOfReturn + "입니다.");
}
}
정리.
이번 로또는 정말 아쉬움이 많이 남았다..
원시값 포장과 일급컬렉션을 최대한 지키려고 많이 노력하였고, 새로운 기술들을 많이 써봐서 좋기도 했지만 아직도 enum과 dto 를 어떤 식으로 효율적으로 써야 할 지 감이 잡히지 않았다.. 특히 dto의 경우 dto를 쓰는 목적이 정확하게 어떤 객체를 전달하는지 나타내기 위해 쓰는 것이라고 생각하는데, 나는 이 목적을 잘 지키지 못한 것 같아 많은 아쉬움이 들었다.
또한, LottoRank 클래스가 너무 난잡하게 작성되어 있다는 사실을 깨달았다. 객체를 더 나누거나 stream 메서드를 공부해 사용하거나, 아니면 다른 방식으로 간결하고 효율적인 메서드를 작성해야 했다는 생각이 들었다. 하지만 이번 로또 미션을 통해 일급컬렉션, 원시값 포장, 테스트 코드 작성 등 정말 기본적이고 개념적인 부분에 있어서는 얻은 것이 많다고 생각들고, 앞으로 코드 작성 할 때 객체를 어떤식으로 나누어야 할 지에 대한 감각이 생긴 것 같아서 너무 좋다. 더 열심히 해야징.
'자바 > 초록스터디' 카테고리의 다른 글
초록 스터디에 참여하게 된 계기와 초록 스터디를 하며 느낀점 (2) | 2024.09.25 |
---|---|
(8)초록스터디 로또 3,4 단계 구현 (0) | 2024.07.15 |
(7)초록스터디 로또 1,2 단계 테스트 코드 구현 (0) | 2024.05.23 |
(6)초록스터디 로또 1,2 단계 구현 (0) | 2024.05.23 |
(5)초록스터디 : 계산기 구현 PR 후기 (0) | 2024.05.22 |