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단계 - 블랙잭 게임 실행] 채채(신채원) 미션 제출합니다. #410

Merged
merged 72 commits into from
Mar 10, 2023

Conversation

chaewon121
Copy link

@chaewon121 chaewon121 commented Mar 3, 2023

채채 (페어: 메리) 미션 제출합니다!

고민한 부분들

  • controller의 역할
    블랙젝 게임은 계속해서 입력을 받고 그 입력으로 인해 값들이 변경됩니다.
    BlackJackGame 이라는 클래스를 추가하여 컨트롤러의 역할을 도와주는 클래스를 추가하려고 하였는데
    그렇게 하면 BlackJackGame은 서비스 패키지가 되는 것일까요? 컨트롤러의 역할에 대해 고민이 많이 되었습니다.
    이부분에 대해 의견 주시면 감사하겠습니다!
  • 자료 관리 부분에 대해
    이번 미션에서 딜러의 결과, 플레이어들의 결과 이 두가지의 결과값을 갖게되어 두가지 결과값을 따로 관리를 하려고 했습니다. 그러나 고민을 해보니 이 두 결과값이 서로 깊게 연관이 되어있고 플레이어의 결과값이 딜러의 결과값에 영향을 준다는 것을 깨닫고 따로 관리하는 것은 비효율 적이지 않을까 고민하게 되었습니다. 그래서 플레이어의 결과값만 저장을 하고 딜러의 결과값을 계산하는 메소드만 추가를 하여 데이터 관리를 하였습니다..
    결과값 관리에 대한 피드백 주시면 감사하겠습니다!

리뷰 잘부탁드립니다!

Copy link

@choijy1705 choijy1705 left a comment

Choose a reason for hiding this comment

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

질문주신 내용에 대한 답변 및 몇가지 코멘트 남겼습니다!
확인부탁드려요
그리고 딜러의 결과값이 조금 이상하게 나옵니다.
이 부분도 체크해봐주시면 좋을것 같아요

import java.util.Collections;
import java.util.List;

public class Cards {

Choose a reason for hiding this comment

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

static 하게 사용하는것보다는 그냥 생성자로 생성할수 있도록 하는게 어떨까요?

