Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1단계 - 블랙잭 게임 실행] 재즈(함석명) 미션 제출합니다. #4

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cc6c638
docs(README): 기능 요구 사항 작성
pricelees Mar 5, 2024
9c89c6f
feat: 카드 문양과 숫자에 대한 Enum 클래스 생성
pricelees Mar 5, 2024
b7011cb
feat(Deck): 모든 카드를 가지는 Deck 클래스 및 테스트 구현
pricelees Mar 5, 2024
1ab946f
style(DeckTest): 중복 코드 제거
pricelees Mar 6, 2024
54db712
feat(BlackJackGamer): 딜러와 플레이어의 공통 추상 클래스 생성
pricelees Mar 6, 2024
1432f2d
feat(Dealer): BlackJackGamer를 상속받는 딜러 클래스 생성과 메서드 재정의
pricelees Mar 6, 2024
56af966
feat(Player): BlackJackGamer를 상속받는 플레이어 클래스 생성과 메서드 재정의
pricelees Mar 6, 2024
af51dfa
feat(Name): 문자열 이름을 포장하는 클래스 생성
pricelees Mar 6, 2024
59f51bc
feat(Players): Player의 일급 컬렉션 생성
pricelees Mar 6, 2024
e75ea3b
refactor: 예외 메시지 추가 및 테스트 수정
pricelees Mar 6, 2024
939882c
test(NameTest): 정상 입력에 대한 테스트 추가
pricelees Mar 6, 2024
f050926
test(PlayersTest): 정상 입력에 대한 테스트 추가
pricelees Mar 6, 2024
9b0e50d
feat(Player): 딜러의 점수를 입력받아 플레이어의 승패 여부를 결정하는 기능 추가
pricelees Mar 7, 2024
ae70681
feat(Hand): 참여자의 카드 리스트에 대한 일급 컬렉션 생성
pricelees Mar 7, 2024
f6afbdc
refactor(BlackjackGamer): Hand를 사용하도록 수정
pricelees Mar 7, 2024
8d1b095
refactor(Dealer, Player): 생성자 및 메서드 수정
pricelees Mar 7, 2024
69e7124
feat(GameResult): 승,패를 표현하는 Enum 클래스 생성
pricelees Mar 7, 2024
1a9df2a
feat: DTO 생성 및 각 도메인에 DTO 생성 로직 추가
pricelees Mar 7, 2024
d74858c
refactor(Hand): 카드 숫자의 합계를 구하는 메서드 세분화 및 상수 추가
pricelees Mar 7, 2024
9fd5c3d
style(Dealer): 상수 추가 및 dto 생성 메서드명 수정
pricelees Mar 7, 2024
e0351cf
style(Player): 매직 넘버 상수화
pricelees Mar 7, 2024
da6b980
feat(Players): 전체 플레이어의 패를 초기화 하는 기능 및 dto 생성 기능 추가
pricelees Mar 7, 2024
6f1ef7b
feat(GameResult): 패배인지 확인하는 기능 및 getter 추가
pricelees Mar 7, 2024
23a4321
feat(InputView): 입력을 받아들이는 InputView 클래스 생성
pricelees Mar 7, 2024
38f9367
feat(OutputView): 출력을 담당하는 OutputView 클래스 생성
pricelees Mar 7, 2024
c3443d3
feat(BlackjackController): 블랙잭 게임 흐름을 제어하는 컨트롤러 클래스 생성
pricelees Mar 7, 2024
74bbc4c
style: 출력 요구사항에 맞춰 빈 줄 출력 포맷 수정
pricelees Mar 7, 2024
8250c40
feat(Application): 컨트롤러를 생성하고 호출하여 게임을 시작하는 클래스 생성
pricelees Mar 7, 2024
1b7ead1
docs(README): 기능 요구 사항 정리
pricelees Mar 8, 2024
094a0bf
refactor(BlackjackController): 명령어 상수를 별도의 view Enum으로 분리 및 사용
seokmyungham Mar 9, 2024
9397927
refactor(Card): 출력에 의존적인 CardNumber, CardShape을 수정하고 view 패키지에 Enum 추가
seokmyungham Mar 10, 2024
12715f4
refactor(GameResult): 기존 출력에 의존적이던 필드 문자열을 제거 및 view enum으로 분리
seokmyungham Mar 11, 2024
1375923
refactor: 기존 도메인 내에 존재하던 Dto 변환 로직을 Dto 내부로 이동 및 리팩토링
seokmyungham Mar 11, 2024
16372e1
refactor(Deck): 테스트 목적의 List<Card>를 파라미터로 받는 생성자 개방
seokmyungham Mar 11, 2024
93c8c4b
test(CardTest): eqauls&hashCode 테스트 추가
seokmyungham Mar 11, 2024
1ff95cb
refactor(PlayersTest): 가독성 향상을 위해 테스트 코드 리팩토링
seokmyungham Mar 11, 2024
ec048b0
test(PlayersTest): 경계 값 테스트를 위해 테스트케이스 수정
seokmyungham Mar 11, 2024
6659db2
feat(Command): 사용자 입력 명령어를 별도의 Enum 클래스로 분리
seokmyungham Mar 11, 2024
8f146b6
style(Players): getter 메서드의 위치를 맨 밑으로 이동
seokmyungham Mar 11, 2024
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
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,41 @@

