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

Step4 #1003

Open
wants to merge 8 commits into
base: gongwho
Choose a base branch
from
Open

Step4 #1003

wants to merge 8 commits into from

Conversation

gongwho
Copy link

@gongwho gongwho commented Dec 8, 2023

리팩토링
수동 로또 기능 구현

Copy link

@namjackson namjackson left a comment

Choose a reason for hiding this comment

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

안녕하세요 홍구님!
4단계 고생하셨습니다. 몇가지 코멘트 남겼으니, 확인해주세요!
변경사항 적용후, 다시 리뷰요청해주세요 😄

Comment on lines 54 to 58
val autoTickets = lottoShop.provideAutoTickets(ticketCount - manualLottoCount)
inputView.printPurchasedLotto(autoLottoTickets = autoTickets, manualLottoTickets = manualTickets)

return LottoTickets(manualTickets.lottoTicketList + autoTickets.lottoTicketList)
}

Choose a reason for hiding this comment

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

LottoSimulator내에서 계산하기보단,
LottoShop에게 위임하는 구조는 어덜까요?
manualTickets와 budget 만 부여하면, 내부적으로 알아서 로또를 생성해줄수 있지 않을까요?
(이미 생성된 LottoPurchaseOrder 객체를 활용해서 전달할수도 있을거같아요 )

