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

[step5] 자동차 경주(리팩터링) #1752

Open
wants to merge 6 commits into
base: saerang
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 8 additions & 22 deletions src/main/kotlin/racingcar/RacingCar.kt
Original file line number Diff line number Diff line change
@@ -1,33 +1,19 @@
package racingcar

import racingcar.domain.Cars
import racingcar.domain.Winners
import racingcar.util.RandomNumberGenerator
import racingcar.view.InputView
import racingcar.view.OutputView

fun main() {
println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).")
val usernames: String = readln()
println("시도할 횟수는 몇 회인가요?")
val round: Int = readln().toInt()
val usernames = InputView.carNames()
val round = InputView.roundCount()

val cars = Cars.usernames(usernames)
val cars = Cars.from(usernames)
repeat(round) {
cars.race(RandomNumberGenerator())
gameResult(cars)
cars.race(RandomNumberGenerator)
OutputView.gameResult(cars)
}

gameWinner(cars)
}

private fun gameResult(cars: Cars) {
cars.cars().forEach {
println(it.username() + " : " + it.position().viewPosition())
}
println()
}

private fun gameWinner(cars: Cars) {
val winners = Winners(cars)
val winnersName = winners.getWinnerNames().joinToString(",")
println(winnersName + "가 최종 우승했습니다.")
OutputView.gameWinner(cars)
}
10 changes: 1 addition & 9 deletions src/main/kotlin/racingcar/domain/Car.kt
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
package racingcar.domain

