-
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
[2단계 - 블랙잭(베팅)] 허브(방대의) 미션 제출합니다. #537
Conversation
|
||
private static void validateBetUnit(final int value) { | ||
if (isInvalidUnit(value)) { | ||
throw new IllegalArgumentException("베팅은 100 단위로 할 수 있습니다."); |
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.
"베팅은 " + BETTING_UNIT + " 단위로 할 수 있습니다."
상수 사용 하겠습니다! 😢
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.
안녕하세요 허브 :) 구현 잘해주셨어요.
전반적인 수정이 필요한 피드백을 남겼는데요. 학습하는 의미로 한번 적용해보셨으면 좋겠어요 :)
진행하시다가 어렵거나 질문사항이 있으면, 언제든 DM 및 커멘트 달아주세요.
그럼 수고 많으셨습니다.
README.md
Outdated
Hand -- 사용자의 패 --> Cards | ||
Hand -- 핸드의 상태 --> State | ||
end | ||
|
||
Players --> 플레이어 --> Hand | ||
|
||
subgraph 플레이어 | ||
direction BT | ||
Gambler -.-> 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.
유료버전에서 제공하는 다이어그램도 좋은 것 같습니다!
IntelliJ에서 markdown mermaid 설정 체크만 해준다면 IntelliJ와 깃허브에서도 둘다 확인이 가능하기 때문에 mermaid도 괜찮다고 생각됩니다 👍
|
||
public class BlackjackApplication { | ||
public final class BlackjackApplication { |
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.
정적 메서드만 가지는 객체에서, final을 사용하는 이유가 있을까요?
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.
클래스 final의 경우, 상속으로 인한 사이드 이펙트가 생길 수 있는 클래스 혹은, 추가 확장이 없음이 확실할 때 걸어주시는 게 좋다고 생각하는데요.
intellij 에서 class 생성시 기본적으로 public class로 생성되기 때문에, 협업시 혼란의 여지가 있을 수 있습니다.
(final이 안걸려있으면, 확장을 막 해도 되는건가? final의 기준이 뭘까?)
모든 클래스에 걸어주는것 vs 필요시에 걸어주는 것의 부분에서 고민해보시길 바래요 :)
이부분은 허브 말씀처럼, 선택에 맡길게요~
private boolean isSameCommand(final String command) { | ||
return this.command.equalsIgnoreCase(command); | ||
} |
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.
대/소문자를 구분하지 않는 구현의 추상화가 잘되어있네요 :)
@@ -1,9 +1,8 @@ | |||
package blackjack.controller; | |||
|
|||
public class Retry { | |||
public final class Retry { | |||
|
|||
private static final int DEFAULT_COUNT = 5; |
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.
DEFAULT_COUNT를 사용하지 않고,
applicatoin 구동시 넣어줘도 좋을 것 같네요.
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 InputView() { | ||
this.scanner = new Scanner(System.in); | ||
} | ||
|
||
public static InputView getInstance() { | ||
return INSTANCE; | ||
} |
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.
[input | ouput]View가 싱글턴 패턴으로 구현되어야 하는 이유가 있을까요?!
싱글턴 패턴을 사용하신 이유를 알 수 있을까요?
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.
static으로 사용할까, 싱글턴으로 사용할까 고민하다가 싱글턴이 더 괜찮을 것 같다는 생각이 들었습니다.
지금보니 특별히 싱글턴을 도입할 이유가 없는 것 같네요! 생성자를 사용하는 것이 명확할 것 같습니다.
public Result play(final Hand other) { | ||
if (state.isBlackjack()) { | ||
if (state == BLACKJACK) { | ||
return playWithBlackjack(other); | ||
} | ||
if (state.isBust()) { | ||
if (state == BUST) { | ||
return Result.LOSE; | ||
} | ||
return playWithScore(other); | ||
} |
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.
if 문도, 줄일 수 있을 것 같구요 :)
public boolean isAce() { | ||
return this == ACE; | ||
} |
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.
Ace를 가져와서, Cards에서 10을 더해주고 있네요, enum에서
예외로 Ace는 1 또는 11로 계산할 수 있으며,
의 요구사항을 표현할 수 없을까요?
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.
음.. 카드의 상태에 따라 10을 더해 11로 계산할 수 있다고 생각해서 Cards에 있는게 더 좋은 것 같다는 생각이 듭니다!
public Bets() { | ||
bets = new LinkedHashMap<>(); | ||
} |
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.
LinkedHashMap 이 필요한 이유가 있을까요?
bets의 순서에 따라 로직이 달라지나요?!
단순히 UI에 순서대로 보여주기 위함이라면, UI를 위한 로직이 Bets에 포함된건 아닐까요?
Dealer와 Gambler를 통해, 출력시, 딜러 -> 플레이어 등으로 표현해볼 수 잇을 것 같아서요.
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.
UI 로직이 반영된 부분 맞습니다!
수정하겠습니다 👍
public final class Name { | ||
private static final int LENGTH_LOWER_BOUND = 1; | ||
private static final int LENGTH_UPPER_BOUND = 5; | ||
private static final String RESERVED_DEALER_NAME = "딜러"; |
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.
RESERVED_DEALER_NAME -> DEALER
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.
깔끔한 것 같습니다 👍 바로 수정하겠습니다!
Arguments.of(CardFixtures.BLACKJACK, BLACKJACK), | ||
Arguments.of(CardFixtures.BUST, 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.
CardsFixutre를 만들어도 좋겠네요 :)
클래스이름은 단수로 설정해주세요 :)
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에 blackjack이나 bust를 확인하는 메서드를 제거하고 싶었는데 state에서 전부 오버라이딩하거나, 제거를 하게된다면 중복된 부분이 많아져서 제거하지 못했습니다. 😢
저는 지금 작성해주신대로 구현되도 나쁘지 않다고 생각이 들어요.
각 상태별로 WIN, LOSE 판별 규칙이 다르니까요.
또한 Cards에서 blackJack이냐 Bust인지 판단하는 책임은 Cards가 가져도 충분히 좋을 책임이라 생각해서요 :)
수고많으셨어요.
README.md
Outdated
```mermaid | ||
--- | ||
title: Hand 상태 | ||
--- | ||
flowchart BT | ||
AbstractHand -.-> Hand | ||
Running --> AbstractHand | ||
Finished --> AbstractHand | ||
Hit --> Running | ||
Blackjack --> Finished | ||
Bust --> Finished | ||
Stay --> Finished | ||
|
||
``` | ||
|
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.
간단하게 작성해보겠습니다!
@@ -18,14 +16,12 @@ public static BlackjackCommand from(final String command) { | |||
return Arrays.stream(values()) | |||
.filter(value -> value.isSameCommand(command)) | |||
.findAny() | |||
.orElseThrow(() -> new IllegalArgumentException(INVALID_COMMAND_MESSAGE + command)); | |||
.orElseThrow(() -> new IllegalArgumentException( | |||
HIT.command + " 또는 " + STAY.command + "을 입력해야 합니다. 입력값:" + command) |
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.
var collect = Arrays.stream(values()).map(it -> it.command).collect(Collectors.joining(" 또는 "));
확장성을 고려한다면 위와 같이 상수 반복을 추가해도 괜찮겠네요 :)
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 static final InputView inputView = new InputView(); | ||
private static final OutputView outputView = new OutputView(); |
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.
생성자 인자로 받아와도 좋을 것 같네요 :)
IntputView Outputview가 도메인과 밀접한 것 같아서요.
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를 run의 인자로 받아와 3개로 줄여보겠습니다!
retry = retry.decrease(); | ||
} | ||
} | ||
throw new IllegalArgumentException(this.retry.getFailMessage()); |
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.
예외 자체를 상수로 가지고 있는것으로 이해했습니다! 적용해보겠습니다!
private void addPlayers() { | ||
Retry retry = this.retry; | ||
while (retry.isRepeatable()) { |
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 retry 를 파라미터로 받으면,
Retry retry = this.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.
왜 이런 생각을 못했을까요 😢
for (final Name player : blackjackGame.getGamblerNames()) { | ||
addBet(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.
blackjackGame.getGamblerNames()
.forEach(this::addBet);
로도 사용할 수 있을 것 같은데,
과연 메서드로 분리해야 했을까요?!
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.
addPlayers(retry);
addBets(retry);
initialDraw();
draw(retry);
play();
run 메서드가 위와 같이 추상화 되어있기 때문에 분리하는 것도 괜찮을 것 같다는 생각이 듭니다!
public abstract class AbstractHand implements Hand { | ||
private final Cards cards; | ||
|
||
AbstractHand(final Cards 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.
해당 생성자는 default 접근 지정자를 가지는 걸까요?
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.
protected가 더 적절할 것 같습니다. 다른 패키지에서도 상속받아서 사용할 수도 있으니까요!
import java.util.Map; | ||
|
||
public final class Bets { | ||
private final Map<Name, Money> bets; |
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.
map의 key를Name이 아닌, 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.
반영했습니다! 테스트가 조금 더 복잡해져서 Name으로 변경을 했었는데, 의미상으로는 Player가 Key로 있는데 더 깔끔한 것 같습니다!
draw(); | ||
play(); |
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.
draw하는 과정은 play 과정이 아닐까요?!
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.
play에 draw를 넣었을 때 initialDraw도 넣어야할 것 같고, 둘 다 넣으면 베팅하는 부분도 넣어야할 것 같은 느낌이 들어서 지금도 괜찮을 것 같다는 생각이 드는데 검프는 어떻게 생각하시나요? 🤔
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.
베팅, initialDraw 등을 initialize 로 빼고, play에 draw를 포함하는 방법도 있겠네요 :)
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개로 나눠지겠군요 😄
피드백 남겨주신 부분 반영해보았습니다! 항상 꼼꼼하게 코멘트 달아주셔서 감사합니다 검프! |
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.
안녕하세요 허브 ! 구현 잘해주셨어요 :)
꽤나 복잡한 리뷰였을 텐데도, 잘 적용해주셨어요...!
여기까지 진행해도 다음레벨을 진행하는데 무리 없을거라 판단하여, 이번 미션은 여기서 머지하겠습니다
수고많으셨어요 :)
간단한 리뷰를 남긴다면
다음 레벨의 미션에는 학습의 취지로 테스트에 given when then 패턴을 한번 적용해보시면 좋을 것 같아요 :)
테스트의 "일관성"을 지킬 수 있거든요.
물론 테스트가 요구사항을 잘 검증하는지가 1순위이긴 하지만요.
throw new IllegalArgumentException(retry.getFailMessage()); | ||
throw retry.getException(); |
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.getFailMessage()를 상수화 하자는 의미였어요..!
명확한 피드백을 못드렸었네요 ㅠㅠㅠ 요건 다음 레벨에서 적용해주세요 :)
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.
메시지 자체를 상수화하는 거였군요! 😄
블랙잭 미션을 진행하면서 다양한 방법을 제시해주셔서 재밌었습니다!
항상 꼼꼼하게 리뷰 남겨주셔서 감사합니다!
안녕하세요 검프🍫! 잘 지내셨나요?
검프와 같이 협업 한다고 생각하고, 납득이 가는 방향이라면 남겨주신 코멘트를 최대한 반영하려고 노력했습니다.
변경점은 다음과 같습니다!!
부족하거나, 더 좋은 방법이 있다면 코멘트 남겨주시면 바로 반영하겠습니다!