-
Notifications
You must be signed in to change notification settings - Fork 355
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
4단계 - 로또(수동) #1088
base: giwankim
Are you sure you want to change the base?
4단계 - 로또(수동) #1088
Conversation
Lotto 를 통합하면 상태를 변경하지 않고 새로운 객체를 만든다.
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.
지완님 어느덧 로또 4단계 미션까지 빠르게 구현해주셨네요 👍
크지는 않지만 소소하게 피드백을 남겨드렸는데, 마지막 미션인만큼 체크하고 넘어가면 좋을 것 같아 피드백 확인 후 다시 리뷰요청 부탁드려요!
|
||
fun getNumberOfManual(): Int = getNumber(NEWLINE + NUMBER_OF_MANUAL_PROMPT) ?: getNumberOfManual() | ||
|
||
fun getManualLotto(numberOfManual: Int): Lotto { |
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계층에서 수행하고 있는 것 같아요 🤔
UI계층에선 단순 값 입/출력만 책임지고 서비스 계층에서 도메인 계층에 대한 의존성을 가지는게 어떨까요?
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.
리팩토링해서 application 레이어로 객체 매핑 로직을 이관했습니다.
원래 의도는 헥사고날의 어댑터 같은 역할이었습니다. 그래서 Int, List 같은 것들을 담고 있는 RequestDto를 도메인 객체로
변경하는 역할을 담당하는 mapper 컴포넌트 도입을 고려하다가 이렇게 구현하게 되었습니다.
return WinningLine(line, bonusBall) | ||
} | ||
|
||
private fun getNumber(prompt: String): Int? { | ||
println(prompt) | ||
val result = readln().toIntOrNull() |
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.
참고만 하시면 좋을 것 같아요.
현재 readIn()을 통해 값을 입력받은 뒤 각각의 함수에서 적절히 타입 변환을 해주고 있는데 이를 refied를 이용해 추상화를 할 수 있습니다.
val result: Int = prompt(message)
private inline fun <reified T> prompt(message: String): T? {
val rawValue = promptAndRead(message)
val result = when (T::class) {
Int::class -> rawValue?.toInt()
Long::class -> rawValue?.toLong()
else -> rawValue
}
return result as? T
}
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.
나중에 꼭 reified
키워드를 알아보도록 하겠습니다. ChatGPT에서는 런타임까지 제네릭 클래스 정보가 남겨지게 하는 기능이라고 하네요. 그래서 여기서는 컴파일 시 없어질 수 있는 리턴 타입으로 로직을 분기하는 데 사용되고 있는 것 같은데, 어떤 상황에 이런 구문을 사용하면 적절할지 궁금해지네요.
import lotto.domain.LottoResult | ||
import lotto.domain.WinningLine | ||
|
||
class LottoService( | ||
private val lineGenerator: LottoLineGenerator, | ||
) { | ||
fun buy(command: BuyLottoCommand): Lotto { | ||
val (payment, manualLotto) = 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.
사실 분해선언을 크게 권장드리지는 않습니다.
간편해보이지만, 다음과 같은 경우에 에러를 잡지 못해 문제가 생길수도 있거든요.
data class LottoCreateResponse(
val autoCount: Int,
val manualCount: Int,
)
val (manualCount, autoCount) = response
이처럼 같은 타입인 경우 잘못 된 순서로 값을 할당받을 경우 문제가 될 수 있거든요.
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.
제가 원래 노드 개발자였기에 비슷하게 변수명을 보고 알아서 매핑하는 줄 알았습니다.
아, 이래서 data class를 사용하면 자동으로 생기는 함수 중에 componentN()
라는 것이 있었군요.
수동으로 번호 입력 기능 외에 Rank 팩토리 메서드에 전달하는 인자를 객체로 감쌌습니다.