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

Dazzle 블랙잭 2단계 #14

Open
wants to merge 38 commits into
base: woo-chang
Choose a base branch
from

Conversation

woo-chang
Copy link

객체지향의 길은 멀고도 험한 것 같습니다 😂

부족한 코드지만 리뷰를 통해 많이 배워가도록 하겠습니다 .. !

woo-chang and others added 30 commits March 6, 2023 21:47
* docs: 요구사항 명세 작성

* feat: 이름의 길이 검증 기능 구현

* feat: 금지된 이름 검증 기능 구현

* docs: 기능 구현 목록 수정

Co-authored-by: woo-chang <[email protected]>

* feat: 이름 도메인 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 문양 도메인 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 숫자 도메인 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 문양 이름 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 숫자 이름 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 점수 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 점수 계산 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 에이스인지 확인하는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 점수 합계 계산 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 점수 최댓값 초과 여부 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 이름 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 블랙잭 여부 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* fix: 메서드명 수정 및 잘못된 로직 수정

Co-authored-by: woo-chang <[email protected]>

* feat: 카드 추가 여부 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 카드 추가 기능 구현

Co-authored-by: woo-chang <[email protected]>

* chore: 테스트 어노테이션 추가

Co-authored-by: woo-chang <[email protected]>

* feat: 카드를 받는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 점수 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 개수 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 카드 추가 여부 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 점수 확인 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 카드를 받는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 딜러 도메인 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 참가자 도메인 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 딜러와 플레이어가 참가자 상속

Co-authored-by: woo-chang <[email protected]>

* feat: 플레이어의 이름 중복 검증 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 참가자 인원 검증 기능 구현

Co-authored-by: woo-chang <[email protected]>

* refactor: 외부 참조 끊도록 수정

Co-authored-by: woo-chang <[email protected]>

* feat: 카드를 뽑는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 덱 상태 검증 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 덱 섞는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 덱 팩토리 도메인 생성

Co-authored-by: woo-chang <[email protected]>

* chore: 패키지 분리 및 import 최적화

Co-authored-by: woo-chang <[email protected]>

* feat: 문자열 파싱 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 문자열 앞뒤 공백 제거 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 플레이어 이름 목록 입력 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 카드 받을 여부 입력 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 참가자들의 카드 현황 출력 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 딜러 카드 추가 여부 출력 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 최종 결과 출력 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 최종 승패 출력 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 빈 생성자로 생성될 수 있는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: Cards 도메인에 대한 DTO 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 딜러 상태에 대한 DTO 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 참가자에 대한 DTO 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 플레이어 결과에 대한 DTO 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 결과에 대한 열거형 도메인 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 점수에 대한 도메인 생성

Co-authored-by: woo-chang <[email protected]>

* feat: 참가자들이 카드를 뽑는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 참가자들 중 딜러와 플레이어를 찾는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 이름으로만 생성될 수 있는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 덱에서 카드를 뽑아 참가자들에게 나눠주는 기능 구현

Co-authored-by: woo-chang <[email protected]>

* feat: 블랙잭 게임 실행 기능 구현

Co-authored-by: woo-chang <[email protected]>

* fix: 게임 결과 로직 수정

Co-authored-by: woo-chang <[email protected]>

* refactor: TRUMP는 덱이 알도록 수정

* refactor: 입력 기능 가독성 위해 메서드명 수정

* refactor: 축약하지 않은 변수명으로 수정

* refactor: 딜러가 카드를 추가로 뽑을 수 있는 점수는 딜러가 알도록 수정

* refactor: ACE -> Ace 일관성있는 표현으로 수정

* refactor: 테스트 목적을 명확히하도록 수정

* refactor: 계층 구조 테스트로 의미를 명확하게 전달하도록 수정

* refactor: 자바 컨벤션에 따라 메서드명 수정

* refactor: 카드 뽑을 때 검증하도록 수정

* refactor: NPE 방지 및 변수, 메서드명 수정

* refactor: 참가자에게 딜러 여부에 대한 메시지를 던지도록 수정

* refactor: 거짓 성공을 막기위해 검증부에는 하드코딩 하도록 수정

* refactor: TRUMP 생성 시 flatMap 사용 및 덱 생성 시 섞도록 수정

* refactor: 플레이어 이름을 명시하도록 Name -> PlayerName 수정

* refactor: 참여자 목록 생성 책임을 생성자로 수정