블랙잭 미션 저장소

## 우아한테크코스 코드리뷰
## 기능 요구 사항

- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)
### 게임

- [x] 딜러와 플레이어 중 카드의 합이 21 또는 21에 가장 가까운 쪽이 승리한다.
- [x] 게임을 시작하면 플레이어는 두 장의 카드를 지급 받는다.
- [x] 이후 플레이어와 딜러의 카드를 출력한다.
- [x] 단, 딜러의 카드는 하나만 출력한다.
- [x] 플레이어는 카드의 숫자 합이 21을 초과하지 않는다면 카드를 원하는 만큼 다시 뽑을 수 있다.
- [x] 새로 받을 때 마다 해당 플레이어의 카드를 출력한다.
- [x] 플레이어가 카드를 다 받으면 딜러의 카드를 확인한다.
- [x] 딜러의 카드 합이 17 이상이 될 때 까지 카드를 받는다.
- [x] 딜러와 플레이어의 카드, 결과와 최종 승패를 출력한다.

### 카드

- [x] 클로버, 스페이드, 하트, 다이아몬드 모양을 가진다.
- [x] 카드는 2부터 10까지의 숫자와 Ace, King, Queen, Jack으로 이루어져 있다.
- [x] King, Queen, Jack은 10으로 계산한다.
- [x] ACE는 1 또는 11로 계산할 수 있다.

### 딜러, 플레이어 공통

- [x] 최소 1글자, 최대 5글자의 이름을 가진다.
- [x] ACE 카드를 가지는 경우, 일단 11로 계산한 뒤, 합이 21을 초과하면 1로 계산한다.
- [x] 현재 가진 카드 숫자의 합을 기준으로 카드를 더 받을 수 있는지 결정한다.
- [x] 딜러는 숫자의 합이 16 이하이면 카드를 더 받을 수 있다.
- [x] 플레이어는 숫자의 합이 21 이하이면 카드를 더 받을 수 있다.

### 플레이어

- [x] 플레이어의 이름은 중복될 수 없다.
- [x] 플레이어는 최소 2명부터 최대 8명까지 가능하다.
- [x] 딜러의 점수를 입력받아 승,패를 결정한다.
- [x] 플레이어의 점수가 21을 초과하면 딜러의 점수와 무관하게 패배한다.
- [x] 플레이어의 점수가 21 이하이고, 딜러와 동점인 경우 패배한다.
- [x] 플레이어의 점수가 21 이하이고, 딜러의 점수가 21을 초과하면 승리한다.
- [x] 플레이어와 딜러의 점수가 모두 21 이하이고, 딜러의 점수보다 크면 승리한다.
Comment on lines +38 to +42
Copy link
Member

Choose a reason for hiding this comment

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

나도 무승부를 구현하지 않았는데, 따로 무승부를 구현하지 않은 이유가 있을까?

Copy link
Member Author

Choose a reason for hiding this comment

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

그냥 최대한 현재 요구사항에 충실하려고 노력했던 것 같아 😄
2단계 요구사항을 보지않고 진행했어서, 만약 2단계에 무승부가 없다면 굳이 에너지를 낭비하게 될 수도 있다는 생각이었어

11 changes: 11 additions & 0 deletions src/main/java/blackjack/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package blackjack;

import blackjack.controller.BlackjackController;

