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

πŸš€ 5단계 - μžλ™μ°¨ κ²½μ£Ό(λ¦¬νŒ©ν„°λ§) #1742

Open
wants to merge 11 commits into
base: aimbe
Choose a base branch
from
Open
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@

# μš”κ΅¬μ‚¬ν•­ 정리

## Step 4. μžλ™μ°¨ κ²½μ£Ό(우승자)
- [x] κ²Œμž„ 진행 μ‹œ μžλ™μ°¨μ˜ 이름을 λ°›λŠ”λ‹€.
- [x] RacingCar 객체에 이름을 λΆ€μ—¬ν•˜λŠ” κΈ°λŠ₯을 λ§Œλ“ λ‹€
- [x] 우승자λ₯Ό μ„ μ •ν•˜λŠ” μ±…μž„μ„ 가진 객체λ₯Ό μƒμ„±ν•œλ‹€
- [x] κ²Œμž„ μ™„λ£Œ ν›„ 우승자λ₯Ό 좜λ ₯ν•œλ‹€.
##πŸš€ 5단계 - μžλ™μ°¨ κ²½μ£Ό(λ¦¬νŒ©ν„°λ§)
- [x] 핡심 λΉ„μ§€λ‹ˆμŠ€ λ‘œμ§μ„ κ°€μ§€λŠ” 객체λ₯Ό domain νŒ¨ν‚€μ§€, UI κ΄€λ ¨ν•œ 객체λ₯Ό view νŒ¨ν‚€μ§€μ— κ΅¬ν˜„ν•œλ‹€.
- [x] λͺ¨λ“ˆ μ˜μ‘΄μ„±μ— λŒ€ν•΄ κ³ λ €ν•˜λ©° μ„€κ³„ν•œλ‹€.
- [x] 이전 리뷰 ν”Όλ“œλ°±μ„ λ°˜μ˜ν•˜μ—¬ κ΅¬ν˜„ν•œλ‹€.
6 changes: 4 additions & 2 deletions src/main/kotlin/misson/car/PlayGame.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package misson.car

import misson.car.domain.RacingCar
import misson.car.domain.RacingCars
import view.InputView
import view.ResultView.printRoundResult
import view.ResultView.printWinner
Expand All @@ -20,9 +22,9 @@ class PlayGame(private val racingCars: RacingCars, private val attempts: Int) {
fun play() {
repeat(attempts) {
racingCars.moveAll { (0..9).random() }
printRoundResult(racingCars.getPositionsWithName())
printRoundResult(racingCars)
Copy link
Member

Choose a reason for hiding this comment

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

λ§ˆμ§€λ§‰ 단계인 만큼 μ’€ 더 κ°œμ„ ν•΄λ³Ό 수 μžˆλŠ” μ—¬λŸ¬ 아이디어λ₯Ό μ œμ‹œν•˜κ³  μ‹Άμ–΄μš” πŸ™‚

ResultView ν˜ΈμΆœμ„ μ΅œλŒ€ν•œ 쀄여보면 μ–΄λ–¨κΉŒμš”?

μš°λ¦¬κ°€ ν”νžˆ μ›Ή ν”„λ‘œκ·Έλž¨μ—μ„œ μ„œλ²„μ™€ ν΄λΌμ΄μ–ΈνŠΈ 간에 μ†Œν†΅ν•˜λŠ”κ±Έ 생각해보면
μ„œλ²„μ™€ ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ‘œ μš”μ²­κ³Ό 응닡을 μ£Όκ³ λ°›λŠ” 과정은 λͺ¨λ‘ λΉ„μš©μž…λ‹ˆλ‹€. μ΄λŸ¬ν•œ λΉ„μš©μ„ μ€„μ΄λŠ” 것이 μ›Ή ν”„λ‘œκ·Έλž˜λ°μ—μ„œ μ€‘μš”ν•˜κ²Œ 여겨지기도 ν•©λ‹ˆλ‹€.

또 μ§€κΈˆμ€ λ‹¨μˆœν•œ μ½˜μ†” ν”„λ‘œκ·Έλž¨μ΄μ§€λ§Œ, λ‚˜μ€‘μ— λ·°κ°€ μ•ˆλ“œλ‘œμ΄λ“œ μ•±μœΌλ‘œ λ°”λ€λ‹€λ˜μ§€, μ›ΉνŽ˜μ΄μ§€ λ“±μœΌλ‘œ 바뀐닀고 ν•˜λ©΄ μ΄λŸ¬ν•œ 호좜이 λͺ¨λ‘ λΉ„μš©μ΄ λ©λ‹ˆλ‹€.

}

printWinner(racingCars.findWinners().representWinners())
printWinner(racingCars.findWinners())
}
}
32 changes: 0 additions & 32 deletions src/main/kotlin/misson/car/RacingCar.kt

