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
57 changes: 57 additions & 0 deletions src/main/java/Lotto/Lotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Lotto {
private final static int LOTTO_NUM_SIZE = 6;
private final List<LottoNo> lottoNums;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

final 로 선언하신 이유가 궁금합니다~

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Set 로 선언하는 것은 어떻게 생각하시나요~


public Lotto(List<LottoNo> lottoNums) {
checkSizeValid(lottoNums);
checkNumbersValid(lottoNums);
checkDuplicated(lottoNums);

this.lottoNums = lottoNums;
}

public List<Integer> getNums() {
List<Integer> lottoNumbers = new ArrayList<>();

for (LottoNo lottoNo : lottoNums) {
lottoNumbers.add(lottoNo.getLottoNumber());
}

return lottoNumbers;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

java 8 의 stream map 을 써보면 어떨까요?

}

public List<LottoNo> getLottoNums() {
return lottoNums;
}

public void checkSizeValid(List<LottoNo> lotto) {
if (!isValidLottoSize(lotto)) {
throw new IllegalArgumentException("6개의 로또 번호를 입력해 주세요.");
}
}

public void checkNumbersValid(List<LottoNo> lotto) {
if (lotto.contains(LottoNo.INVALID_LOTTO_NO)) {
throw new IllegalArgumentException("1 ~ 45 안의 정수를 입력하세요.");
}
}

public void checkDuplicated(List<LottoNo> lotto) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

check 메서드들이 public 인 이유가 있나요~?

if (!isValidLottoSize(new HashSet<>(lotto))) {
throw new IllegalArgumentException("로또 번호는 중복될 수 없습니다.");
}
}

boolean isValidLottoSize(List<LottoNo> lotto) {
return lotto.size() == LOTTO_NUM_SIZE;
}

boolean isValidLottoSize(Set<LottoNo> lotto) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

접근제어자를 package-private 으로 하신 이유가 있을까요?

return lotto.size() == LOTTO_NUM_SIZE;
}
}
46 changes: 46 additions & 0 deletions src/main/java/Lotto/LottoNo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import java.util.Objects;

public class LottoNo implements Comparable<LottoNo> {
private final static int INVALID_NUM = 0;
public final static LottoNo INVALID_LOTTO_NO = new LottoNo(INVALID_NUM);

private int lottoNumber;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LottoNo 는 변경되지 않는 lottoNumber 하나를 가지고 있어야하므로
final 키워드를 넣어도 될 것 같네요 ㅎㅎ


public LottoNo(int lottoNumber) {
try {
this.lottoNumber = validateLottoNo(lottoNumber);
} catch (IllegalArgumentException e) {
this.lottoNumber = INVALID_NUM;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

음.. RuntimeException 을 발생시키고 catch 를 굳이 하는 이유가 있을까요?
checkedException 과 uncheckedException 에 대해서 공부해보시면 좋을 것 같습니다~

}

public int getLottoNumber() {
return lottoNumber;
}

private int validateLottoNo(int lottoNumber) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

굳이 메서드로 빼지 않아도 될 것 같아요

if (lottoNumber < 1 || lottoNumber > 45) {
throw new IllegalArgumentException();
}

return lottoNumber;
}

@Override
public int hashCode() {
return Objects.hashCode(lottoNumber);
}

@Override
public boolean equals(Object obj) {
if (lottoNumber == ((LottoNo)obj).lottoNumber)
return true;

return false;
}

@Override
public int compareTo(LottoNo o) {
return lottoNumber - o.lottoNumber;
}
}
40 changes: 40 additions & 0 deletions src/main/java/Lotto/LottoRankResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import java.util.ArrayList;
import java.util.List;