* refactor: Deck 생성 책임은 Deck이 가지도록 수정

* refactor: 블랙잭 게임 컨트롤러 수정

* refactor: 딜러 승패 여부 확인 로직 수정

* refactor: 카드 목록에서 사용되지 않는 메서드 제거

* refactor: 딜러가 결과 확인하는 로직 수정

* test: 테스트하지 못했던 코드에 대한 테스트 코드 작성

* feat: 제네릭 미션 구현

---------

Co-authored-by: kokodak <[email protected]>
@woo-chang woo-chang changed the title Step2 dazzle의 블랙잭 Mar 11, 2023
@woo-chang woo-chang changed the title dazzle의 블랙잭 dazzle 블랙잭 Step2 Mar 11, 2023
@woo-chang woo-chang changed the title dazzle 블랙잭 Step2 Dazzle 블랙잭 2단계 Mar 11, 2023
Copy link
Member

@greeng00se greeng00se left a comment

Choose a reason for hiding this comment

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

같이 객체지향을 고민해 보아요 👍

Comment on lines +32 to +38
final BlackJackGame blackJackGame = createBlackJackGame();
initialGame(blackJackGame);

drawCardsForPlayers(blackJackGame);
drawCardForDealer(blackJackGame);

printResult(blackJackGame);
Copy link
Member

Choose a reason for hiding this comment

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

추상화 기준이 깔끔해서 구조를 이해하기 쉬웠어 👍

Choose a reason for hiding this comment

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

허브 의견에 동의 합니다 굿굿

private static final int TRUMP_COUNT = 1;
private static final int INITIAL_DRAW_COUNT = 2;
private static final int BLACK_JACK_SCORE = 21;
private static final double BLACK_JACK_BONUS_RATE = 1.5;
Copy link
Member

Choose a reason for hiding this comment

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

다른 ratio의 경우 결과에 위치하는데 이 부분만 BlackjackGame에 있는게 어색한 것 같아
BLACKJACK_WIN이라는 enum을 추가해보는건 어떨까?

Copy link
Author

Choose a reason for hiding this comment

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

처음에는 이기는 상황이 2개라 어색하다고 판단했는데, 블랙잭이라는 특수한 경우이기 때문에 결과를 나누는 것도 좋은 방법인 것 같습니다. 좋은 리뷰 감사합니다!

private static final double BLACK_JACK_BONUS_RATE = 1.5;

private final Participants participants;
private final Deck deck;
Copy link
Member

Choose a reason for hiding this comment

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

요구사항을 지켜야하지 않을 명확한 이유가 없다면 나는 요구사항을 지키는게 연습에 도움이 된다고 생각해
Deck을 static으로 가져와서 사용해도 큰 문제가 없을 것 같다고 생각하는데, 다즐은 어떻게 생각해?

Copy link
Author

Choose a reason for hiding this comment

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

요구사항을 잘 지키도록 연습하는 것 중요하다고 생각합니다! static 사용을 고려해 보았으나 도입하지 않은 이유는 아래와 같습니다.

Deck은 카드를 뽑을 때마다 내부 상태가 변하기에 static으로 선언해서 어디서든 사용할 수 있게 되어버리면, 내부 상태를 예측할 수 없게 되어버려서 사용하지 않았습니다!

허브는 static 메서드를 언제 사용해야한다고 생각하는지 궁금합니다 🌿

Copy link
Member

Choose a reason for hiding this comment

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

내부 상태를 예측가능하다는 것은 BlackjackGame이 덱을 관리하는 부분에 대한 이야기겠지?

랜덤한 상태를 가지고 있는 덱의 내부 상태를 예측할 수 없는건 지금도 마찬가지라고 생각되고(필드로 관리하고 있긴 하지만) 현재의 상황에서 싱글톤 형태의 덱을 BlackjackGame만 static 메서드로 가져와서 사용하는거랑 큰 차이를 느끼지 못할 것 같아.

내 개인적인 생각이지만 BlackjackGame이 Deck을 생성하고 관리하는 느낌을 가질 수 있다는 장점이 있지만
테스트도 힘든 것 같다고 느껴져서, 필드를 3개로 사용하려면 덱 자체를 DI 받는건 어떻게 생각해?

static은 유틸리티 메서드? 정적 팩터리 메서드?

