Skip to content
18 changes: 11 additions & 7 deletions src/main/java/lotto/Main.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
package lotto;

import lotto.domain.LottoGame;
import lotto.domain.LottoResult;
import lotto.domain.Money;
import lotto.domain.WinningLotto;
import lotto.domain.*;
import lotto.view.InputView;
import lotto.view.ResultView;

import java.util.List;

public class Main {
public static void main(String[] args) {
long price = InputView.initLottoPrice();
LottoGame lottoGame = new LottoGame(price);
Money money = new Money(InputView.initLottoPrice());
int manualCount = InputView.initManualCount();
List<String> manualList = InputView.initManualList(manualCount);

LottoPurchase lottoPurchase = new LottoPurchase(money, manualList);

LottoGame lottoGame = new LottoGame(lottoPurchase);
ResultView.printLottos(lottoGame);

WinningLotto winningLotto = new WinningLotto(InputView.initWinningLotto(), InputView.initBonusNumber());
LottoResult result = lottoGame.findWinner(winningLotto);
ResultView.printResult(result, new Money(price));
ResultView.printResult(result, money);
}
}
15 changes: 15 additions & 0 deletions src/main/java/lotto/domain/AutoLottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package lotto.domain;

public class AutoLottoGenerator implements LottoGenerator {

private final LottoCount lottoCount;

public AutoLottoGenerator(LottoCount lottoCount) {
this.lottoCount = lottoCount;
}

@Override
public Lottos generate() {
return new Lottos(lottoCount.value());
}
}
20 changes: 20 additions & 0 deletions src/main/java/lotto/domain/CompositeLottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package lotto.domain;

import java.util.List;

public class CompositeLottoGenerator implements LottoGenerator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

두 개의 Lotto를 합치는 객체까지 추가 👍
LottoPurchase의 purchse 메서드 내부를 CompositeLottoGenerator 에서 아래와 같이 구현해도 되지 않을까?

이와 같이 인터페이스를 구현하고, 구현체가 서로 연결되어 있는 경우 아래와 같은 구현체를 통해 구현체를 통합할 수 있음.
보통 디자인 패턴에서 컴포지트 패턴으로 알려져 있음.
아래와 같은 객체 추가에 따른 효과를 느껴 봤으면 하는 바람으로 피드백 남겨봄.

public class LottosBundleGenerator implements LottosGenerator {
    private final List<LottosGenerator> lottosGenerators;

    public LottosBundleGenerator(Money money, List<String> manualLottoText) {
        this(toLottosGenerators(money, manualLottoText));
    }

    private static List<LottosGenerator> toLottosGenerators(Money money, List<String> manualLottoText) {
        // manualLottoText 활용해 ManualLottosGenerator 생성
        // money에서 수동으로 구매한 로또 수 만큼 차감한 후 AutoLottosGenerator 생성
    }

    public LottosBundleGenerator(List<LottosGenerator> lottosGenerators) {
        this.lottosGenerators = lottosGenerators;
    }

    @Override
    public Lottos generate() {
        // List<LottosGenerator> 반복문 돌며 로또 생성
        return  로또를 합쳐서 반환;
    }
}


private final List<LottoGenerator> generators;

public CompositeLottoGenerator(List<LottoGenerator> generators) {
this.generators = generators;
}

@Override
public Lottos generate() {
return generators.stream()
.map(LottoGenerator::generate)
.reduce(Lottos::merge)
.orElseGet(Lottos::empty);
}
}
20 changes: 20 additions & 0 deletions src/main/java/lotto/domain/LottoCount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package lotto.domain;

public class LottoCount {
private final int value;

public LottoCount(int value) {
validate(value);
this.value = value;
}

private static void validate(int value) {
if (value < 0) {
throw new IllegalArgumentException();
}
}

public int value() {
return value;
}
}
12 changes: 3 additions & 9 deletions src/main/java/lotto/domain/LottoGame.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,13 @@

