-
Notifications
You must be signed in to change notification settings - Fork 467
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단계 - 블랙잭 베팅] 짱구(박준혁) 미션 제출합니다. #877
base: dlfmadlanjwl
Are you sure you want to change the base?
Conversation
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단계도 깔끔하게 구현해주셨네요 👍 👍
몇가지 코멘트 남겼으니 확인해주세요!!
궁금한 점 있으면 언제든 DM 이나 코멘트 남겨주세요~
@@ -2,14 +2,6 @@ | |||
|
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단계에 이어서 2단계를 구현하면서도 각 객체의 책임을 명확하게 분리하려고 노력했습니다.
데이터를 가진 객체가 직접 자신의 상태를 이용해서 기능을 수행하도록 했고, 실제 세계에 존재하는 개념에 최대한 유사하게 책임을 분배하여 역할을 설정했습니다. 하지만, 그러다 보니 실제 게임에서도 그러하듯 딜러에게 많은 책임이 주어지게 되었습니다. 특히 기존에 존재했던 승패에 대한 판단 책임에 새로운 요구사항이 더해져서 수익을 계산하는 책임도 갖게 되었습니다. 실제 세계에서 딜러가 많은 책임을 가지고 있다면, 객체지향 세계에서도 객체가 많은 책임을 가져도 되는 것인지 궁금합니다.
객체 지향 프로그래밍에서 실제 세계와 비슷하게 구현했을 때 장점은 무엇일까요? 🤔
제가 생각하기에 실제와 비슷하게 구현하면 객체가 어떤 책임을 가지는지 쉽게 추측
할 수 있기 때문이라 생각해요
실제 세계를 반영하여 시스템을 이해하기 좋게 만드는거죠
그 말은 무턱대고 실제세계를 반영해서 너무 많은 책임으로 인해
오히려 이해하기 어렵게 된다면 시스템을 이해하기 좋게 만든다
는 장점이 사라질거라 생각해요
반드시 실제 세계와 동일하게 갈 필요는 없습니다 :)
비슷하게 가지만 일부는 적절하게 책임을 분배해도 괜찮아요
객체지향 세계에서는 자동차가 직접 자신에게 기름을 주유할 수도 있고
돈이라는 객체가 외부 개입없이 스스로를 곱하여 결과를 만들어낼 수도 있죠
즉 너무 많은 책임으로 인해 시스템을 이해하기 어렵다면 책임을 분리하는것을 추천합니다!
return new Money(value); | ||
} | ||
|
||
public static Money of(String rawValue) { |
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.
int 를 인자로 받아도 됐을 것 같은데 문자열로 받으신 이유가 궁금해요!
문자열 -> 정수로 변환하는 단순한 입력 타입의 실수는 View 에서 검사해도 된다고 생각하는데
짱구는 어떻게 생각하세요?
LOSE(-1), | ||
DRAW(0); | ||
|
||
private final double winningRate; |
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.
- 결과와 함께 배당을 표현해주신점 👍 👍 👍
- winningRate 는 상태와 맞지 않는 필드명으로 보여요!
대충 눈치로 이해할 순 있지만 적절한 이름으로 지어보는것도 좋을 것 같아요 😃
case WIN -> LOSE; | ||
case WIN, BLACKJACK -> LOSE; |
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.
👍
적절한 switch case 를 사용해주셔서 가독성이 좋네요
@@ -9,6 +9,7 @@ public class Hand { | |||
|
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단계에서 남겨주신 찰리의 코멘트입니다. Score라는 클래스를 생성하는 것을 제안해주셨는데, 제가 정확히 이해하지 못해서 단순 int형을 포장한 Score가 어떤 책임을 가져야 하는지 잘 모르겠습니다. 찰리가 이러한 피드백을 주신 이유에 대해 궁금합니다.
돈을 포장했듯이 카드의 점수를 나타내는 값도 포장해보라는 의도였어요
하지만 짱구가 생각하기에 Score
라는 객체로 포장했을 때 장점이 없어보인다면 반영하지 않으셔도 좋습니다 😃
점수 객체가 있다면 점수의 합을 구하는 책임이나 점수의 상태 판단에 대한 책임을 넘길 수 있다고 생각해요!
public boolean isBlackJack() { | ||
return calculateFinalScore() == BLACKJACK_SCORE && size() == BLACKJACK_SIZE; | ||
} | ||
|
||
public boolean isTwentyOne() { | ||
return calculateFinalScore() == BLACKJACK_SCORE; | ||
} |
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 Map<Player, GameResult> getGameResult(Players players) { | ||
return players.getPlayers().stream() | ||
.collect(Collectors.toMap(player -> player, player -> GameResult.getResult(player, this))); | ||
.collect(Collectors.toMap(player -> player, this::judgeResult)); | ||
} | ||
|
||
public int getNewCardCount() { |
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.
입출력 요구사항에 따라 딜러가 추가로 카드를 뽑아야 하는 경우 카드를 뽑고 뽑은 카드의 수를 출력해야 했습니다.
저는 해당 기능을 하나의 메서드에서 카드를 뽑는 것과 뽑은 카드의 수를 리턴하는 것 두 가지를 하나의 메서드에서 처리하는 방식으로 구현했습니다. 최근에 '오브젝트'를 읽으며 CQS에 대해 알게 되었는데, 제 구현 방식이 과연 CQS를 위반하는가에 대해 궁금했습니다. 두 가지 기능을 수행하고 있긴 하지만, 실제 Command로 인한 상태 변화는 Hand와 Deck에 발생하기 때문에 CQS와 관련이 없다고 생각하여 우선 다음과 같이 구현했습니다. 이에 대한 찰리의 생각도 궁금합니다.
엄밀히 말하자면 CQS 를 위반한 상태라고 볼 수 있습니다
내부적으로도 상태 변경이 일어나는것은 사실이니까요 :)
다만 CQS 를 위반한다고 무조건 안좋은것인가?
는 고민해봐야합니다.
CQS 에도 분명 단점은 존재하니
CQS 적용했을 때와 안했을 때 트레이드 오프를 해보시면 좋겠어요 😃
public Money calculateDealerRevenue() { | ||
Map<Player, Money> results = calculateRevenue(); | ||
return results.values().stream().reduce(Money::plus).map(money -> money.times(-1)).orElse(Money.of(0)); | ||
} |
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 Money calculateDealerRevenue() { | |
Map<Player, Money> results = calculateRevenue(); | |
return results.values().stream().reduce(Money::plus).map(money -> money.times(-1)).orElse(Money.of(0)); | |
} | |
return results.values() | |
.stream() | |
.reduce(Money::plus) | |
.map(money -> money.times(-1)) | |
.orElse(Money.of(0)); |
@@ -65,6 +72,11 @@ public Map<GameResult, Integer> calculateDealerWinningCount() { | |||
return dealerWinningCount; | |||
} | |||
|
|||
public Money calculateDealerRevenue() { | |||
Map<Player, Money> results = calculateRevenue(); | |||
return results.values().stream().reduce(Money::plus).map(money -> money.times(-1)).orElse(Money.of(0)); |
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.
Money.of(0)
Money 의 0 이라는 숫자는 자주 사용될 수 있으니
매선 객체를 새로 생성하지 않고 한 번 만들어놓고 재사용하는 방법도 고민해볼 수 있겠어요!
안녕하세요, 찰리! 2단계 블랙잭 베팅 미션 리뷰 요청 드립니다. 부족한 코드 읽고 리뷰해주셔서 감사합니다!
체크 리스트
test
를 실행했을 때, 모든 테스트가 정상적으로 통과했나요?객체지향 생활체조 요구사항을 얼마나 잘 충족했다고 생각하시나요?
1~5점 중에서 선택해주세요.
어떤 부분에 집중하여 리뷰해야 할까요?
책임의 분리
1단계에 이어서 2단계를 구현하면서도 각 객체의 책임을 명확하게 분리하려고 노력했습니다.
데이터를 가진 객체가 직접 자신의 상태를 이용해서 기능을 수행하도록 했고, 실제 세계에 존재하는 개념에 최대한 유사하게 책임을 분배하여 역할을 설정했습니다. 하지만, 그러다 보니 실제 게임에서도 그러하듯 딜러에게 많은 책임이 주어지게 되었습니다. 특히 기존에 존재했던 승패에 대한 판단 책임에 새로운 요구사항이 더해져서 수익을 계산하는 책임도 갖게 되었습니다. 실제 세계에서 딜러가 많은 책임을 가지고 있다면, 객체지향 세계에서도 객체가 많은 책임을 가져도 되는 것인지 궁금합니다. 각 클래스에 대한 책임의 분리가 적절했는지 리뷰해주시면 감사하겠습니다!
Score
1단계에서 남겨주신 찰리의 코멘트입니다. Score라는 클래스를 생성하는 것을 제안해주셨는데, 제가 정확히 이해하지 못해서 단순 int형을 포장한 Score가 어떤 책임을 가져야 하는지 잘 모르겠습니다. 찰리가 이러한 피드백을 주신 이유에 대해 궁금합니다.
Command Query Separation
입출력 요구사항에 따라 딜러가 추가로 카드를 뽑아야 하는 경우 카드를 뽑고 뽑은 카드의 수를 출력해야 했습니다.
저는 해당 기능을 하나의 메서드에서 카드를 뽑는 것과 뽑은 카드의 수를 리턴하는 것 두 가지를 하나의 메서드에서 처리하는 방식으로 구현했습니다. 최근에 '오브젝트'를 읽으며 CQS에 대해 알게 되었는데, 제 구현 방식이 과연 CQS를 위반하는가에 대해 궁금했습니다. 두 가지 기능을 수행하고 있긴 하지만, 실제 Command로 인한 상태 변화는 Hand와 Deck에 발생하기 때문에 CQS와 관련이 없다고 생각하여 우선 다음과 같이 구현했습니다. 이에 대한 찰리의 생각도 궁금합니다.