-
Notifications
You must be signed in to change notification settings - Fork 323
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
Step4 - 로또(수동) ver2 #985
base: oyj7677
Are you sure you want to change the base?
Step4 - 로또(수동) ver2 #985
Changes from all commits
d008b10
dffd018
2273de6
e28951c
8dfcb45
9b5f054
a0698e5
4578453
787b65d
8532e66
6d0bb74
08c5846
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,18 +14,10 @@ enum class LottoRanking(val matchingNumberCnt: Int, val price: Int) : Prize { | |
|
||
companion object { | ||
fun findLottoRanking(matchingNumberCnt: Int, hasBonusNumber: Boolean): LottoRanking { | ||
return if (matchingNumberCnt == SecondPlace.matchingNumberCnt) { | ||
determineRankingWithBonusNumber(hasBonusNumber) | ||
} else { | ||
LottoRanking.values().find { it.matchingNumberCnt == matchingNumberCnt } ?: None | ||
} | ||
} | ||
|
||
private fun determineRankingWithBonusNumber(isContainBonusNumber: Boolean): LottoRanking { | ||
return if (isContainBonusNumber) { | ||
return if (matchingNumberCnt == SecondPlace.matchingNumberCnt && hasBonusNumber) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분이 많이 헷갈리시는것 같아요. 이쪽에서 제가 드렸던 피드백의 핵심은 상위 객체(LottoRanking)는 하위 객체가 무엇으로 결정되는지에 대해서 상세 조건을 알고싶어하지 않아야 한다는거죠. 반면, 상위객체에선 전달받은 객체만 하위 객체에 전달해서 맞는지에 대한 유무만 판단하도록한다면 로직이 추가되던 값이 바뀌던 뭐가 어떻게 되던 로직이 바뀔일이 없겠죠. return values().find { it.support(matchingNumberCnt, hasBonusNumber) } ?: NONE 아 그리고 열거타입의 네이밍 컨벤션은 대문자 스네이크 케이스입니다 ㅎㅎ |
||
SecondPlace | ||
} else { | ||
ThirdPlace | ||
LottoRanking.values().find { it.matchingNumberCnt == matchingNumberCnt } ?: None | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package lotto.data | ||
|
||
class NumberCombination(val numberCombination: List<Int>) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 오버 엔지니어링으로 보이네요 🤔 |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -7,7 +7,7 @@ data class WinningLotto(val lotto: Lotto, val bonusNumber: LottoNumber) { | |||||
} | ||||||
|
||||||
fun countMatchingNumbers(lotto: Lotto): Int { | ||||||
return this.lotto.selectNumbers.intersect(lotto.selectNumbers).size | ||||||
return this.lotto.matching(lotto) | ||||||
} | ||||||
|
||||||
fun hasBonusNumber(lotto: Lotto): Boolean { | ||||||
|
@@ -19,6 +19,14 @@ data class WinningLotto(val lotto: Lotto, val bonusNumber: LottoNumber) { | |||||
} | ||||||
|
||||||
private fun validateDuplicationBonusNumber() { | ||||||
require(!lotto.selectNumbers.contains(bonusNumber)) { "당첨 번호 구성과 보너스 번호가 중복됩니다." } | ||||||
require(!lotto.selectNumbers.contains(bonusNumber)) { ERR_MSG_DUPLICATION_BONUS_NUMBER } | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 좀 더 객체 지향적으로 설계가 되었다면 다음과 같이 작성될 수 있을꺼에요.
Suggested change
|
||||||
} | ||||||
|
||||||
private fun Lotto.matching(lotto: Lotto): Int { | ||||||
return this.selectNumbers.intersect(lotto.selectNumbers).size | ||||||
} | ||||||
|
||||||
companion object { | ||||||
private const val ERR_MSG_DUPLICATION_BONUS_NUMBER = "당첨 번호 구성과 보너스 번호가 중복됩니다." | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,24 @@ | ||
package lotto.domain | ||
|
||
import lotto.data.LottoRanking | ||
import java.util.EnumMap | ||
|
||
object LottoCalculator { | ||
|
||
private const val GAME_COST = 1000 | ||
private const val ERR_MSG_OVER_MANUAL_GAME_TIMES = "수동 게임 횟수가 총 게임 횟수를 초과하였습니다." | ||
|
||
fun calculateWinningRate(cash: Int, winningStatus: Map<LottoRanking, Int>): Float { | ||
fun calculateWinningRate(cash: Int, winningStatus: EnumMap<LottoRanking, Int>): Float { | ||
val totalPrice = winningStatus.toList().sumOf { it.first.findPrize(it) } | ||
|
||
return totalPrice / cash.toFloat() | ||
} | ||
|
||
fun getTimes(cash: Int): Int { | ||
return cash / GAME_COST | ||
fun getTimes(cash: Int, gameCost: Int): Int { | ||
return cash / gameCost | ||
} | ||
|
||
fun getAutoTimes(totalTimes: Int, manualGameTimes: Int): Int { | ||
require(totalTimes >= manualGameTimes) { ERR_MSG_OVER_MANUAL_GAME_TIMES } | ||
return totalTimes - manualGameTimes | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,18 +3,32 @@ package lotto.service | |
import lotto.data.Lotto | ||
import lotto.data.LottoNumber | ||
import lotto.data.LottoRanking | ||
import lotto.data.NumberCombination | ||
import lotto.data.WinningLotto | ||
import lotto.domain.LottoCalculator | ||
import lotto.domain.LottoMachine | ||
import lotto.domain.RandomLogicInterface | ||
import lotto.domain.WinningDomain | ||
import java.util.EnumMap | ||
|
||
class LottoGame(private val randomLogic: RandomLogicInterface) { | ||
class LottoGame(private val randomLogic: RandomLogicInterface, private val gameCost: Int = DEFAULT_COST) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. private val gameCost: Int = DEFAULT_COST 해당 값은 stateful한 설계로 보이는데 서비스는 stateless를 지향해서 적절한 선언은 아닙니다 ㅎ |
||
|
||
fun buyLotto(cash: Int): List<Lotto> { | ||
val times = LottoCalculator.getTimes(cash) | ||
fun getGameTimes(cash: Int): Int { | ||
return LottoCalculator.getTimes(cash, gameCost) | ||
} | ||
|
||
fun buyLotto(gameTimes: Int, numberCombinationList: List<NumberCombination> = emptyList()): List<Lotto> { | ||
val autoTimes = LottoCalculator.getAutoTimes(gameTimes, numberCombinationList.size) | ||
val lottoList = mutableListOf<Lotto>() | ||
|
||
lottoList.addAll(numberCombinationList.map { createManualLotto(it) }) | ||
lottoList.addAll(createLotto(autoTimes)) | ||
|
||
return lottoList | ||
} | ||
|
||
return createLotto(times) | ||
fun getWinningStats(winningLotto: WinningLotto, purchaseLottoList: List<Lotto>): EnumMap<LottoRanking, Int> { | ||
return WinningDomain.checkWinningResult(winningLotto, purchaseLottoList) | ||
} | ||
|
||
private fun createLotto(times: Int): List<Lotto> { | ||
|
@@ -26,8 +40,12 @@ class LottoGame(private val randomLogic: RandomLogicInterface) { | |
return lottoList | ||
} | ||
|
||
fun getWinningStats(winningLotto: WinningLotto, purchaseLottoList: List<Lotto>): Map<LottoRanking, Int> { | ||
private fun createManualLotto(numberCombination: NumberCombination): Lotto { | ||
val lottoNumberCombination = LottoNumber.createLottoNumbers(numberCombination) | ||
return LottoMachine.createSelectLotto(lottoNumberCombination) | ||
} | ||
|
||
return WinningDomain.checkWinningResult(winningLotto, purchaseLottoList) | ||
companion object { | ||
private const val DEFAULT_COST = 1000 | ||
} | ||
} |
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.
좀 더 심화로 넘어간 키워드를 드리자면, 현재 Main은 컨트롤러와 UI가 섞여있다고 볼 수 있습니다.
그러다보니 설계를 하다보면 뭔가 섞이는 것 같다는 애매한 느낌을 받을 수 있습니다.
(저는 이 부분에서 많은 고민을 했었죠. )
웹서비스를 보면 프론트 영역에서 ajax로 요청해야하는 부분도 컨트롤러에 있는 것 같고, 응용SW로 보면 CLI의 영역을 컨트롤러가 같이 가지고 있는 것으로 보이죠.
그래서 이를 한번 더 분리해서 사용자와 입출력을 담당하는 cli계층과 말 그대로 하나의 요청에 대한 응답을 해주는 컨트롤러 영역을 분리해보는것도 좋은 경험이 될 것 같아요,.