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 자동차 경주 리팩토링 #948

Open
wants to merge 5 commits into
base: youngsuk-kim
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
14 changes: 0 additions & 14 deletions src/main/kotlin/src/racingcar/Car.kt

This file was deleted.

17 changes: 0 additions & 17 deletions src/main/kotlin/src/racingcar/CarService.kt

This file was deleted.

17 changes: 0 additions & 17 deletions src/main/kotlin/src/racingcar/InputView.kt

This file was deleted.

5 changes: 4 additions & 1 deletion src/main/kotlin/src/racingcar/RacingCarGame.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package src.racingcar

import src.racingcar.view.InputView
import src.racingcar.view.ResultView

object RacingCarGame {
fun startGame() {
val inputValue = InputView.executeInputScreen()
CarService().execute(inputValue.tryCount, inputValue.carNumber)
ResultView.printRacingCarGameResult(inputValue.tryCount, inputValue.carNames)
}
}

Expand Down
10 changes: 0 additions & 10 deletions src/main/kotlin/src/racingcar/RamdomUtil.kt

This file was deleted.

7 changes: 0 additions & 7 deletions src/main/kotlin/src/racingcar/ResultView.kt

This file was deleted.

40 changes: 40 additions & 0 deletions src/main/kotlin/src/racingcar/description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
경주할 자동차 이름을 추출 하는 기능.

Choose a reason for hiding this comment

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

description.md 파일의 위치는 src가 아닌 다른 디렉터리에 있어야하지 않을까요?


경주할 자동차 대수를 추출 하는 기능.

경주 자동차 이름 별로 "-" 가 나오도록 구현.

어떤 자동차가 최종 우승 하였는지 알아내는 기능

모든 로직에 단위 테스트를 구현한다.

단, UI(System.out, System.in) 로직은 제외
핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.

UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다.

indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다.

예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.

힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.

함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다.

함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다.

기능을 구현하기 전에 README.md 파일에 구현할 기능 목록을 정리해 추가한다.

git의 commit 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가한다.

사용자가 입력한 이름의 숫자 만큼 자동차 대수를 생성한다.

자동차는 자동차 이름과 위치 정보를 가지는 Car 객체를 추가해 구현한다.

각 자동차에 이름을 부여할 수 있다. 자동차 이름은 5자를 초과할 수 없다.

전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다.

자동차 이름은 쉼표(,)를 기준으로 구분한다.

자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다.
22 changes: 22 additions & 0 deletions src/main/kotlin/src/racingcar/domain/Car.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package src.racingcar.domain

open class Car(

Choose a reason for hiding this comment

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

open class를 사용하신 이유가 있을까요?

val name: String,
moveCount: Int = 0
) {

var moveCount: Int = moveCount
protected set
Comment on lines +8 to +9

Choose a reason for hiding this comment

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

Suggested change
var moveCount: Int = moveCount
protected set
var moveCount: Int = moveCount
private set

kotlin에서 protected와 private의 차이는 무엇일까요~?


open fun move(carMoveNumber: Int = (MOVE_START_POINT..MOVE_END_POINT).random()): Int {
if (CAR_MOVE_CONDITION_NUMBER <= carMoveNumber) moveCount++

return moveCount
}
Comment on lines +11 to +15

Choose a reason for hiding this comment

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

default arguments를 사용하셨군요! 👍


companion object {
private const val CAR_MOVE_CONDITION_NUMBER = 4
private const val MOVE_START_POINT = 0
private const val MOVE_END_POINT = 9
}
}
21 changes: 21 additions & 0 deletions src/main/kotlin/src/racingcar/domain/Race.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package src.racingcar.domain

class Race(cars: List<Car>) {
var cars: List<Car> = cars
private set

fun start(): List<Car> {
cars.forEach { it.move() }

return cars
}
Comment on lines +7 to +11

Choose a reason for hiding this comment

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

도메인 클래스에 대한 테스트는 모두 해야한다고 생각해요! race에 결과에 대한 테스트는 어떻게 해야 할까요?

참고 문서 입니다!


companion object {
fun create(carNames: List<String>): Race {
val cars = buildList {
carNames.forEach { this.add(Car(it)) }
}
return Race(cars)
}
}
}
10 changes: 10 additions & 0 deletions src/main/kotlin/src/racingcar/domain/Winner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package src.racingcar.domain

