-
Notifications
You must be signed in to change notification settings - Fork 389
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단계 - 블랙잭 게임 실행] 허브(방대의) 미션 제출합니다. #427
Conversation
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
- 점수 계산 기능 포함 Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
Co-authored-by: Combi153 <ssrno009@gmail.com>
- calculate -> get
- drawByDealer -> drawToDealer
안녕하세요 검프! 😄 꼼꼼하게 코멘트 남겨주셔서 감사합니다. 아래에는 반영한 내용들과 약간의 질문들이 포함되어있습니다! 감사합니다! 👍 리팩터링 및 리뷰 반영한 내용
flowchart TD
BlackjackController --> BlackjackGame
BlackjackController --> InputView
BlackjackController --> OutputView
BlackjackGame --> BlackjackGameResult
BlackjackGame --> Players
subgraph 카드
ShuffledDeck --> Card
Card --> Rank
Card --> Shape
Cards --> Card
Hand -- 사용자의 패 --> Cards
Hand -- 핸드의 상태 --> State
end
Players --> 플레이어 --> Hand
subgraph 플레이어
direction BT
Gambler -.-> Player
Dealer -.-> Player
end
flowchart LR
player --> card
game --> player
game --> card
여기서 BlackjackGame, Players 클래스에서 drawTo, stay 메서드가 단순 위임 형태로 구현되었습니다. 추가로 Player를 가져오는 부분도 List를 반환하도록 설정했습니다!!
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고수..👍👍
} | ||
|
||
private Result playWithScore(final Hand other) { | ||
if (other.state.isBust() || cards.calculateTotalScore() > other.cards.calculateTotalScore()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
other.state.isBust() 대신 other.isBust()가 가능하게끔 구현하는 것은 어떤가요?
뒤에 있는 other.cards.cal~~ 도 마찬가지로요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 말랑🍡 늦은 시간에 리뷰 남겨주셔서 감사합니다.
방금 간단하게 반영을 해보았습니다~
현재 Hand가 State 자체를 필드로 가지고 있는데, 단순히 이 메서드만을 위해 private 메서드를 추가로 3개나 만들어야 해서 해당 메서드의 가독성은 올라가지만 전체적으로 가독성이 떨어지는 느낌을 받았습니다.
말씀해주신 other.cards.cal~~ 부분은 아래에 존재하는 calculateScore() 메서드를 사용한다면 가독성을 개선할 수 있을 것 같아요! 감사합니다 👍
package blackjack.domain.card; | ||
|
||
public enum Rank { | ||
ACE("A", 1), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rank는 도메인인데, 뷰와 관련된 책임을 담당하는 것 아닌가요?
ACE를 A로 바꾸어 출력해달라는 요구사항이 생기면 뷰가 아닌 도메인의 코드가 바뀌는 것이 바람직한가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전 상황에 따라 작성을 하는 편입니다.
새로운 도전을 하지 않는 이상 복잡한 방법보다 최대한 간단한 방법으로 해결하는 것을 선호하는 편입니다.
이번 미션에서는 빠르게 구현하고, 다른 부분에 집중하는 것이 더 좋다고 생각이 들었어요!
뷰에 요구사항에 따라 도메인 코드가 변경되지 않는 것이 왜 바람직할까요?
크게 본다면 변경사항에 대한 파급력을 줄이기 위해 관심사를 분리하는 것이고, 이는 결국 유지보수를 용이하게 하기 위함이라고 생각됩니다.
현재 미션에서는 단순하고 명료함을 포기할만큼, 해당 부분에서 큰 이득이 있다고 느껴지지 않았습니다.
package blackjack.domain.card; | ||
|
||
public enum Shape { | ||
DIAMOND("다이아몬드"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
마찬가지입니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
위와 동일합니다 👍
@Override | ||
public Card draw() { | ||
final Card card = cards.removeFirst(); | ||
cards.addLast(card); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다시 더해주시는 이유가 있나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deck에서 카드가 한 장씩 사라지는게 개인적으로 마음에 안들었어요!
필요한 경우 shuffle 메서드를 추가한다면 재사용할 수도 있지 않을까 상상만 해보았습니다~ 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deck에, 무덤패 등의 속성이 추가되도 좋겠네요 :0
그럴일은 없겠지만, 51개가 다 돌면 골치아플수도 있을 것 같아서요.
이후 shuffle을 할 때, 무덤패 + 사용패 후 shuffle을 해도 좋을 것 같구요 :)
다만, 이부분은 세밀한 부분이라, 편하게 진행해주세요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
무덤패 속성을 추가하는 것도 재밌을 것 같군요 👍
import blackjack.domain.card.Hand; | ||
import java.util.List; | ||
|
||
public abstract class AbstractPlayer implements Player { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
추상 골격 클래스로 구현해 주신 것 같은데, 그냥 Player를 추상 클래스로 정의하는 것이 더 간편하지않나요?
굳이 Player를 인터페이스로 만들고, 이에 대한 추상 골격을 만들어주신 이유가 있으실까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일단 처음에 인터페이스로 구현을 했기 때문에 해당 부분을 지우지 않고 새로운 도전을 해보고 싶었습니다. 추상 골격 클래스가 뭔지는 알지만, 정말 사용하면 장점이 있을까? 라고 생각을 하면서 적용을 해보았는데요. 😄
복잡한 인터페이스일 때 사용하면 좋다고 알고 있는데, 그렇게 복잡한 인터페이스가 아니었기 때문에 장점이라고 할 만한 부분을 느끼지 못했습니다.
이 부분은 말랑이 코멘트 남겨주신대로 추상 클래스 하나만 사용하는 것이 간결한 선택이라고 생각이 듭니다 👍
리뷰 남겨줘서 감사합니다~ 다른 이야기도 더 많이 나눠보면 좋을 것 같아요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
학습을 위한 도전이라면 좋은 도전이라 생각합니다 :)
저는 추상클래스를 주로, public method의 구현을 도와주는 protected abstract method가 필요할 때, 사용하곤 합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
검프만의 기준을 알려주셔서 감사합니다 🙇
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 허브! 구현 잘 해주셨어요 :)
각 도메인별 책임이 확실히 잘 보이네요!
현재도 커맨트에 댓글을 남기시고 계셔서, 저도 해당 커맨트에 답글남길게요!!
추가 반영은 다음 레벨에서 진행해주시면 좋을 것 같아요!!
Cards 생성자 추가
Player가 카드를 초기에 2장을 가지고 있는 형태가 되어
블랙잭 게임을 진행하며, Hand에 카드가 2장이 있다고 하셧는데요!,
public Hand(final List<Card> cards) {
this.cards = new Cards(cards);
this.state = State.calculateState(this.cards);
}
의 경우, 기본생성자에서만 사용되고 있어요, 0장을 가진다면, 사용하는곳에서 인자로, new ArrayList<>()를 넣어주는게 어떨까 ? 라는 의문에서 시작된 피드백이였는데요.
즉, 사용하는곳에서 빈 List를 만들어 생성자의 인자로 넣어줘도 문제 없어보입니다 :)
TestFixture 추가
Fixture를 사용하게되면, 준비,실행,검증 구절 중 준비 구절의 양을 줄일 수 있다고 생각하여, 저도 많이 즐겨쓰는 방법이에요 :)
다만, 사용하신 픽스쳐를 가져와, List를 만드는 걸 많이 확인할 수 있었는데요.
이경우, List를 제공하는 픽스처를 만들어 보는건 어떨까요?!
수고많으셨습니다 :)
public boolean isHit() { | ||
return this == HIT; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵, enum 자체가 HIT을 표현하고 있기에, 그대로 비교를 해도 문제없어 보입니다 :)
final BlackjackGame blackjackGame = initializeGame(); | ||
initialDraw(blackjackGame); | ||
draw(blackjackGame); | ||
play(blackjackGame); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오우 추상화 단계가 깔끔하네요 💯
} | ||
|
||
private BlackjackGame initializeGame() { | ||
final Players players = createPlayers(new Retry()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
외부에서 Retry를 주입할 순 없을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2단계때는 Controller가 Retry와 BlackjackGame을 가지고 있는 방향으로 수정 해봐야겠군요! 👍
|
||
private void draw(final BlackjackGame blackjackGame) { | ||
for (final Player player : blackjackGame.getPlayers()) { | ||
drawOnce(blackjackGame, player); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
몇번을 메서드에 표현하는것 보단,
drawOnce(blackjackGame, player); | |
draw(blackjackGame, player); |
는 어떨까요? 파라미터로 그 의미를 충분히 유추할 수 있을 것 같네요 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
명확해서 더 좋은 것 같습니다! 👍
public Cards() { | ||
this(new ArrayList<>()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트에서만 사용되는 생성자는 삭제부탁드립니다.
public Cards(final List<Card> cards) { | ||
this.cards = new ArrayList<>(cards); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
방어적 복사 💯
public boolean isBlackjack() { | ||
return this == BLACKJACK; | ||
} | ||
|
||
public boolean isPlayable() { | ||
return this == PLAY; | ||
} | ||
|
||
public boolean isBust() { | ||
return this == BUST; | ||
} | ||
|
||
public boolean isNotBust() { | ||
return this != BUST; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
자료구조인 enum에 메서드를 추가할 이유는 없어보여요!!
private static final String NEW_LINE = System.lineSeparator(); | ||
private static final int INITIAL_DRAW_COUNT = 2; | ||
private static final int DEALER_OPEN_CARD_INDEX = 0; | ||
private static final String INITIAL_DRAW_MESSAGE = "에게 " + INITIAL_DRAW_COUNT + "장을 나누었습니다."; | ||
private static final String DELIMITER = ", "; | ||
private static final String PLAYER_CARD_MESSAGE_FORMAT = "%s 카드: %s"; | ||
private static final String PLAYER_SCORE_MESSAGE_FORMAT = " - 결과: %d"; | ||
private static final String ERROR_MESSAGE = "[ERROR] "; | ||
private static final String DEALER_DRAW_MESSAGE = NEW_LINE + "딜러는 16이하라 한 장의 카드를 더 받았습니다." + NEW_LINE; | ||
private static final String GAME_RESULT_MESSAGE = NEW_LINE + "##최종 승패"; | ||
private static final String GAME_RESULT_PLAYER_MESSAGE_FORMAT = "%s: %s"; | ||
private static final String WIN_MESSAGE = "승"; | ||
private static final String PUSH_MESSAGE = "무"; | ||
private static final String LOSE_MESSAGE = "패"; | ||
private static final String GAME_RESULT_DEALER_MESSAGE_FORMAT = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
각 메세지를 다 상수화를 해야만하는 이유가 있을까요?! 한면만 쓰이는 메세지의 경우, 메서드 본문에 나타내는게 더 가독성이 좋아보여요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
package-private 상수 사용한 부분 제거와 함께 반영해보도록 하겠습니다~ 👍
void mission2() { | ||
final String[] arrays = {"first", "second"}; | ||
final SimpleList<String> result = SimpleList.<String>fromArrayToList(arrays); | ||
|
||
assertAll( | ||
() -> assertThat(result.contains("first")).isTrue(), | ||
() -> assertThat(result.contains("second")).isTrue() | ||
); | ||
} | ||
|
||
@Test | ||
void mission3() { | ||
final SimpleList<Double> doubleValues = new SimpleArrayList<Double>(0.5, 0.7); | ||
final SimpleList<Integer> intValues = new SimpleArrayList<Integer>(1, 2); | ||
|
||
assertAll( | ||
() -> assertThat(sum(doubleValues)).isEqualTo(1.2), | ||
() -> assertThat(sum(intValues)).isEqualTo(3) | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트가 의도하는 바가 무엇일까요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
미니 미션이라고 크게 생각을 하지 않고 메서드명을 작성했네요!
이 부분도 의미있는 테스트명으로 수정해보겠습니다 👍
안녕하세요 검프!
전 허브🌿라고 합니다. 잘부탁드립니다!
블랙잭 미션동안 잘 부탁드립니다!
부족한 부분이나 개선을 하면 좋겠다고 생각하시는 부분에 대해 리뷰 남겨주시면 적극적으로 반영하겠습니다! 감사합니다 😄