본문 바로가기

강의/TDD, Clean Code with Java 12기

[로또] step2 - 로또(자동) - 피드백 반영(20일차)

해당 객체가 가지고 있는 역할이 굉장히 많은 것 같아요 🤔
적절한 책임을 나누어 객체를 분리해보면 좋겠습니다!

 

로또 번호가 42까지 밖에 안보이네요 @_@
또한 값의 범위가 커질수록 하드코딩 하는 것이 힘들어질 수 있기 때문에 범위를 통해 번호를 생성해보면 좋을 것 같아요!

 

InputView의 경우 LottoApp에서 사용하고 ResultView의 경우 도메인 내부에 존재하도록 구현해주셨네요!
도메인 내부에 View의 로직이 존재한다면 어떠한 문제가 있을지 고민해보아요

 

String 타입으로 로또의 번호라는 사실을 검증할 수 있을까요?
규칙 3: 모든 원시값과 문자열을 포장한다.을 통해 값들을 포장하여 해당 문제를 해결해 볼 수 있을 것 같습니다 :)

 

이전에 멘토님께서 위와 같은 피드백을 주셨다.

피드백을 바탕으로 새롭게 코드를 구현해 보았다.

 

먼저 클래스를 좀 더 세분화 해 보았다.

이전에는 LottoMachine에서 모든 기능을 구현하였다면

이번에는 Lotto, LottoMachine, Caluculator, LastWinningLottoNumberChecker 등을 구현하였다.

 

Lotto

    -로또를 발행

 

Calculator

    - 발행된 로또와, 이전 당첨번호와 비교하는 로직

 

LastWinningLottoNumberChecker

    - 이전 당첨번호를 사용자가 잘 입력했는지 확인하는 부분

 

LottoMachine 

    - 전반적인 기능을 실행하는 부분이다.

 

package step2.domain;

import java.util.ArrayList;
import java.util.Collections;

public class Lotto {
    static final int MIN_OF_LOTTO_NUMBER = 1;
    static final int MAX_OF_LOTTO_NUMBER = 45;
    static final int NUM_OF_LOTTO_NUMBER = 6;
    static ArrayList<Integer> lottoNumberList = new ArrayList<>();


    public Lotto() {
        makeLottoNumberList();
    }

    public ArrayList<Integer> issueLotto() {
        ArrayList<Integer> lotto = new ArrayList<>();
        Collections.shuffle(lottoNumberList);
        for (int i = 0; i < NUM_OF_LOTTO_NUMBER; i++) {
            lotto.add(lottoNumberList.get(i));
        }
        printIssuedLottoNumber(lotto);
        return lotto;
    }

    private void printIssuedLottoNumber(ArrayList lotto) {
        System.out.println(lotto);
    }

    public ArrayList<Integer> makeLottoNumberList() {
        for (int i = MIN_OF_LOTTO_NUMBER; i < MAX_OF_LOTTO_NUMBER; i++) {
            lottoNumberList.add(i);
        }
        return lottoNumberList;
    }
}
package step2.domain;

import step2.util.LastWinningLottoNumberChecker;

import java.util.ArrayList;

public class LottoMachine {
    static int numOfLotto;
    static String lastWinningLottoNum;
    static LastWinningLottoNumberChecker lastWinningLottoNumberChecker;
    static Lotto lotto = new Lotto();
    static ArrayList<Integer> lastWinningLottoNumberArray;
    static ArrayList<ArrayList> issuedLottolist = new ArrayList<>();

    public LottoMachine(int numOfLotto, String lastWinningLottoNum) {
        this.numOfLotto = numOfLotto;
        this.lastWinningLottoNum = lastWinningLottoNum;

    }

    public ArrayList<ArrayList> run() {
        getLottoList();
        lastWinningLottoNumberChecker = new LastWinningLottoNumberChecker(lastWinningLottoNum);
        lastWinningLottoNumberArray = lastWinningLottoNumberChecker.getLottoWinningNumberArray();
        return issuedLottolist;
    }

    public ArrayList<ArrayList> getLottoList() {
        for (int i = 0; i < numOfLotto; i++) {
            issuedLottolist.add(lotto.issueLotto());
        }
        return issuedLottolist;
    }

    public ArrayList<Integer> getLastWinningLottoNumberArray() {
        return lastWinningLottoNumberArray;
    }

}
package step2.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Calculator {
    static ArrayList<ArrayList> issuedLottolist;
    static final int NUM_OF_LOTTO_NUMBERS = 6;
    static int[] lottoResultArray;
    static ArrayList<Integer> lastWinningLottoNumberArray;

    public Calculator(ArrayList<ArrayList> issuedLottolist, ArrayList<Integer> lastWinningLottoNumberArray) {
        this.issuedLottolist = issuedLottolist;
        this.lastWinningLottoNumberArray = lastWinningLottoNumberArray;
    }

    public void run() {
        lottoResultArray = new int[NUM_OF_LOTTO_NUMBERS+1];
        for (ArrayList<Integer> issuedLotto : issuedLottolist) {
            calcMatchedLottoNum(issuedLotto);
        }
    }

    public void calcMatchedLottoNum(ArrayList<Integer> issuedLotto) {


        List<Integer> matchedLottoList = issuedLotto.stream()
                .filter(num -> lastWinningLottoNumberArray.contains(num))
                .collect(Collectors.toList());
        lottoResultArray[matchedLottoList.size()]++;
    }

    public int[] getLottoResultArray() {
        return lottoResultArray;
    }


}
package step2.util;

import java.util.ArrayList;

