-
Notifications
You must be signed in to change notification settings - Fork 410
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
base: youngsuk-kim
Are you sure you want to change the base?
Step4 자동차 경주 리팩토링 #948
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
경주할 자동차 이름을 추출 하는 기능. | ||
|
||
경주할 자동차 대수를 추출 하는 기능. | ||
|
||
경주 자동차 이름 별로 "-" 가 나오도록 구현. | ||
|
||
어떤 자동차가 최종 우승 하였는지 알아내는 기능 | ||
|
||
모든 로직에 단위 테스트를 구현한다. | ||
|
||
단, 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자를 초과할 수 없다. | ||
|
||
전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. | ||
|
||
자동차 이름은 쉼표(,)를 기준으로 구분한다. | ||
|
||
자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,22 @@ | ||||||||||
package src.racingcar.domain | ||||||||||
|
||||||||||
open class Car( | ||||||||||
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. open class를 사용하신 이유가 있을까요? |
||||||||||
val name: String, | ||||||||||
moveCount: Int = 0 | ||||||||||
) { | ||||||||||
|
||||||||||
var moveCount: Int = moveCount | ||||||||||
protected set | ||||||||||
Comment on lines
+8
to
+9
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
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
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. 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 | ||||||||||
} | ||||||||||
} |
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
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. 도메인 클래스에 대한 테스트는 모두 해야한다고 생각해요! race에 결과에 대한 테스트는 어떻게 해야 할까요? 참고 문서 입니다! |
||
|
||
companion object { | ||
fun create(carNames: List<String>): Race { | ||
val cars = buildList { | ||
carNames.forEach { this.add(Car(it)) } | ||
} | ||
return Race(cars) | ||
} | ||
} | ||
} |
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 } | ||||||
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
|
||||||
} | ||||||
} |
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(",") | ||
} |
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 | ||
) |
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("가 최종 우승 했습니다.") | ||
} | ||
} |
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") | ||
} | ||
} |
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++ | ||
} | ||
} | ||
} |
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") | ||
} | ||
} |
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.
description.md
파일의 위치는 src가 아닌 다른 디렉터리에 있어야하지 않을까요?