This file was deleted.

22 changes: 0 additions & 22 deletions src/main/kotlin/misson/car/RacingCars.kt

This file was deleted.

11 changes: 0 additions & 11 deletions src/main/kotlin/misson/car/Winners.kt

This file was deleted.

13 changes: 13 additions & 0 deletions src/main/kotlin/misson/car/domain/CarPositionFormatter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package misson.car.domain

class CarPositionFormatter {
companion object {
fun formatCarPosition(car: RacingCar): String {
return "μžλ™μ°¨ ${car.name} : ${formatPosition(car.position)}"
Copy link
Member

Choose a reason for hiding this comment

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

λ·° μš”κ΅¬ 사항에 μ˜μ‘΄ν•˜κ³  μžˆλŠ” 이 둜직이 domain νŒ¨ν‚€μ§€μ— μžˆλŠ” 것이 μ μ ˆν• κΉŒμš”?

MVC νŒ¨ν„΄ 기반으둜 λ¦¬νŒ©ν† λ§ν•΄ view νŒ¨ν‚€μ§€μ˜ 객체가 domain νŒ¨ν‚€μ§€ 객체에 μ˜μ‘΄ν•  수 μžˆμ§€λ§Œ, domain νŒ¨ν‚€μ§€μ˜ κ°μ²΄λŠ” view νŒ¨ν‚€μ§€ 객체에 μ˜μ‘΄ν•˜μ§€ μ•Šλ„λ‘ κ΅¬ν˜„ν•œλ‹€.

Copy link
Author

Choose a reason for hiding this comment

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

μ•„λ¬΄λž˜λ„ domain에 있긴 μ•ˆλ§žκ³  view에 μžˆκΈ°μ—λ„ μ• λ§€ν•΄μ„œ util νŒ¨ν‚€μ§€ 생성 ν›„ μ΄λ™μ‹œμΌ°μŠ΅λ‹ˆλ‹€! γ…Žγ…Ž

}

fun formatPosition(position: Int): String {
return "-".repeat(position)
}
}
}
19 changes: 19 additions & 0 deletions src/main/kotlin/misson/car/domain/RacingCar.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package misson.car.domain

// μ½”ν‹€λ¦° λ¬Έλ²•μ—μ„œ position을 private으둜 ν•˜μ§€ μ•Šμ•„λ„ λ‚΄λΆ€μ μœΌλ‘œλŠ” getter둜 μ ‘κ·Ό
class RacingCar(val name: String = "뢕뢕이", var position: Int = 0) {
Copy link
Member

Choose a reason for hiding this comment

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

ν˜„μž¬λŠ” position이 privateν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μ™ΈλΆ€μ—μ„œ position 값을 λ§ˆμŒλŒ€λ‘œ μˆ˜μ •ν•  수 μžˆμ–΄μš”.

val car = RacingCar()
car.position = 123

μ–΄λ–»κ²Œ κ°œμ„ ν•΄λ³Ό 수 μžˆμ„κΉŒμš”?
https://kotlinlang.org/docs/properties.html#getters-and-setters

Copy link
Member

Choose a reason for hiding this comment

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

"뢕뢕이"λŠ” λ„ˆλ¬΄ κ·€μ—½μ§€λ§Œ(γ…‹γ…‹γ…‹) ν…ŒμŠ€νŠΈ νŽΈμ˜μ„±μ„ μœ„ν•΄ λ§Œλ“€μ–΄μ§„ κ°’μ΄λ―€λ‘œ ν”„λ‘œλ•μ…˜ μ½”λ“œμ— μΆ”κ°€λ˜κΈ°μ—λŠ” μ ν•©ν•˜μ§€ μ•Šμ€ 것 κ°™μ•„μš”.

init {
validateName(name)
}

private fun validateName(name: String) {
require(name.length <= 5) { "이름은 5자 μ΄ν•˜λ§Œ κ°€λŠ₯ν•©λ‹ˆλ‹€." }
require(name.isNotBlank()) { "이름은 곡백일 수 μ—†μŠ΅λ‹ˆλ‹€." }
}

fun move(randomNumberGenerator: () -> Int) {
if (randomNumberGenerator() >= 4) {
position++
}
}
}
14 changes: 14 additions & 0 deletions src/main/kotlin/misson/car/domain/RacingCars.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package misson.car.domain

class RacingCars(val cars: List<RacingCar>) {
fun moveAll(randomNumberGenerator: () -> Int) {
cars.forEach { it.move(randomNumberGenerator) }
}

// 우승자λ₯Ό μ°ΎλŠ” μ±…μž„ 이동
fun findWinners(): Winners {
val maxPosition = cars.maxOf { it.position }
val winners = cars.filter { it.position == maxPosition }
return Winners(winners)
}
}
8 changes: 8 additions & 0 deletions src/main/kotlin/misson/car/domain/Winners.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package misson.car.domain