  • 우선 확장 가능성이 없을것 같아요. application하나당 오직 하나의 cards만 존재하는데 만약 서비스가 커져서 여러개의 게임방을 만든다고 하면 모두 바꿔야할것 같습니다
  • 또한 언제 어디서든 card를 뽑아 쓴다는게 독이 될수 있을것 같은데요. 지금은 혼자 코드를 관리하지만 여러명에서 코드를 관리한다 생각해보면 어느 시점에 카드가 사용될지 예측할수 없을것 같습니다

static으로 관리하는 것은 상태가 전혀없는 함수들을 static으로 관리하면 좋을것 같아요. 예를 들면 자동차 게임에서 랜덤 숫자를 생성하는 로직 같은 util 기능들은 상태가 없기 때문에 언제 어디서든 호출하여도 문제가 없을것 같습니다.

src/main/java/blackjack/view/OutputView.java Show resolved Hide resolved
import java.util.List;
import java.util.Map;

public class RunningGame {

Choose a reason for hiding this comment

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

컨트롤러인거 같은데 명시적으로 Controller라는 이름으로 표현하면 좋을것 같습니다!

src/main/java/blackjack/game/BlackJackGame.java Outdated Show resolved Hide resolved
src/main/java/blackjack/game/BlackJackGame.java Outdated Show resolved Hide resolved
Players players = blackJackGame.getPlayers();

OutputView.printReadyMessage(names);
printUserFirstCards(players.getPlayers(), dealer);

Choose a reason for hiding this comment

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

Suggested change
printUserFirstCards(players.getPlayers(), dealer);
printUserFirstCards(users);

같은 User일텐데 Users로 관리해보는 건 어떤가요?
Users에 getDealer, getPlayers, getUsers를 구현해서 사용하면 파라미터로는 항상 Users만 넘기면 될것 같습니다

Copy link
Author

Choose a reason for hiding this comment

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

플레이어들과 딜러를 넘기는 경우는 저 함수 하나만 존재하는데 users라는 클래스를 추가하는것이 크게 장점으로 느껴지지 않습니다. 데이터관리 면에서나 또다른 장점이 존재한다면 말씀해주시면 감사하겠습니다!

Choose a reason for hiding this comment

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

Users클래스를 새로 만들다기보다 players 클래스를 users로 관리하면 어떨지의 의견이었습니다.
파라미터의 숫자를 일단 줄일수 있을것 같네요!


import java.util.*;

public class GameResult {
Copy link

@choijy1705 choijy1705 Mar 6, 2023

Choose a reason for hiding this comment

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

말씀주신대로 dealer와 player의 결과는 항상 연관된 결과값이라고 생각합니다. 근데 player와 dealer의 결과 타입이 달라서 쉽게 눈에 들어오지 않는 것 같아요. 결과는 항상 게임이 끝나고 나서 계산이 될것이고 계산된 결과값은 변하지 않을거에요.
굳이 key값이 Player, 결과값이 ResultMatcher일 필요는 없을것 같습니다.
Map<String, String> 으로 최종 결과를 저장해서 하나의 result 변수에 dealer와 player의 결과를 저장하면 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

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

딜러의 경우 결과값 승 무 패 의 개수로 저장이 되어야 하는데 혹시 딜러의 결과값을 Map<String, String> 여기에 어떻게 저장하라는 말씀이신지 설명해주시면 감사하겠습니다! 필요한 결과값만 저장하는 좋은 방안을 제시해주셔서 감사합니다!

Choose a reason for hiding this comment

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

result.put("딜러", "1승 1패");
result.put("유저1", "승");
결과 계산을 다하고 요렇게 map에 담아주면 player, dealer를 동시에 관리할 수 있을것 같아서요

Comment on lines +27 to +29
public static void printPlayerCurrentCards(Player player) {
System.out.println(player.getPlayerName() + CARD_STRING + OutViewHelper.getUserCards(player));
}

Choose a reason for hiding this comment

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

도메인을 view에서 다알고 있네요

Suggested change
public static void printPlayerCurrentCards(Player player) {
System.out.println(player.getPlayerName() + CARD_STRING + OutViewHelper.getUserCards(player));
}
public static void printPlayerCurrentCards(String playerName, List<String> cardNames) {
System.out.println(playerName + CARD_STRING + String.join(",", cardNames));
}

지금은 문제가 없겠지만. 만약 개인정보가 있을때 도메인 자체를 view로 넘기게 되면 개발자도구를 통해 중요정보를 다 볼 수 있을것 같아요.

CardSymbol symbol = CardSymbol.HEART;

// then
Assertions.assertThatNoException().isThrownBy(() -> new Card(number, symbol));

Choose a reason for hiding this comment

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

예외가 안던져지는지 체크하는것보다
생성한 card에 값이 잘들어갔는지를 체크해보면 좋을것 같아요
지금은 파라미터만 받고 필드에 저장하는 로직을 빼먹어도 통과할것 같아요

Copy link
Author

Choose a reason for hiding this comment

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

생성하는것 보다 값이 잘 들어갔는지 테스트 하는 것이 맞는 것 같네요 수정하겠습니다!

src/main/java/blackjack/view/InputView.java Outdated Show resolved Hide resolved
Copy link

@choijy1705 choijy1705 left a comment

Choose a reason for hiding this comment

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

안녕하세요 채채!
피드백 반영잘해주셨는데요👍
2단계 진행하시면서 남긴 코멘트들 반영해주시면 될것 같아요

}

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

Choose a reason for hiding this comment

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

Suggested change
return cardNumber.equals(CardNumber.ACE);
return cardNumber == CardNumber.ACE;

enum의 경우 equals도 가능하긴 하지만 ==이 더 안전할것 같아요. 여기에 대해서는 한번 생각해보면 좋을것 같아요

Comment on lines +27 to +32
public static CardNumber of(String inputNumber) {
return Arrays.stream(CardNumber.values())
.filter(cardNumber -> cardNumber.number.equals(inputNumber))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("찾을 수 없는 카드넘버입니다."));
}

Choose a reason for hiding this comment

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

테스트에서만 사용하는 코드인것 같아요

CardNumberTest에서 CardNumber.valueOf(value) 를 테스트 하고싶은거 같은데
굳이 모든 경우를 다 테스트해볼 필요가 있을까요?
하나만 해도 테스트가 충분히 되고 CardNumber.of(number)를 그냥 실제 CardNumber.ACE 처럼 확인해보면 어떤가요

private static final int CARD_TOTAL_SIZE = 48;

private static Stack<Card> cards;
private static final Deck DECK = new Deck();

Choose a reason for hiding this comment

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

이전에 리뷰한거 같은데 static을 계속 쓰는 이유가 궁금합니다

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

public class Hand {
Copy link

@choijy1705 choijy1705 Mar 10, 2023

Choose a reason for hiding this comment

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

Hand는 너무 뜬금없는 클래스명 같아요

일급컬렉션은 Collection이외에 어떠한 필드변수가 없는게 정의 아닌가요?
totalScore를 변수로 가지고 있으면 일급 컬렉션 위반일것 같습니다


import java.util.*;

public class GameResult {

Choose a reason for hiding this comment

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

result.put("딜러", "1승 1패");
result.put("유저1", "승");
결과 계산을 다하고 요렇게 map에 담아주면 player, dealer를 동시에 관리할 수 있을것 같아서요

Comment on lines +10 to +19
@ParameterizedTest(name = "input : {0}")
@CsvSource(value = {"A:ACE", "2:TWO", "3:THREE", "4:FOUR", "5:FIVE", "6:SIX", "7:SEVEN", "8:EIGHT", "9:NINE", "K:KING", "Q:QUEEN", "J:JACK"}, delimiter = ':')
@DisplayName("of()는 카드넘버를 문자로 받아 값을 반환해 준다.")
void get_value_of_card_number_test(String number, String value) {
// given & when
CardNumber expected = CardNumber.valueOf(value);

// then
Assertions.assertThat(CardNumber.of(number)).isEqualTo(expected);
}

Choose a reason for hiding this comment

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

위에서 언급드렸지만
테스트를 위한 코드를 만들어서 까지 parameterizedTest를 굳이 할 필요없을것 같습니다.
parameterizedTest는 테스트의 시간이 길어지게 하는 주요 원인이 될 수 잇을것 같아요

Suggested change
@ParameterizedTest(name = "input : {0}")
@CsvSource(value = {"A:ACE", "2:TWO", "3:THREE", "4:FOUR", "5:FIVE", "6:SIX", "7:SEVEN", "8:EIGHT", "9:NINE", "K:KING", "Q:QUEEN", "J:JACK"}, delimiter = ':')
@DisplayName("of()는 카드넘버를 문자로 받아 값을 반환해 준다.")
void get_value_of_card_number_test(String number, String value) {
// given & when
CardNumber expected = CardNumber.valueOf(value);
// then
Assertions.assertThat(CardNumber.of(number)).isEqualTo(expected);
}
@DisplayName("of()는 카드넘버를 문자로 받아 값을 반환해 준다.")
@Test
void get_value_of_card_number_test(String number, String value) {
// given
String value = "ACE";
// when
CardNumber expected = CardNumber.valueOf(value);
// then
Assertions.assertThat(CardNumber.ACE).isEqualTo(expected);
}

@ParameterizedTest(name = "input : {0}")
@CsvSource(value = {"하트:HEART", "다이아몬드:DIAMOND", "스페이드:SPADE", "클로버:CLOVER"}, delimiter = ':')
@DisplayName("of()는 심볼 이름를 받아 해당 enum 을 반환한다.")
void test_(String symbolName, String symbol) {

Choose a reason for hiding this comment

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

마찬가지로 고려해주세요

Comment on lines +52 to +54
public int getTotalScore() {
return totalScore.getTotalScore();
}

Choose a reason for hiding this comment

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

Suggested change
public int getTotalScore() {
return totalScore.getTotalScore();
}
public int getTotalScore() {
int newTotalScore = 0;
for (Card card : playerCards) {
newTotalScore += card.getCardNumber().getValue();
}
return updateAceScore(newTotalScore);
}

요렇게만 있으면 totalScore에 관한 모든 로직은 필요없지 않나요?

if (cards.size() < MIN_CARD_SIZE) {
throw new IndexOutOfBoundsException("뽑을 수 있는 카드가 없습니다.");
}
return cards.remove();

Choose a reason for hiding this comment

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

stack 은 vector 를 상속한 클래스인데요
vector가 성능저하의 주요 원인중 하나라서 vector사용을 권장하지 않습니다. 공식 문서상에서도요.
이를 구현한 stack도 차라리 deque를 써라고 권장하고 있습니다.
여유가 된다면 직접 클래스를 들어가보면 적혀있는 주석을 읽어보시면 좋을것 같아요

@choijy1705 choijy1705 merged commit 91fcf3f into woowacourse:chaewon121 Mar 10, 2023
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.

2 participants