public class Application {

public static void main(String[] args) {
BlackjackController blackjackController = new BlackjackController();
blackjackController.run();
}
}
111 changes: 111 additions & 0 deletions src/main/java/blackjack/controller/BlackjackController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package blackjack.controller;

import blackjack.view.object.Command;
import java.util.ArrayList;
import java.util.List;

import blackjack.domain.card.Deck;
import blackjack.domain.gamer.Dealer;
import blackjack.domain.gamer.GameResult;
import blackjack.domain.gamer.Player;
import blackjack.domain.gamer.Players;
import blackjack.dto.DealerInitialHandDto;
import blackjack.dto.DealerResultDto;
import blackjack.dto.GamerHandDto;
import blackjack.dto.PlayerResultsDto;
import blackjack.view.InputView;
import blackjack.view.OutputView;

public class BlackjackController {

private static final String HIT_COMMAND = "y";
private static final String STAND_COMMAND = "n";
Copy link
Member

Choose a reason for hiding this comment

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

나는 해당 커멘드가 Controller보다 InputView에 있는게 더 좋을 것 같은데, 어떻게 생각해?

Copy link
Member Author

Choose a reason for hiding this comment

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

앗 별도의 명령어를 view 패키지의 Enum으로 사용하도록 수정했었는데
정작 컨트롤러는 수정하지 않았었네 😭
바로 수정!!


Copy link
Member

Choose a reason for hiding this comment

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

enum으로 묶는다면 커맨드 관련 책임과 로직을 응집할 수 있을 것 같습니다 💪🏻
컨트롤러가 게임 흐름의 자세한 로직을 아는 것도 완화할 수 있을 것 같고요 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

맞습니다! 저도 리비 의견에 전적으로 동의해요.
처음에는 컨트롤러에서 게임 흐름을 처리하니까, 저렇게 사용하고 인지하지 못했던 것 같아요
의사소통을 위한 별도의 Enum을 view패키지 안에 생성하고 view와 controller 사이에서 전달 받도록 수정해야할 것 같습니다 😄

private final InputView inputView;
private final OutputView outputView;

public BlackjackController() {
this.inputView = new InputView();
this.outputView = new OutputView();
}

Copy link
Member

Choose a reason for hiding this comment

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

생성자에서 어떤 객체를 주입받을지 fix하고 있네요
DI를 통해 유연성을 확보하는 것이 더 좋지 않을까요!

Copy link
Member Author

Choose a reason for hiding this comment

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

맞아요 프로젝트가 나중에 확장될 가능성을 생각해 본다면
지금 Application 클래스와 같은 외부에서 주입하도록 하는 것이 나을 수도 있을 것 같네요 😊

public void run() {
Players players = getPlayers();
Dealer dealer = new Dealer();
Deck deck = new Deck();
deck.shuffle();

setUpInitialHands(players, deck, dealer);
distributeCardToPlayers(players, deck);
distributeCardToDealer(dealer, deck);
printAllGamerScores(dealer, players);
printResult(dealer, players);
}

private Players getPlayers() {
List<String> playerNames = inputView.receivePlayerNames();

return new Players(playerNames);
}

private void setUpInitialHands(Players players, Deck deck, Dealer dealer) {
players.initAllPlayersCard(deck);
dealer.initCard(deck);
printInitialHands(players, dealer);
}

private void printInitialHands(Players players, Dealer dealer) {
DealerInitialHandDto dealerInitialHandDto = dealer.convertDealerToInitialHandDto();
List<GamerHandDto> playersInitialHandDto = players.convertPlayersToDto();

outputView.printInitialHands(dealerInitialHandDto, playersInitialHandDto);
}

private void distributeCardToPlayers(Players players, Deck deck) {
for (Player player : players.getPlayers()) {
distributeCardToPlayer(deck, player);
}
}

private void distributeCardToPlayer(Deck deck, Player player) {
while (canDistribute(player)) {
player.addCard(deck.draw());
outputView.printPlayerHand(player.convertGamerToDto());
}
}

private boolean canDistribute(Player player) {
return player.canReceiveCard() && Command.isHit(getCommand(player));
}

private Command getCommand(Player player) {
return inputView.receiveCommand(player.getName().value());
}

private void distributeCardToDealer(Dealer dealer, Deck deck) {
while (dealer.canReceiveCard()) {
dealer.addCard(deck.draw());
outputView.printDealerMessage(dealer.getName().value());
}
}

private void printAllGamerScores(Dealer dealer, Players players) {
outputView.printEmptyLine();
outputView.printScore(dealer.convertGamerToDto(), dealer.getScore());
printPlayersScores(players);
}

private void printPlayersScores(Players players) {
for (Player player : players.getPlayers()) {
outputView.printScore(player.convertGamerToDto(), player.getScore());
}
}

private void printResult(Dealer dealer, Players players) {
PlayerResultsDto playerResultsDto = players.convertPlayersToResultDto(dealer.getScore());
List<GameResult> playerResults = new ArrayList<>(playerResultsDto.resultMap().values());
DealerResultDto dealerResultDto = dealer.convertDealerToResultDto(playerResults);

outputView.printResult(dealerResultDto, playerResultsDto);
}
}
43 changes: 43 additions & 0 deletions src/main/java/blackjack/domain/card/Card.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package blackjack.domain.card;