class Winner(
private val racingCars: List<Car>
) {
fun findWinners(): List<Car> {
val max = racingCars.maxOf { it.moveCount }
return racingCars.filter { car -> car.moveCount >= max }

Choose a reason for hiding this comment

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

Suggested change
return racingCars.filter { car -> car.moveCount >= max }
return racingCars.filter { car -> car.moveCount == max }

== 비교로도 충분하지 않을까요?

}
}
5 changes: 5 additions & 0 deletions src/main/kotlin/src/racingcar/utils/Parser.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package src.racingcar.utils

fun parseComma(input: String): List<String> {
return input.split(",")
}
17 changes: 17 additions & 0 deletions src/main/kotlin/src/racingcar/view/InputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package src.racingcar.view

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

return RacingCarGameInput(carNames, tryCount)
}
}

data class RacingCarGameInput(
val carNames: String,
val tryCount: Int
)
32 changes: 32 additions & 0 deletions src/main/kotlin/src/racingcar/view/ResultView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package src.racingcar.view

import src.racingcar.domain.Car
import src.racingcar.domain.Race
import src.racingcar.domain.Winner
import src.racingcar.utils.parseComma

object ResultView {
fun printRacingCarGameResult(tryCount: Int, carNames: String) {
val race = Race.create(parseComma(carNames))
repeat(tryCount) {
val raceCars = race.start()
printRacing(raceCars)
}

printWinner(Winner(race.cars).findWinners())
}

private fun printRacing(raceCars: List<Car>) {
for (raceCar in raceCars) {
print(raceCar.name)
print(" : ")
println("-".repeat(raceCar.moveCount))
}
println()
}

private fun printWinner(findWinners: List<Car>) {
print(findWinners.joinToString { car -> car.name })
print("가 최종 우승 했습니다.")
}
}
20 changes: 16 additions & 4 deletions src/test/kotlin/src/racingcar/CarTest.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
package src.racingcar

import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import src.racingcar.domain.Car

class CarTest {

@Test
fun `자동차는 한번에 두번 이상 움직일 수 없다`() {
val moveCount = Car().move()
fun `랜덤 값이 4 이상이면 차가 움직인다`() {
val moveCount = Car("testName").move(4)
assertThat(moveCount).isEqualTo(1)
}

Assertions.assertThat(moveCount).isLessThan(2)
@Test
fun `랜덤 값이 4 미만이면 차가 움직이지 않는다`() {
val moveCount = Car("testName").move(3)
assertThat(moveCount).isEqualTo(0)
}

@Test
fun `차의 이름을 지정할 수 있다`() {
val car = Car("testName")
assertThat(car.name).isEqualTo("testName")
}
}
25 changes: 25 additions & 0 deletions src/test/kotlin/src/racingcar/RaceTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package src.racingcar

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import src.racingcar.domain.Car
import src.racingcar.domain.Race

class RaceTest {

@Test
fun `여러대의 차들은 움직일 수 있다`() {
val car1 = StubCar()
val cars = listOf(car1)

val race = Race(cars).start()

assertThat(race[0].moveCount).isEqualTo(1)
}

class StubCar : Car("test") {
override fun move(carMoveNumber: Int): Int {
return super.moveCount++
}
}
}
25 changes: 25 additions & 0 deletions src/test/kotlin/src/racingcar/WinnerTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package src.racingcar

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import src.racingcar.domain.Car
import src.racingcar.domain.Winner

class WinnerTest {

@Test
fun `레이싱 우승자를 찾을 수 있다`() {
val car1 = Car("test1")
val car2 = Car("test2")
val car3 = Car("test3")
val cars = listOf(car1, car2, car3)
car1.move(0)
car2.move(4)
car3.move(4)

val winners = Winner(cars).findWinners()

assertThat(winners[0].name).isEqualTo("test2")
assertThat(winners[1].name).isEqualTo("test3")
}
}