@JvmInline
value class Winners(private val winners: List<RacingCar>) {
fun getNames(): List<String> {
return winners.map { it.name }
}
}
15 changes: 11 additions & 4 deletions src/main/kotlin/view/ResultView.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package view

import misson.car.domain.CarPositionFormatter
import misson.car.domain.RacingCars
import misson.car.domain.Winners

object ResultView {
fun printRoundResult(positions: List<String>) {
positions.forEach { println(it) }
fun printRoundResult(racingCars: RacingCars) {
racingCars.cars
.map { CarPositionFormatter.formatCarPosition(it) }
.forEach { println(it) }
println()
}

fun printWinner(winners: String) {
println("μ΅œμ’… μš°μŠΉμžλŠ” $winners μž…λ‹ˆλ‹€.")
fun printWinner(winners: Winners) {
val winnerNames = winners.getNames().joinToString(", ")
println("μ΅œμ’… μš°μŠΉμžλŠ” $winnerNames μž…λ‹ˆλ‹€.")
}
}
12 changes: 5 additions & 7 deletions src/test/kotlin/misson/RacingCarTest.kt
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
package misson

import misson.car.RacingCar
import misson.car.domain.RacingCar
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows

class RacingCarTest {
@Test
fun `이름이 5자λ₯Ό μ΄ˆκ³Όν•˜λ©΄ μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€`() {
assertThrows<IllegalArgumentException> {
RacingCar("1234567")
}
assertThat(assertThrows<IllegalArgumentException> { RacingCar("1234567") }.message)
Copy link
Member

Choose a reason for hiding this comment

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

RacingCar의 position 값을 μ΄ˆκΈ°ν™”ν•œλ‹€λŠ” 것을 λͺ…μ‹œμ μœΌλ‘œ λ“œλŸ¬λ‚΄κΈ° μœ„ν•΄ named argumentsλ₯Ό ν™œμš©ν•˜μ‹œλ©΄ μ–΄λ–¨κΉŒμš”?

RacingCar(position = "1234567")

이 외에도 named argumentsλ₯Ό ν™œμš©ν•  곳이 μžˆλ‚˜μš”? ν”„λ‘œμ νŠΈ μ „λ°˜μ μœΌλ‘œ 적용될 수 μžˆλŠ” 변경사항인 것 κ°™μ•„μš”!

.isEqualTo("이름은 5자 μ΄ν•˜λ§Œ κ°€λŠ₯ν•©λ‹ˆλ‹€.")
}

@Test
fun `이름이 빈 λ¬Έμžμ—΄μ΄λ©΄ μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€`() {
assertThrows<IllegalArgumentException> {
RacingCar("")
}
assertThat(assertThrows<IllegalArgumentException> { RacingCar("") }.message)
.isEqualTo("이름은 곡백일 수 μ—†μŠ΅λ‹ˆλ‹€.")
}

@Test
Expand Down
39 changes: 31 additions & 8 deletions src/test/kotlin/misson/RacingCarsTest.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
package misson

import misson.car.RacingCar
import misson.car.RacingCars
import misson.car.domain.RacingCar
import misson.car.domain.RacingCars
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.CsvSource

class RacingCarsTest {
@Test
fun `μžλ™μ°¨ 그룹을 ν•œλ²ˆμ— μ΄λ™μ‹œν‚¨λ‹€`() {
val racingCars = RacingCars(List(3) { RacingCar() })
racingCars.moveAll { 4 }

val positions = racingCars.getPositions()
assertThat(positions).containsExactly("-", "-", "-")
racingCars.cars.forEach {
assertThat(it.position).isEqualTo(1)
}
}

@Test
fun `μžλ™μ°¨ 그룹을 값이 4μ΄ν•˜ 이면 μ΄λ™ν•˜μ§€ μ•ŠλŠ”λ‹€`() {
val racingCars = RacingCars(List(3) { RacingCar() })
racingCars.moveAll { 3 }

val positions = racingCars.getPositions()
assertThat(positions).containsExactly("", "", "")
racingCars.cars.forEach {
assertThat(it.position).isEqualTo(1)
}
}

@Test
Expand All @@ -36,7 +40,7 @@ class RacingCarsTest {
)

val winners = racingCars.findWinners()
assertThat(winners.representWinners()).isEqualTo("car1")
assertThat(winners.getNames()).containsExactly("car1")
}

@Test
Expand All @@ -51,6 +55,25 @@ class RacingCarsTest {
)

val winners = racingCars.findWinners()
assertThat(winners.representWinners()).isEqualTo("car1, car2")
assertThat(winners.getNames()).containsExactly("car1", "car2")
}

@ParameterizedTest
@CsvSource(
"4, 1",
"5, 1",
"3, 0",
"2, 0",
)
fun `Param 값에 따라 μžλ™μ°¨ 그룹이 μ΄λ™ν•œλ‹€`(
Copy link
Member

Choose a reason for hiding this comment

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

ν…ŒμŠ€νŠΈλͺ…을 톡해 μ–΄λ–€ 것을 ν…ŒμŠ€νŠΈν•˜κ³ μž ν•˜λŠ” 것이 μ œλŒ€λ‘œ λ“œλŸ¬λ‚˜μ§€ μ•ŠλŠ” 것 κ°™μ•„μš”. ν…ŒμŠ€νŠΈλͺ…을 μž‘μ„±ν•˜μ‹€ λ•Œμ—λŠ”

  1. κ²€μ¦ν•˜κ³ μž ν•˜λŠ” λ‘œμ§μ„ λͺ…ν™•ν•˜κ²Œ μ •ν•˜κ³  (검증이 ν•„μš”ν•œ 둜직이 두 개 이상이면 ν•„μš”μ— 따라 또 λ‹€λ₯Έ ν•¨μˆ˜λ‘œ λΆ„ν• ν•œλ‹€)
  2. 그것을 ν•¨μˆ˜λͺ…μœΌλ‘œ λ“œλŸ¬λ‚΄λ³΄λ©΄ μ–΄λ–¨κΉŒμš”?

μ΄μƒμ μœΌλ‘œλŠ” κΈ°λŠ₯ μš”κ΅¬ μ‚¬ν•­μœΌλ‘œ μ •λ¦¬ν•˜μ‹  λ¬Έμ„œμ˜ μ‹œλ‚˜λ¦¬μ˜€κ°€ κ·ΈλŒ€λ‘œ ν…ŒμŠ€νŠΈ μ‹œλ‚˜λ¦¬μ˜€λ‘œλ„ 이어지면 μ’‹μŠ΅λ‹ˆλ‹€ πŸ™‚

randomValue: Int,
expectedPosition: Int,
) {
val racingCars = RacingCars(List(3) { RacingCar() })
racingCars.moveAll { randomValue }

racingCars.cars.forEach { car ->
assertThat(car.position).isEqualTo(expectedPosition)
}
}
}
34 changes: 34 additions & 0 deletions src/test/kotlin/misson/car/CarPositionFormatterTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package misson.car

import misson.car.domain.CarPositionFormatter
import misson.car.domain.RacingCar
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.CsvSource

class CarPositionFormatterTest {
@Test
fun `μžλ™μ°¨ μœ„μΉ˜λ§ˆλ‹€ -λ₯Ό , μ•žμ— μžλ™μ°¨ 이름을 뢙인닀`() {
val car = RacingCar("car1", 3)
val result = CarPositionFormatter.formatCarPosition(car)

assertThat(result).isEqualTo("μžλ™μ°¨ car1 : ---")
}

@ParameterizedTest
@CsvSource(
"0, ''",
"1, '-'",
"3, '---'",
"5, '-----'",
)
fun `positionλ§ˆλ‹€ -λ₯Ό 뢙인닀`(
Copy link
Member

Choose a reason for hiding this comment

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

λ‹€μŒ μš”κ΅¬ 사항을 λ‹€μ‹œ ν•œ 번 고렀해보면 μ–΄λ–¨κΉŒμš”~?

λͺ¨λ“  λ‘œμ§μ— λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό κ΅¬ν˜„ν•œλ‹€. 단, UI(System.out, System.in) λ‘œμ§μ€ μ œμ™Έ
핡심 λ‘œμ§μ„ κ΅¬ν˜„ν•˜λŠ” μ½”λ“œμ™€ UIλ₯Ό λ‹΄λ‹Ήν•˜λŠ” λ‘œμ§μ„ κ΅¬λΆ„ν•œλ‹€.
UI λ‘œμ§μ„ InputView, ResultView와 같은 클래슀λ₯Ό μΆ”κ°€ν•΄ λΆ„λ¦¬ν•œλ‹€.

position: Int,
expected: String,
) {
val result = CarPositionFormatter.formatPosition(position)

assertThat(result).isEqualTo(expected)
}
}
4 changes: 3 additions & 1 deletion src/test/kotlin/misson/car/WinnerTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package misson.car

import misson.car.domain.RacingCar
import misson.car.domain.Winners
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

Expand All @@ -14,6 +16,6 @@ class WinnerTest {
),
)

assertThat(winners.representWinners()).isEqualTo("car1, car2")
assertThat(winners.getNames()).containsExactly("car1", "car2")
}
}