import java.util.Objects;

import blackjack.dto.CardDto;

public class Card {

private final CardShape cardShape;
private final CardNumber cardNumber;
Copy link
Member

Choose a reason for hiding this comment

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

CardShape, CardNumber보다 Shape, Number가 더 간결하게 표현할 수 있지 않을까?
Card안에 쓰였다는 것만으로도 카드의 모양, 숫자를 나타낼 수 있다고 생각해.

Copy link
Member Author

Choose a reason for hiding this comment

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

나는 간결보다는 명확한 걸 좋아해서 이게 낫다고 생각했어
Enum이 쓰이는 상황에서도 Shape.Heart 보다는 CardShape.Heart 가 더 직관적이라고 생각해


public Card(CardShape cardShape, CardNumber cardNumber) {
this.cardShape = cardShape;
this.cardNumber = cardNumber;
}

public boolean isAce() {
return cardNumber == CardNumber.ACE;
}

public int getNumber() {
return cardNumber.getValue();
}

public CardDto convertCardToDto() {
return new CardDto(cardNumber.getName(), cardShape.getName());
}
Copy link
Member

Choose a reason for hiding this comment

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

DTO를 운용하기로 결정하셨군요
DTO의 생성 방법이 3가지 있는 것 같아요

  • 도메인에서 ToDto 구현하기
  • Dto에서 from 구현하기
  • Mapper 이용하기

더 자주 바뀌는 객체가 무엇인지 생각해보고 의존방향 결정해봐도 좋을 것 같습니다 😀

Copy link
Member Author

Choose a reason for hiding this comment

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

지금 코드 구조에 조금 문제가 있다는 걸 다른 방법들과 함께 간접적으로 알려주셨군요 !!

저도 도메인에서 ToDto 구현하기Dto에서 from 구현하기 사이의 장점 단점들을 인지는 하고 있었는데
확신이 없었기에 이번 미션에서 실수를 저질렀던 것 같아요.

미션 리뷰어(현구막), 로키, 리비 다 같은 부분들을 지적해 주셨고
두 방법 사이에 트레이드 오프는 존재하지만, Dto가 변환로직을 스스로 책임을 지는게 맞다는 걸 크게 느끼게 되었어요.

Mapper 이용하는 방법은 들어만 보고 모르고 있었던 부분인데
이번 기회에 학습해봐야겠네요!! 리비 알려주셔서 감사해요~ 😊


@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Card card = (Card)o;
return cardShape == card.cardShape && cardNumber == card.cardNumber;
}

@Override
public int hashCode() {
return Objects.hash(cardShape, cardNumber);
}
}
34 changes: 34 additions & 0 deletions src/main/java/blackjack/domain/card/CardNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package blackjack.domain.card;