public class LastWinningLottoNumberChecker {
    private static final String LOTTO_COUNT_ERROR_MESSAGE = "로또 당첨번호는 6개를 입력하세요. 당첨번호는 ', '로 구분을 하고 있습니다.";
    private static final String LOTTO_NUMBER_RANGE_ERROR_MESSAGE = "로또 당첨번호는 1과 45 사이의 정수이어야 합니다.";
    private static final String LOTTO_DELIMITER = ", ";
    private static final int MIN_OF_LOTTO_NUMBER = 1;
    private static final int MAX_OF_LOTTO_NUMBER = 45;
    private static final int COUNT_OF_LOTTO_WINNING_NUMBER = 6;
    private final ArrayList<Integer> lastWinningLottoNumberArray;

    public LastWinningLottoNumberChecker(String lastWinningLottoNum) {
        ArrayList<Integer> lottoNumberIntegerArray = makeIntegerArray(validateCountOfLotto(lastWinningLottoNum));
        lottoLoop(lottoNumberIntegerArray);
        this.lastWinningLottoNumberArray = lottoNumberIntegerArray;
    }

    private ArrayList<Integer> makeIntegerArray(String[] lottoNumberStringArray) {
        ArrayList<Integer> lottoNumberIntegerArray = new ArrayList<>();
        for (int i = 0; i < lottoNumberStringArray.length; i++) {
            lottoNumberIntegerArray.add(Integer.parseInt(lottoNumberStringArray[i]));
        }
        return lottoNumberIntegerArray;
    }

    public void lottoLoop(ArrayList<Integer> lottoNumberIntegerArray) {
        for (int lottoNumber : lottoNumberIntegerArray) {
            validatePositiveLottoNum(lottoNumber);
        }
    }

    private void validatePositiveLottoNum(int lottoNumber) {
        if (lottoNumber < MIN_OF_LOTTO_NUMBER || lottoNumber > MAX_OF_LOTTO_NUMBER) {
            throw new IllegalArgumentException(LOTTO_NUMBER_RANGE_ERROR_MESSAGE);
        }
    }

    public String[] validateCountOfLotto(String lastWinningLottoNum) {
        String[] lottoNumberStringArray = lastWinningLottoNum.split(LOTTO_DELIMITER);
        int numOfLotto = lottoNumberStringArray.length;
        if (numOfLotto != COUNT_OF_LOTTO_WINNING_NUMBER) {
            throw new IllegalArgumentException(LOTTO_COUNT_ERROR_MESSAGE);
        }
        return lottoNumberStringArray;
    }

    public ArrayList<Integer> getLottoWinningNumberArray() {
        return lastWinningLottoNumberArray;
    }
}
package step2;

import step2.domain.LottoMachine;
import step2.util.Calculator;
import step2.view.InputView;
import step2.view.ResultView;

import java.util.ArrayList;

public class LottoApp {
    public static void main(String[] args) {
        InputView inputView = new InputView();
        ResultView resultView = new ResultView();

        int numOfLotto = inputView.requestInput();
        String lastWinningLottoNum = inputView.requestWinningLottoNumber();

        LottoMachine lottoMachine = new LottoMachine(numOfLotto, lastWinningLottoNum);
        ArrayList<ArrayList> issuedLottolist = lottoMachine.run();
        ArrayList<Integer> lastWinningLottoNumberArray = lottoMachine.getLastWinningLottoNumberArray();

        Calculator calculator = new Calculator(issuedLottolist, lastWinningLottoNumberArray);
        calculator.run();
        int[] lottoResultArray = calculator.getLottoResultArray();
        resultView.printMatchedLottoRecord(lottoResultArray, numOfLotto);
    }
}
package step2.view;

import java.util.Scanner;

public class InputView {
    static final String INPUT_MESSAGE = "구입 금액을 입력해주세요.";
    static final String INPUT_INFO_MESSAGE = "개를 구매했습니다.";
    static final String INPUT_LAST_LOTTO_NUMBER = "지난 주 당첨 번호를 입력해 주세요.";
    private static final int chargeOfLotto = 1000;
    static Scanner sc = new Scanner(System.in);

    public int requestInput() {
        System.out.println(INPUT_MESSAGE);
        int charge = sc.nextInt();
        sc.nextLine();
        int numOfLotto = charge/chargeOfLotto;
        System.out.println(numOfLotto+INPUT_INFO_MESSAGE);
        return numOfLotto;
    }

    public String requestWinningLottoNumber() {
        System.out.println(INPUT_LAST_LOTTO_NUMBER);
        String lastWinningLottoNum = sc.nextLine();
        return lastWinningLottoNum;
    }
}
package step2.view;

import java.util.ArrayList;
import java.util.Arrays;

public class ResultView {
    static int[] charge = {0,0,0,5000,50000,1500000,2000000000};
    public void printIssuedLottoNumber(String[] lotto) {
        System.out.println(Arrays.toString(lotto));
    }

    public void printMatchedLottoRecord(int[] matchedLottoRecordArray, int numOfLotto) {
        int totalRevenue = 0;
        System.out.println("당첨 통계");
        System.out.println("-------");
        for (int i = 1; i <= 6; i++) {
            System.out.printf("%s 개 일치 (%s) %s개\n",i,charge[i],matchedLottoRecordArray[i]);
            totalRevenue += charge[i] * matchedLottoRecordArray[i];
        }

        double yield =  totalRevenue / (double)(numOfLotto * 1000);
        printResultMessage(yield);

    }

    private void printResultMessage(double yield) {
        if (yield < 1) {
            System.out.printf("총 수익률은 %s입니다.(기준이 1이기 때문에 결과적으로 손해라는 의미임)",yield);
            return;
        }
        if (yield >= 1) {
            System.out.printf("총 수익률은 %s입니다.(기준이 1이기 때문에 결과적으로 이익이라는 의미임)",yield);
            return;
        }

    }
}