public class LottoRankResult {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

뭔가 이름이 결과를 담는 데이터 그릇 같은 느낌이라
LottoCalculator
LottoResultCalculator
LottoRankCalculator
같은 네이밍으로 변경해보면 어떨까요?

그에 맞춰서 메서드 네이밍도 변경하면 단순히 set 된 데이터를 get 하는 것보다
상태와 행위를 갖는 객체지향적인 네이밍이 될 것 같다는 생각이 듭니다

private List<Rank> ranks;

public LottoRankResult(WinningLotto winningLotto, LottoTicket lottoTicket) {
this.ranks = new ArrayList<>();

for (Lotto lotto : lottoTicket.getAllLottoGames()) {
ranks.add(
Rank.valueOf(
winningLotto.getCountOfSameNumber(lotto),
winningLotto.isWinningBonus(lotto)
)
);
}
}

public int getCount(Rank rank) {
return (int) ranks.stream().filter(t -> t.equals(rank)).count();
}

public Money getTotalWinningMoney() {
Money earnings = Money.ZERO;

for (Rank rank : ranks) {
earnings = earnings.add(rank.getWinningMoney());
}

return earnings;
}

public double getEarningsRate(Money invest) {
Money earnings = getTotalWinningMoney();

return (double)(earnings.intValue()) / invest.intValue() * 100.0;
}

}
22 changes: 22 additions & 0 deletions src/main/java/Lotto/Lottos.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import java.util.ArrayList;
import java.util.List;