class Car(private var position: Position, private val username: String) {
class Car(var position: Position, val username: String) {
Copy link

Choose a reason for hiding this comment

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

position의 setter도 public으로 열리게된 것 같아요!

https://ksabs.tistory.com/247

위 글을 읽어보고 프로퍼티의 setter는 private으로 막아보면 어떨까요?

fun move(number: Int) {
this.position = position.move(number)
}

fun position(): Position {
return this.position
}

fun username(): String {
return this.username
}

companion object {
fun init(username: String): Car {
return Car(Position.init(), username)
Expand Down
14 changes: 3 additions & 11 deletions src/main/kotlin/racingcar/domain/Cars.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import racingcar.util.NumberGenerator

private const val USERNAME_SPLIT_CONDITION = ","

class Cars(private val cars: List<Car>) {
class Cars(val cars: List<Car>) {
fun race(generator: NumberGenerator) {
for (car in cars) {
val number = generator.generate()
Expand All @@ -13,19 +13,11 @@ class Cars(private val cars: List<Car>) {
}

fun positions(): List<Position> {
val positions: MutableList<Position> = ArrayList()
for (car in cars) {
positions.add(car.position())
}
return positions
}

fun cars(): List<Car> {
return cars
return cars.map { it.position }
}

companion object {
fun usernames(usernames: String): Cars {
fun from(usernames: String): Cars {
return Cars(usernames.split(USERNAME_SPLIT_CONDITION).map { username -> Car.init(username) })
}
}
Expand Down
6 changes: 1 addition & 5 deletions src/main/kotlin/racingcar/domain/Position.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ private const val MOVE_POSITION_CONDITION = 4
private const val POSITION_VIEW = "-"

@JvmInline
value class Position(private val position: Int) {
value class Position(val position: Int) {
fun move(number: Int): Position {
if (number < MOVE_START_NUMBER || number > MOVE_END_NUMBER) {
throw IllegalArgumentException("Only numbers between 0 and 9 can be entered. input number:$number")
Expand All @@ -27,10 +27,6 @@ value class Position(private val position: Int) {
return POSITION_VIEW.repeat(max(DEFAULT_NUMBER, position))
}

fun position(): Int {
return this.position
}

companion object {
fun init(): Position {
return Position(DEFAULT_NUMBER)
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/racingcar/domain/Winners.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ class Winners(cars: Cars) {

init {
val highestPosition: Position =
cars.positions().maxByOrNull { it.position() } ?: Position(0)
cars.positions().maxByOrNull { it.position } ?: Position.init()
winners =
cars.cars()
.filter { it.position() == highestPosition }
cars.cars
.filter { it.position == highestPosition }
.map { it }
}

fun getWinnerNames(): List<String> {
return winners.map { it.username() }
return winners.map { it.username }
}
}
2 changes: 1 addition & 1 deletion src/main/kotlin/racingcar/util/RandomNumberGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import kotlin.random.Random

private const val RANDOM_MAX_NUMBER = 10

class RandomNumberGenerator : NumberGenerator {
object RandomNumberGenerator : NumberGenerator {
override fun generate(): Int {
return Random.nextInt(RANDOM_MAX_NUMBER)
}
Expand Down
13 changes: 13 additions & 0 deletions src/main/kotlin/racingcar/view/InputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package racingcar.view

object InputView {
fun carNames(): String {
Copy link

Choose a reason for hiding this comment

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

함수명은 동사형으로 작성해주면 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

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

enterCarNames 나 setCarNames 등 할 수 있긴한데, Class 자체가 Input을 하는애들이기 때문에 InputView.carNames() 에 의미가 어느정도 있다고 생각을 하는데. 어떻게 생각하시나요?!

println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분).")
return readln()
}

fun roundCount(): Int {
println("시도할 횟수는 몇 회인가요?")
return readln().toIntOrNull() ?: throw IllegalArgumentException("숫자를 입력해 주세요.")
}
}
19 changes: 19 additions & 0 deletions src/main/kotlin/racingcar/view/OutputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package racingcar.view

import racingcar.domain.Cars
import racingcar.domain.Winners

object OutputView {
Copy link

Choose a reason for hiding this comment

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

outView에 Car객체를 리턴하게 되면 View레벨에서 Car 객체 안에있는 함수를 실행할 수 있을 것 같아요 :)
DTO를 활용해보면 어떨까요?

fun gameResult(cars: Cars) {
cars.cars.forEach {
println(it.username + " : " + it.position.viewPosition())
}
println()
}

fun gameWinner(cars: Cars) {
val winners = Winners(cars)
Copy link

Choose a reason for hiding this comment

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

Winner를 구하는게 View의 역할일까요? Cars에 있어도 좋을 것 같아요 :)

val winnersName = winners.getWinnerNames().joinToString(",")
println(winnersName + "가 최종 우승했습니다.")
Copy link

Choose a reason for hiding this comment

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

kotlin의 String templates을 활용해보면 어떨까요?

}
}
4 changes: 2 additions & 2 deletions src/test/kotlin/racingcar/domain/CarTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class CarTest {

car.move(number)

assertThat(car.position()).isEqualTo(Position(1))
assertThat(car.position).isEqualTo(Position(1))
}

@ParameterizedTest
Expand All @@ -23,7 +23,7 @@ class CarTest {

car.move(number)

assertThat(car.position()).isEqualTo(Position(0))
assertThat(car.position).isEqualTo(Position(0))
}

@ParameterizedTest
Expand Down
6 changes: 3 additions & 3 deletions src/test/kotlin/racingcar/domain/CarsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import racingcar.TestNumberGenerator
class CarsTest {
@Test
fun `자동차들을 생성한다`() {
val cars = Cars.usernames("pobi,crong,honux")
val cars = Cars.from("pobi,crong,honux")
assertThat(cars).isNotNull()
}

@Test
fun `자동차 경주 시 4이상의 숫자는 전진한다`() {
val cars = Cars.usernames("pobi,crong,honux")
val cars = Cars.from("pobi,crong,honux")

cars.race(TestNumberGenerator(4))

Expand All @@ -22,7 +22,7 @@ class CarsTest {

@Test
fun `자동차 경주 시작 시 4미만의 숫자는 멈춰 있는다`() {
val cars = Cars.usernames("pobi,crong,honux")
val cars = Cars.from("pobi,crong,honux")

cars.race(TestNumberGenerator(3))

Expand Down