public enum CardNumber {

ACE("A", 11),
TWO("2", 2),
THREE("3", 3),
FOUR("4", 4),
FIVE("5", 5),
SIX("6", 6),
SEVEN("7", 7),
EIGHT("8", 8),
NINE("9", 9),
TEN("10", 10),
JACK("J", 10),
QUEEN("Q", 10),
KING("K", 10);

Copy link
Member

Choose a reason for hiding this comment

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

이 부분은 재즈의 의견을 물어보고 싶네요
CardNumber의 name은 뷰로직일까요? 🤔

먼저 저도 비슷한 방식으로 구현했습니다
CardNumber는 이름을 속성으로 가지고 이름을 가져다가 출력하는 것이 위화감 없어 보인다는 생각이에요 (자동차 경주에서 Car의 이름을 가져다가 출력하듯이)

다만 저는 리뷰어에게서 도메인 속 뷰로직이 존재한다 라는 코멘트를 받았습니다 😅

재즈는 어떻게 생각하시나요!

Copy link
Member Author

@seokmyungham seokmyungham Mar 10, 2024

Choose a reason for hiding this comment

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

먼저 저도 비슷한 방식으로 구현했습니다
CardNumber는 이름을 속성으로 가지고 이름을 가져다가 출력하는 것이 위화감 없어 보인다는 생각이에요 (자동차 경주에서 Car의 이름을 가져다가 출력하듯이)

앗 ㅋㅋㅋ 저도 속으로 "이정도는 괜찮나~?...." 생각했었는데 리뷰어분께 같은 코멘트를 받았어요 😭
현재 출력을 위한 이름이 도메인에 포함되어 있는지(재즈)

근데 리뷰를 받고 보니 제 페어 리뷰어분은 또 다른 의견이신 것 같아서 신기했습니다
현재 출력을 위한 이름이 도메인에 포함되어 있는지(상돌)

사실 미션 중간에 조금 꺼림칙하기도 해서,
제가 페어에게 view 패키지 안에 출력으로 변환해줄 수 있는 Enum을 만들어보는 방법도 제안해봤었는데, 제 페어는 이정도 까지는 괜찮을 것 같다라는 의견이었고 그냥 그대로 진행하게 되었습니다.

제 개인적인 생각은 여기까지는 허용할 수 있다, 이건 안된다는 너무 주관적인 영역인 것 같고 모호하다고 생각해요
그래서 저는 이번 미션도 그렇고 앞으로의 미션도 모두 별도의 변환을 하게끔 설계하기로 다짐하게 되었는데
현재 리비는 어떻게 생각하고 계신가요~??

Copy link
Member

Choose a reason for hiding this comment

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

저도 별도의 변환이 필요하다고 생각하게 되었네요 👍

숫자들을 TWO처럼 영어로 출력되도록 바꿔주세요라는 요청을 받으면 어느 패키지를 열어볼까요? 라는 질문을 받은 적 있는데 저라면 뷰를 열어볼 것 같더군요 😂

여기에 설득되어 뷰 레이어에서 따로 변환하도록 할 것 같습니다.

private final String name;
private final int value;

CardNumber(String name, int value) {
this.name = name;
this.value = value;
}

public String getName() {
return name;
}

public int getValue() {
return value;
}
}
19 changes: 19 additions & 0 deletions src/main/java/blackjack/domain/card/CardShape.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package blackjack.domain.card;