Comment on lines +76 to +82
public int getDealerProfit() {
final List<PlayerName> playerNames = participants.getPlayerNames();
final int playersProfit = playerNames.stream()
.mapToInt(this::getPlayerProfit)
.sum();
return -playersProfit;
}
Copy link
Member

Choose a reason for hiding this comment

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

BettingTable에게 위임하는건 어때?

Copy link
Author

Choose a reason for hiding this comment

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

이 부분도 고려해 보았습니다! 도입하지 않은 이유는 아래와 같습니다.

위임하기 위해서는 BettingTable이 각 플레이어들의 승부 결과를 알야야하는데, 이는 BlackJackGame이 알아야하는 정보라고 생각했습니다. 플레이어들의 정보를 Participants로부터 받고 베팅 정보를 BettingTable로부터 받아서 이를 취합해 이익을 계산하는 것은 BlackJackGame의 역할이라고 생각합니다!

Copy link
Member

Choose a reason for hiding this comment

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

나도 이 구조에서는 괜찮다고 생각해!
BettingTable이 승부 결과를 받아서 플레이어와 딜러의 이익을 계산하도록 책임을 가질 수 있는 방법도 괜찮을 것 같다는 이야기였어 👍

public class Betting {

private static final int MINIMUM_BET = 100;
private static final int MAXIMUM_BET = 1_000_000;
Copy link
Member

Choose a reason for hiding this comment

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

숫자 1_000_000 좋은데요? 나도 써먹어야지

Choose a reason for hiding this comment

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

나도 써먹어야지


public Hand getHiddenHand() {
final List<Card> cards = getHand().getCards();
return new Hand(cards.subList(0, cards.size() - 1));
Copy link
Member

Choose a reason for hiding this comment

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

리스트를 새로 생성하지 않으려고 subList를 사용했나보구나
cards.size() - 1보다 1을 상수로 사용해보는건 어때?

Copy link
Author

Choose a reason for hiding this comment

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

마지막 장을 보여주지 않는다는 것을 표현하려고 했는데 1로 변경하는게 좋을까요 🤔

Copy link
Member

Choose a reason for hiding this comment

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

카드 사이즈에서 - 1 한 리스트를 만든다는게 이해하기 어려웠어

public List<PlayerName> getPlayerNames() {
return participants.stream()
.filter(participant -> !participant.isDealer())
.map(Player.class::cast)
Copy link
Member

Choose a reason for hiding this comment

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

cast에 대해서 고민을 많이 했는데 캐스팅이 OOP적이지 않은 느낌이 많이 들어서
캐스팅을 제거해보는건 어떨까?

Copy link
Author

Choose a reason for hiding this comment

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

어떤 이유로 OOP적이지 않은 느낌이 들었는지 들어보고 싶어요 :)

Copy link
Member

Choose a reason for hiding this comment

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

cast를 해야한다면 추상화를 잘 못한게 아닐까 생각이 들었어! 내가 짠 코드도 그렇다고 생각되고


WIN("승", Betting::getValue),
DRAW("무", profit -> 0),
LOSE("패", profit -> profit.getValue() * -1);
Copy link
Member

Choose a reason for hiding this comment

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

승, 무, 패 name은 이제 필요없을 것 같아!

Comment on lines 86 to 96
final Player player = new Player("toney");
player.drawCard(new Card(ACE, SPADE));
player.drawCard(new Card(QUEEN, SPADE));
final Participants participants = new Participants(
new Dealer(),
List.of(player, new Player("dazzle"))
);
final Map<PlayerName, Betting> betting = new HashMap<>();
betting.put(new PlayerName("toney"), new Betting(10000));
final BettingTable bettingTable = new BettingTable(betting);
final BlackJackGame blackJackGame = new BlackJackGame(participants, bettingTable);
Copy link
Member

Choose a reason for hiding this comment

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

BlackjackGameTest니 BlackjackGame의 기능을 이용해 테스트 해보는건 어때?

void 카드를_받을_수_없는_상태라면_예외를_던진다() {
final Dealer dealer = new Dealer();
dealer.drawCard(new Card(QUEEN, CLOVER));
dealer.drawCard(new Card(ACE, HEART));
Copy link
Member

Choose a reason for hiding this comment

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

Fixture를 사용해서 중복을 제거해보는건 어때?

Choose a reason for hiding this comment

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

아 허브가 이미 언급했군요. 밑에 있어서 못봤삼 ><

Copy link

@hanueleee hanueleee left a comment

Choose a reason for hiding this comment

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

늦어서 죄송해요,,,,, 하지만 늦은만큼 열심히 달았습니다ㅎㅎㅎ
p.s. 다즐 코드 너무 깔끔해서 좋아요. 뭔가 마음이 편안~~해져요!!!

Comment on lines +32 to +38
final BlackJackGame blackJackGame = createBlackJackGame();
initialGame(blackJackGame);

drawCardsForPlayers(blackJackGame);
drawCardForDealer(blackJackGame);

printResult(blackJackGame);

Choose a reason for hiding this comment

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

허브 의견에 동의 합니다 굿굿

}

private BlackJackGame createBlackJackGame() {
final Participants participants = new Participants(new Dealer(), gatherPlayers());

Choose a reason for hiding this comment

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

Participants 생성자에 dealer와 player를 따로 넣어주는 방식 좋네요!!

Choose a reason for hiding this comment

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

근데 제가 못 찾은 것일수도 있는데 Participants안의 validate에서 예외를 던져주는데 해당 예외들에 대한 핸들링이 이루어지지 않고 있는것 같네요..?!

Copy link
Author

Choose a reason for hiding this comment

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

이번 미션에서는 예외가 발생했을 때 올바르지 않은 상황으로 판단하여 예외 처리를 하지 않았습니다 :)

public class Betting {

private static final int MINIMUM_BET = 100;
private static final int MAXIMUM_BET = 1_000_000;

Choose a reason for hiding this comment

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

나도 써먹어야지

public static ParticipantResponse ofDealerWithHidden(final BlackJackGame blackJackGame) {
final Hand hand = blackJackGame.getDealerHiddenHand();
return new ParticipantResponse(blackJackGame.getDealerName(), CardsResponse.of(HIDDEN_SCORE, hand));
}

Choose a reason for hiding this comment

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

dto에 정적팩토리메소드 여러개둔거 인상깊네요!!

Copy link
Author

Choose a reason for hiding this comment

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

dto도 컨트롤러 레이어에 속하므로 컨트롤러에서 변환하는 로직을 dto의 역할로 위임하였습니다!

participants.add(ParticipantResultResponse.ofDealer(blackJackGame));
participants.addAll(listOfPlayers(blackJackGame));
return participants;
}

Choose a reason for hiding this comment

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

다즐 dto를 참 효율적으로 잘 쓰는 것 같아요. 멋집니다 👍

Choose a reason for hiding this comment

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

정적팩토리메소드명도 너무 찰떡

Copy link
Author

Choose a reason for hiding this comment

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

dto를 꼼꼼히 작성하려고 노력했는데 알아봐주셔서 감사합니다~

@Override
public String toString() {
return symbol;
}

Choose a reason for hiding this comment

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

state는 getState로 가져오고, symbol은 toString을 오버라이드한 이유는 먼가요??

Copy link
Author

Choose a reason for hiding this comment

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

테스트, 디버깅에 toString을 사용하지만 출력에 용이하게 하기 위해 사용했습니다 👾


blackJackGame.initialDraw();

assertAll(

Choose a reason for hiding this comment

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

박스터가 좋아하는 assertAll 발견 ㅋㅋㅋㅋㅋㅋㅋ

@Test
void 딜러에게_진경우_베팅금액만큼_잃는다() {
final Dealer dealer = new Dealer();
dealer.drawCard(new Card(TEN, HEART));

Choose a reason for hiding this comment

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

(이것도 제 리뷰어께서 언급한 내용)
이번 미션 같은 경우에는 Card가 많이 사용되는데 계속 만들어주기 번거로우니까 TestFixture를 써보는건 어떨까요??

Copy link
Author

Choose a reason for hiding this comment

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

너무 좋은데요 👍

void 카드를_받을_수_없는_상태라면_예외를_던진다() {
final Dealer dealer = new Dealer();
dealer.drawCard(new Card(QUEEN, CLOVER));
dealer.drawCard(new Card(ACE, HEART));

Choose a reason for hiding this comment

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

아 허브가 이미 언급했군요. 밑에 있어서 못봤삼 ><

@@ -0,0 +1,25 @@
## 제네릭 이해하기

Choose a reason for hiding this comment

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

다즐은 참 부지런하군요 .. 나는 이거 언제하지 ㅎㅎㅎ.. 이번주안에는 꼭..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants