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

4단계 - 로또(수동) #1088

Open
wants to merge 18 commits into
base: giwankim
Choose a base branch
from
Open

4단계 - 로또(수동) #1088

wants to merge 18 commits into from

Conversation

giwankim
Copy link

수동으로 번호 입력 기능 외에 Rank 팩토리 메서드에 전달하는 인자를 객체로 감쌌습니다.

Copy link

@catsbi catsbi left a 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 {
Copy link

Choose a reason for hiding this comment

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

로또라는 도메인의 생성책임을 UI계층에서 수행하고 있는 것 같아요 🤔
UI계층에선 단순 값 입/출력만 책임지고 서비스 계층에서 도메인 계층에 대한 의존성을 가지는게 어떨까요?

Copy link
Author

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()
Copy link

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
}

Copy link
Author

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
Copy link

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

이처럼 같은 타입인 경우 잘못 된 순서로 값을 할당받을 경우 문제가 될 수 있거든요.

Copy link
Author

Choose a reason for hiding this comment

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

제가 원래 노드 개발자였기에 비슷하게 변수명을 보고 알아서 매핑하는 줄 알았습니다.

아, 이래서 data class를 사용하면 자동으로 생기는 함수 중에 componentN()라는 것이 있었군요.

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