public enum CardShape {

HEART("하트"),
CLOVER("클로버"),
SPADE("스페이드"),
DIAMOND("다이아몬드");

private final String name;

CardShape(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
32 changes: 32 additions & 0 deletions src/main/java/blackjack/domain/card/Deck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package blackjack.domain.card;

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

public class Deck {

private final LinkedList<Card> cards;

Copy link
Member

Choose a reason for hiding this comment

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

Deck에서 LinkedList를 사용하신 이유가 궁금해요 💭

Copy link
Member

Choose a reason for hiding this comment

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

저두 궁금해요! QueueList를 사용하는 것이 내부 구현을 바꾸는데 좀 더 용이하지 않을까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

맨 앞쪽(위쪽)의 카드를 가져온다라는 의미와 잘 매칭되는 메서드를 먼저 생각해봤는데
Queue 자료구조의 poll() 메서드가 가장 먼저 떠올랐던 것 같아요.
큐 자료구조 특성상 데이터 변경이 일어날 때 리스트보다 성능 상 유리한 점이 많이 와닿았던 것 같습니다.

그리고 Queue 자료구조가 특정 상황과 연관되는 구현체들이 많다고 개인적으로 생각해서
다형성을 포기하고 LinkedList만 사용해! 라고 뭔가 강제하게 된 느낌인데, 이게 좋은지는 아직 잘 모르겠네요.. ㅎㅎ

public Deck() {
this.cards = Arrays.stream(CardShape.values())
.flatMap(cardShape -> Arrays.stream(CardNumber.values())
.map(number -> new Card(cardShape, number)))
.collect(Collectors.toCollection(LinkedList::new));
}

public void shuffle() {
Collections.shuffle(cards);
}

public Card draw() {
return cards.poll();
}

public List<Card> getCards() {
return new ArrayList<>(cards);
}
}
50 changes: 50 additions & 0 deletions src/main/java/blackjack/domain/gamer/BlackjackGamer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package blackjack.domain.gamer;

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

import blackjack.domain.card.Card;
import blackjack.domain.card.Deck;
import blackjack.dto.CardDto;
import blackjack.dto.GamerHandDto;

public abstract class BlackjackGamer {

private final Name name;
private final Hand hand;

public BlackjackGamer(Name name) {
this.name = name;
this.hand = new Hand(new ArrayList<>());
}

public abstract boolean canReceiveCard();

public void initCard(Deck deck) {
addCard(deck.draw());
addCard(deck.draw());
}

Comment on lines +22 to +27
Copy link
Member

Choose a reason for hiding this comment

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

게이머는 시작 카드가 두장이다라는 규칙 자체를 상수로써 표현할 수 있을 것 같아요

initCard를 실행할 때 해당 상수를 이용하도록 하면 규칙의 변경에 유연하게 대처할 수 있을 것 같습니다 😀

Copy link
Member Author

Choose a reason for hiding this comment

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

오!! 미처 생각지 못했는데 괜찮은 방법인 것 같습니다 😄
바로 반영해보겠습니다!

public void addCard(Card card) {
hand.add(card);
}

public Card getFirstCard() {
return hand.getFirstCard();
}

public int getScore() {
return hand.calculateScore();
}

public Name getName() {
return name;
}
Comment on lines +28 to +42
Copy link
Member

Choose a reason for hiding this comment

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

하위 클래스에서 재정의해서 사용하지 않을 메서드는 final 키워드를 붙여서 관리해보는 건 어떨끼?
하위 클래스에서 실수로 재정의하는 것을 방지해줄 수 있을 것 같아.


public GamerHandDto convertGamerToDto() {
String playerName = name.value();
List<CardDto> gamerHand = hand.convertHandToDto();

return new GamerHandDto(playerName, gamerHand);
}
}
39 changes: 39 additions & 0 deletions src/main/java/blackjack/domain/gamer/Dealer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package blackjack.domain.gamer;

import java.util.List;

import blackjack.domain.card.Card;
import blackjack.dto.DealerInitialHandDto;
import blackjack.dto.DealerResultDto;

public class Dealer extends BlackjackGamer {

private static final String DEFAULT_DEALER_NAME = "딜러";
private static final int DEALER_DRAW_THRESHOLD = 16;

public Dealer() {
super(new Name(DEFAULT_DEALER_NAME));
}

@Override
public boolean canReceiveCard() {
return getScore() <= DEALER_DRAW_THRESHOLD;
}

public DealerResultDto convertDealerToResultDto(List<GameResult> playerResults) {
Name name = getName();
int winCount = (int)playerResults.stream()
.filter(GameResult::isLose)
.count();
int loseCount = playerResults.size() - winCount;

return new DealerResultDto(name.value(), winCount, loseCount);
}

public DealerInitialHandDto convertDealerToInitialHandDto() {
String dealerName = getName().value();
Card first = getFirstCard();

return new DealerInitialHandDto(dealerName, first.convertCardToDto());
}
Copy link

Choose a reason for hiding this comment

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

Entity를 DTO로 변환하는 로직이 Entity에 있으면 View의 출력 요구조건에 따라 Domain 코드가 바뀌게 된다고 생각합니다.

Copy link
Member Author

Choose a reason for hiding this comment

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

저도 기존에 동일한 생각을 가지고 있었는데, 확신이 없었던 것 같습니다.
처음에는 dto 변환 로직을 dto가 책임지도록 했다가, 컨트롤러 코드가 너무 길어져서 중간에 수정하게 되었어요.

그런데 이번 리뷰어분도 같은 부분을 지적해주셨고
계속 고민해본 결과, dto 변환 로직을 스스로 책임질 수 있도록 해서
dto가 변경되거나 삭제되어도 도메인은 영향을 받지 않도록 하는 게 맞는 것 같아요
수정해보겠습니다.

}
Loading