override fun create(ticketCount: Int): LottoTickets {
val lottoTicketList = mutableListOf<LottoTicket>()
repeat(ticketCount) {
val lottoTicket = LottoTicket(readln().trim().split(",").map { it.toInt() }.map { LottoNumber(it) })

Choose a reason for hiding this comment

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

TicketGenerator는 domain 로직이라고 볼수도 있을거같아요,
생성로직과 View관련 기능은 분리해보면 어떨까요?

val manualLottoCount = inputView.getManualLottoCount()

val manualTickets = if (manualLottoCount != 0) {
inputView.printManualLottoInputString()

Choose a reason for hiding this comment

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

단순히 print를 실행하기보단,
함수에게 책임을주고, 행위를 위임해보면 어떨까요?

LottoSimulator가 하나씩 print에 관여하기보다, inputView에게 메세지를 전달해보아요!
inputView.getManualNumbers(manualLottoCount)

Copy link
Author

Choose a reason for hiding this comment

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

이 부분은 view 의 역할과 lotto shop 의 역할을 어디까지로 설정할 지 고민이 좀 되는 부분이네요 ㅎㅎ 일단 가장 적절해 보이는 방식으로 작성해 보겠습니다!

Comment on lines 5 to 6
class ExactTicketGenerator(private val lottoTickets: LottoTickets) : TicketGenerator {
override fun create(ticketCount: Int): LottoTickets = lottoTickets

Choose a reason for hiding this comment

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

lottoTickets의 사이즈와 ticketCount 가 일치하지 않는다면 테스트에 문제가 생길수도 있을거같아요

Comment on lines 5 to 7
object ActualLottoShop : LottoShop {
override fun provideAutoTickets(ticketCount: Int): LottoTickets = AutoTicketGenerator.create(ticketCount)
override fun provideManualTickets(ticketCount: Int): LottoTickets = ManualTicketGenerator.create(ticketCount)

Choose a reason for hiding this comment

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

AutoTicketGenerator, ManualTicketGenerator를 싱글턴으로 접근하는구조네요!
싱글턴 패턴은 자주 사용되는 패턴이지만, 잘못사용되면 객체간 결합도를 높여주게 되는 현상이 있어요

Suggested change
object ActualLottoShop : LottoShop {
override fun provideAutoTickets(ticketCount: Int): LottoTickets = AutoTicketGenerator.create(ticketCount)
override fun provideManualTickets(ticketCount: Int): LottoTickets = ManualTicketGenerator.create(ticketCount)
class ActualLottoShop(
autoTicketGenerator: TicketGenerator,
manualTicketGenerator: lTicketGenerator
) : LottoShop {
override fun provideAutoTickets(ticketCount: Int): LottoTickets = autoTicketGenerator.create(ticketCount)
override fun provideManualTickets(ticketCount: Int): LottoTickets = manualTicketGenerator.create(ticketCount)

위 처럼 바꾼 코드랑은 어떤점이 다를까요? 고민해보시면 좋을거같아요!

Copy link

@namjackson namjackson left a comment

Choose a reason for hiding this comment

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

안녕하세요 홍구님!
연말이라 리뷰가 많이 늦었네요 ㅠ,ㅠ!죄송합니다!
몇가지 추가적인 코멘트 남겼으니, 확인해주세요!
마지막 단계이니, 조금더 힘내보아요!

Comment on lines +51 to +56
val manualTickets = if (manualLottoCount != 0) {
lottoShop.provideManualTickets(inputView.getManualNumbers(manualLottoCount))
} else LottoTickets(listOf())

val autoTickets = lottoShop.provideAutoTickets(ticketCount, manualLottoCount)
inputView.printPurchasedLotto(autoLottoTickets = autoTickets, manualLottoTickets = manualTickets)

Choose a reason for hiding this comment

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

자동로또와 수동로또를 구매하는 역할도 LottoShop이 가지고 있어도 좋을거 같다는 생각이들어요!
단순히 provide해주는 객체가 아닌, manualNumbers와 budget 정보만으로 로또를 생성해줄수 있지않을까요?

LottoSimulator는 Controller역할로 View와의 상호작용에 대한 책임만 있지, 어떤 로또가 provide등의 책임은 LottoShop에게 모두 위임해보아요!


interface LottoShop {
fun provideAutoTickets(ticketCount: Int, preGeneratedTicketCount: Int): LottoTickets
fun provideManualTickets(manualNumbersList: List<List<Int>>): LottoTickets

Choose a reason for hiding this comment

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

List<List>가 어떤데이터인지 알기힘들진 않을까요?

Comment on lines +8 to +9
private val autoTicketGenerator: AutoTicketGenerator,
private val manualTicketGenerator: ManualTicketGenerator,

Choose a reason for hiding this comment

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

AutoTicketGenerator, ManualTicketGenerator
추상화를 제거하고, 하나의 object 클래스로 만들어주셨군요
TicketGenerator라는 추상화를 해보면 어떨까요?

ActualLottoShop 관련해서 Fake객체를 주입시켜, 구체적인 테스트도 작성할수 있을거같아요

Comment on lines +6 to +9
class MockLottoShop(private val manualTicketGenerator: ManualTicketGenerator) : LottoShop {
override fun provideAutoTickets(ticketCount: Int, preGeneratedTicketCount: Int): LottoTickets = LottoTickets(listOf())
override fun provideManualTickets(manualNumbersList: List<List<Int>>): LottoTickets =
manualTicketGenerator.create(manualNumbersList)

Choose a reason for hiding this comment

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

해당 Mock객체는 정상적인 동작을 한다고 보기는 힘들지 않을까요?
fake객체라면 원하는대로 활용할수있는구조로 작성해봐도 좋을거같아요

추상화를 한 이유와 Fake객체를 사용하는 이유가 무엇일지 고민해보면 어떨까요?
테스트가능한 구조를 구민보아요

Suggested change
class MockLottoShop(private val manualTicketGenerator: ManualTicketGenerator) : LottoShop {
override fun provideAutoTickets(ticketCount: Int, preGeneratedTicketCount: Int): LottoTickets = LottoTickets(listOf())
override fun provideManualTickets(manualNumbersList: List<List<Int>>): LottoTickets =
manualTicketGenerator.create(manualNumbersList)
class MockLottoShop(
private val autoTickets: LottoTickets,
private val manualTicket: LottoTickets,
) : LottoShop {
override fun provideAutoTickets(ticketCount: Int, preGeneratedTicketCount: Int): LottoTickets = autoTickets
override fun provideManualTickets(manualNumbersList: List<List<Int>>): LottoTickets = manualTicket

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.

3 participants