public class LottoGame {
private final Lottos lottos;
private final Money money;

public LottoGame(long amount) {
this(new Money(amount));
public LottoGame(LottoPurchase purchase) {
this(purchase.purchase());
}

public LottoGame(Money money) {
this(new Lottos(money.buyCount()), money);
}

public LottoGame(Lottos lottos, Money money) {
public LottoGame(Lottos lottos) {
this.lottos = lottos;
this.money = money;
}

public LottoResult findWinner(WinningLotto winningLotto) {
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/lotto/domain/LottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package lotto.domain;

public interface LottoGenerator {
Lottos generate();
}
53 changes: 53 additions & 0 deletions src/main/java/lotto/domain/LottoPurchase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package lotto.domain;

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

public class LottoPurchase {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 객체가 수동/자동 로또 생성을 담당하고 있다.
이 부분은 인터페이스 기반으로 변경해 보는 리팩터링 도전해 보면 어떨까?

3단계에서 4단계로 요구사항이 변경될 때 로또를 생성하는 부분의 요구사항만 변경됐다.
로또를 생성하는 부분을 다음과 같은 구조의 인터페이스로 분리해 보는 연습을 해보면 어떨까?
이와 같이 인터페이스로 구현했을 때의 잇점에 대해 고민해 보는 시간을 가져본다.

public interface LottosGenerator {
    Lottos generate();
}

private static final long LOTTO_PRICE = 1_000;

private final LottoCount count;
private final List<Lotto> manualLottos;

public LottoPurchase(Money money) {
this(new LottoCount(calculateCount(money)));
}

public LottoPurchase(LottoCount count) {
this(count, List.of());
}

public LottoPurchase(Money money, List<String> manualList) {
this(new LottoCount(calculateCount(money)), convert(manualList));
}

public LottoPurchase(LottoCount count, List<Lotto> manualLottos) {
this.count = count;
this.manualLottos = manualLottos;
}

public Lottos purchase() {
LottoGenerator compositeGenerator = new CompositeLottoGenerator(
List.of(new ManualLottoGenerator(manualLottos), new AutoLottoGenerator(new LottoCount(autoCount()))));

return compositeGenerator.generate();
}

public static List<Lotto> convert(List<String> manualList) {
return manualList.stream()
.map(Lotto::new)
.collect(Collectors.toUnmodifiableList());
}

private static int calculateCount(Money money) {
return (int)(money.getMoney() / LOTTO_PRICE);
}

public int count() {
return count.value();
}

public int autoCount() {
return count.value() - manualLottos.size();
}
}
15 changes: 15 additions & 0 deletions src/main/java/lotto/domain/Lottos.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package lotto.domain;

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

public class Lottos {
Expand All @@ -17,6 +18,20 @@ public List<Lotto> values() {
return lottos;
}

public static Lottos empty() {
return new Lottos(List.of());
}

public Lottos merge(Lottos manualLottos) {
return merge(manualLottos.lottos);
}

public Lottos merge(List<Lotto> manualLottos) {
List<Lotto> newLottos = new ArrayList<>(this.lottos);
newLottos.addAll(manualLottos);
return new Lottos(newLottos);
}

public LottoResult findResult(WinningLotto winningLotto) {
LottoResult result = new LottoResult();
for (Lotto lotto : lottos) {
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/lotto/domain/ManualLottoGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package lotto.domain;

import java.util.List;

public class ManualLottoGenerator implements LottoGenerator {

private final List<Lotto> manualList;

public ManualLottoGenerator(List<Lotto> manualList) {
this.manualList = manualList;
}

@Override
public Lottos generate() {
return new Lottos(manualList);
}
}
4 changes: 0 additions & 4 deletions src/main/java/lotto/domain/Money.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ private void validate(long money) {
}
}

public int buyCount() {
return (int) (money / LOTTO_PRICE);
}

public double getMoney() {
return money;
}
Expand Down
22 changes: 11 additions & 11 deletions src/main/java/lotto/domain/Rank.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,22 @@ public int match() {
return match;
}

public boolean isMatch(int match) {
return this.match == match;
private boolean isMatch(int matchCount, boolean matchBonus) {
if (this == SECOND) {
return matchCount == 5 && matchBonus;
}

if (this == THIRD) {
return matchCount == 5 && !matchBonus;
}

return this.match == matchCount;
}

public static Rank from(int matchCount, boolean matchBonus) {
return Arrays.stream(values())
.filter(rank -> rank.isMatch(matchCount))
.filter(rank -> rank.isMatch(matchCount, matchBonus))
.findFirst()
.map(rank -> bonusCheck(rank, matchBonus))
.orElse(NONE);
}

private static Rank bonusCheck(Rank rank, boolean matchBonus) {
if (rank == Rank.THIRD && matchBonus) {
return Rank.SECOND;
}
return rank;
}
}
19 changes: 19 additions & 0 deletions src/main/java/lotto/view/InputView.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package lotto.view;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class InputView {
Expand All @@ -19,4 +22,20 @@ public static int initBonusNumber() {
System.out.println("보너스 볼을 입력해 주세요.");
return SCANNER.nextInt();
}

public static int initManualCount() {
System.out.println("수동으로 구매할 로또 수를 입력해 주세요.");
int count = SCANNER.nextInt();
SCANNER.nextLine();
return count;
}

public static List<String> initManualList(int manualCount) {
System.out.println("수동으로 구매할 번호를 입력해 주세요.");
List<String> result = new ArrayList<>();
for (int i = 0; i < manualCount; i++) {
result.add(SCANNER.nextLine());
}
return result;
}
}
16 changes: 16 additions & 0 deletions src/test/java/lotto/domain/AutoLottoGeneratorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package lotto.domain;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class AutoLottoGeneratorTest {

@Test
void auto_generate_size() {
AutoLottoGenerator auto = new AutoLottoGenerator(new LottoCount(3));
Lottos generate = auto.generate();
Assertions.assertThat(generate.size()).isEqualTo(3);
}
}
27 changes: 27 additions & 0 deletions src/test/java/lotto/domain/CompositeLottoGeneratorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package lotto.domain;

import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class CompositeLottoGeneratorTest {

@Test
void merge() {
List<Lotto> manualList = List.of(
new Lotto(1, 2, 3, 4, 5, 6)
, new Lotto(2, 3, 4, 5, 6, 7)
);
LottoGenerator manual = new ManualLottoGenerator(manualList);
LottoGenerator auto = new AutoLottoGenerator(new LottoCount(2));

LottoGenerator composite = new CompositeLottoGenerator(
List.of(manual, auto)
);

Lottos merge = composite.generate();
assertThat(merge.size()).isEqualTo(4);
}
}
3 changes: 2 additions & 1 deletion src/test/java/lotto/domain/LottoGameTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class LottoGameTest {
@Test
@DisplayName("입력된 금액만큼의 로또가 생성되어야 한다")
void generate_lotto() {
assertThat(new LottoGame(14000).lottoCount()).isEqualTo(14);
LottoPurchase lottoPurchase = new LottoPurchase(new LottoCount(14));
assertThat(new LottoGame(lottoPurchase).lottoCount()).isEqualTo(14);
}
}
43 changes: 43 additions & 0 deletions src/test/java/lotto/domain/LottoPurchaseTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package lotto.domain;


import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

public class LottoPurchaseTest {

@Test
@DisplayName("정해진 개수로 구매할 수 있다")
void count() {
LottoPurchase purchase = new LottoPurchase(new LottoCount(3));

assertThat(purchase.count()).isEqualTo(3);
}

@Test
@DisplayName("Money로부터 구매 가능한 로또 개수를 계산한다")
void calculate() {
Money money = new Money(5000);

LottoPurchase purchase = new LottoPurchase(money);

assertThat(purchase.count()).isEqualTo(5);
}

@Test
@DisplayName("수동 생성한 리스트의 사이즈를 확인할 수 있다.")
void manualList_size() {
Money money = new Money(5000);
List<String> list = List.of("1,2,3,4,5,6", "2,3,4,5,6,7", "3,4,5,6,7,8");

LottoPurchase lottoPurchase = new LottoPurchase(money, list);
Lottos lottos = lottoPurchase.purchase();

assertThat(lottos.size()).isEqualTo(5);
assertThat(lottoPurchase.autoCount()).isEqualTo(2);
}
}
Loading