public class Lottos {
private List<Lotto> lottos;

public Lottos() {
this.lottos = new ArrayList<>();
}

public List<Lotto> getLottos() {
return lottos;
}

public void addLotto(Lotto lotto) {
lottos.add(lotto);
}

public int getSize() {
return lottos.size();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Lottos 가 가지는 행위가 하나도 없는데요,
다른 객체에서 위임할만한게 없을까요?
get이 사용되고 있다는 것은 Lottos 의 tell dont ask 원칙이 안지켜지고 있다는 뜻이고,
여기로 위임할만한 책임이 산재해 있다는 뜻이기도 합니다.

}
29 changes: 29 additions & 0 deletions src/main/java/Lotto/WinningLotto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import java.util.List;

public class WinningLotto {
private Lotto winningLotto;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Lotto를 상속 받을 수도 있었는데 이렇게 합성을 사용하셨네요. 👍
혹시라도 우연히 이렇게 구현하신거라면,
상속과 합성을 구글링 해보시면 관련 자료를 찾으실 수 있을겁니다 ~

private LottoNo bonusNo;

public WinningLotto(List<LottoNo> winningLottoNumbers, LottoNo lottoNo) {
if (winningLottoNumbers == null) {
throw new IllegalArgumentException("'lotto' must not be null");
}
if (lottoNo == null) {
throw new IllegalArgumentException("'lottoNo' must not be null");
}

this.winningLotto = new Lotto(winningLottoNumbers);
this.bonusNo = lottoNo;
}

public int getCountOfSameNumber(Lotto purchasedLotto) {
return (int) winningLotto.getLottoNums()
.stream()
.filter(purchasedLotto.getLottoNums()::contains)
.count();
}

public boolean isWinningBonus(Lotto purchasedLotto) {
return purchasedLotto.getLottoNums().contains(bonusNo);
}
}
43 changes: 43 additions & 0 deletions src/main/java/Main/LottoApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import java.util.Scanner;

public class LottoApplication {
private static boolean APP_SUCCESS = false;

public static void main(String[] args) {
runUntilAppSuccess();
}

public static void runUntilAppSuccess() {
while (!APP_SUCCESS) {
run();
}
}

public static void run() {
final Scanner scanner = new Scanner(System.in);
int countOfManualLotto;

try {
LottoService lottoService = new LottoService(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LottoGame 이라는 네이밍은 어떨까요

InputView.scanMoney(scanner),
countOfManualLotto = InputView.scanCountOfManualLotto(scanner),
InputView.scanNumbersOfManualLotto(scanner, countOfManualLotto),
new LottoSeller()
);

lottoService.purchaseLottoTicket();
lottoService.printPurchaseResult();

lottoService.setWinningLotto(
InputView.scanWinningLotto(scanner),
InputView.scanBonusNo(scanner)
);

lottoService.printWinningResult();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

lottoService 에 set 하고 get 하고 절차지향적인 방식으로 코드가 짜여져 있습니다.
모든 로직이 lottoService 를 통하면서 결국 이 클래스는 점점 비대해질텐데요
좋은 개선 방법이 없을까요~?


APP_SUCCESS = true;
} catch (OutOfConditionException | IllegalArgumentException e) {
e.printStackTrace();
}
}
}
48 changes: 48 additions & 0 deletions src/main/java/Rank/Rank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import java.util.Arrays;

public enum Rank {
FIRST(6, 2000000000),
SECOND(5, 30000000),
THIRD(5, 1500000),
FOURTH(4, 50000),
FIFTH(3, 5000),
MISS(0, 0);

private int countOfMatch;
private Money winningMoney;

Rank(int countOfMatch, int winningMoney) {
this.countOfMatch = countOfMatch;
this.winningMoney = Money.valueOf(winningMoney);
}

public static Rank valueOf(int countOfGame, boolean matchBonus) {
if (countOfGame == SECOND.getCountOfMatch()) {
return getSecondOrThird(matchBonus);
}

return Arrays.stream(values())
.filter(r -> countOfGame == r.countOfMatch)
.findFirst()
.orElse(MISS);
}

public static Rank[] valuesNotMiss() {
return new Rank[]{FIRST, SECOND, THIRD, FOURTH, FIFTH};
}

private static Rank getSecondOrThird(boolean matchBonus) {
if (matchBonus)
return SECOND;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

중괄호가 빠졌습니다

return THIRD;
}

public int getCountOfMatch() {
return countOfMatch;
}

public Money getWinningMoney() {
return winningMoney;
}

}
21 changes: 21 additions & 0 deletions src/main/java/Rank/RankResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
public class RankResult {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

데이터들을 클래스로 묶는 것이 객체지향은 아닙니다~
RankResult 도 결국 데이터와 get 만 가지고 있고,
유의미한 행위가 없습니다 ㅠㅠ
불필요한 객체가 아닌지, 유의미한 행위를 가진 객체로 만들려면 어떤 행위를 부여해야하는지
고민해보시면 좋을 것 같아요~

private Rank rank;
private int countOfRank;

RankResult(Rank rank) {
this.rank = rank;
this.countOfRank = 0;
}

public Rank getRank() {
return rank;
}

public int getCountOfRank() {
return countOfRank;
}

public void countUp(int count) {
countOfRank += count;
}
}
50 changes: 50 additions & 0 deletions src/main/java/Service/LottoSeller.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import java.util.List;

public class LottoSeller {
private LottoPurchaseService lottoPurchaseService;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Service 라는 네이밍을 쓰시는걸로 봐서
웹 쪽 자료를 보신 것 같은데,
controller, service, repository
이런 layered architecture 는 지금 저희가 하고 있는 객체지향과 거리가 좀 있습니다 ~

service 라는 네이밍을 사용하기보다는 좀 더 구체적이고 누구나 글 읽듯이 볼 수 있는 네이밍을 하시면
해당 객체에 부여하는 책임과 행위들도 달라지게 됩니다 ~
네이밍은 단순히 시각적인 효과 그 이상의 가치를 가지고 있습니다

private Money change;

public LottoSeller() {
change = Money.ZERO;
lottoPurchaseService = new LottoPurchaseService();
}

public LottoTicket sellTicketTo(LottoUser lottoUser) throws OutOfConditionException {
Money investMoney = LottoPurchaseService
.validatePurchase(
lottoUser.getInvestMoney(),
lottoUser.getCountOfManualLotto()
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

점 하나 찍을 때는 줄바꿈을 안하시는게 일반적입니다.
메소드 파라미터도 3개 이상부터 엔터를 치시는게 어떨까요?


this.change = LottoPurchaseService
.calculateChange(investMoney);

return lottoPurchaseService
.createLottoTicket(
investMoney,
getCountOfAutoGame(investMoney, lottoUser.getCountOfManualLotto()),
changeToLottos(lottoUser.getNumbersOfManualLottos())
);
}

public int getCountOfAutoGame(Money investMoney, int countOfManualLotto) {
return investMoney.divideBy(LottoPurchaseService.LOTTO_PRICE).intValue()
- countOfManualLotto;
}

private Lottos changeToLottos(List<List<LottoNo>> numbers0fManualLottos) {
Lottos manualLottos = new Lottos();

for (List<LottoNo> lottoNums : numbers0fManualLottos) {
manualLottos.addLotto(
lottoPurchaseService.createManualLotto(lottoNums)
);
}

return manualLottos;
}

public Money getChange() {
return change;
}
}
Loading