์ค๋ช ์ ์์ ํธ๋ฌ๋ธ์ํ ์ด ๋ฐ์ํ๋ ๊ธฐ์กด ํจํค์ง ๊ตฌ์กฐ๋ฅผ ์ฒจ๋ถํฉ๋๋ค!
...
โโโ src
โโโ main/java/racingcar
โโโ Controller
| โโโ RacingcargameController.java
|
โโโ Domain
| โโโ Car.java
| โโโ Cars.java
| โโโ Game.java
| โโโ Race.java
|
โโโ Exception
| โโโ CarNameException.java
| โโโ TryCountNumberException.java
|
โโโ Service
| โโโ GameFlowManagementService.java
|
โโโ Util
| โโโ ComputerNumberGenerator.java
|
โโโ View
| โโโ InputView.java
| โโโ OutputView.java
|
โโโ Application.java
ํ๋ ์ด์ด๊ฐ ์๋์ฐจ ์ด๋ฆ๊ณผ ์๋ ํ์๋ฅผ ์ ๋ ฅํ๋ฉด
๊ฐ ์ฐจ์๋ณ๋ก "์คํ๊ฒฐ๊ณผ"์ "์ต์ข ์ฐ์น์ : "๊ฐ ์ถ๋ ฅ๋๋ ํ์
์กฐ๊ฑด์ ์ฃผ์ด์ง ์๋์ ์
์ถ๋ ฅ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
ํ๋ ์ด์ด๊ฐ ์๋์ฐจ ์ด๋ฆ๊ณผ ์๋ ํ์๋ฅผ ์
๋ ฅํ๋ฉด ๊ทธ์ ๋ง๊ฒ ๊ฒฝ์ฃผ๋ฅผ ๋ชจ๋ ์คํํ ํ, ๋์ ๋ ์ฐ์น์ ๋ฐ๋ฅธ ์ต์ข
์ฐ์น์๊ฐ ๋์์ผํ๋ ๋ฐฉ์์ด์ฃ ๐
๊ฒฝ์ฃผํ ์๋์ฐจ ์ด๋ฆ์ ์
๋ ฅํ์ธ์.(์ด๋ฆ์ ์ผํ(,) ๊ธฐ์ค์ผ๋ก ๊ตฌ๋ถ)
pobi,woni,jun
์๋ํ ํ์๋ ๋ชํ์ธ๊ฐ์?
5
์คํ ๊ฒฐ๊ณผ
pobi : -
woni :
jun : -
pobi : --
woni : -
jun : --
pobi : ---
woni : --
jun : ---
pobi : ----
woni : ---
jun : ----
pobi : -----
woni : ----
jun : -----
์ต์ข
์ฐ์น์ : pobi, jun
ํ์ง๋ง, ์ ๊ฐ ๊ตฌํํ ์ฝ๋์ ํ์ฌ์ ์ ์ถ๋ ฅ์ ๊ฐ ์ฐจ์๋ณ๋ก ์คํ๊ฒฐ๊ณผ์ ์ต์ข ์ฐ์น์๊ฐ ๊ฐ๊ฐ ์ถ๋ ฅ๋๋ ํํ๋ก ์งํ๋ฉ๋๋ค๐ญ
๊ฒฝ์ฃผํ ์๋์ฐจ ์ด๋ฆ์ ์
๋ ฅํ์ธ์.(์ด๋ฆ์ ์ผํ(,) ๊ธฐ์ค์ผ๋ก ๊ตฌ๋ถ)
pobi,woni,jun
์๋ํ ํ์๋ ๋ชํ์ธ๊ฐ์?
5
์คํ ๊ฒฐ๊ณผ
pobi : ---
woni : ---
jun : ---
์ต์ข
์ฐ์น์: pobi, woni, jun
์คํ ๊ฒฐ๊ณผ
pobi : ----
woni : --
jun : ---
์ต์ข
์ฐ์น์: pobi
์คํ ๊ฒฐ๊ณผ
pobi : ---
woni : --
jun : --
์ต์ข
์ฐ์น์: pobi
์คํ ๊ฒฐ๊ณผ
pobi : --
woni : ----
jun : ----
์ต์ข
์ฐ์น์: woni, jun
์คํ ๊ฒฐ๊ณผ
pobi : ----
woni : --
jun : -
์ต์ข
์ฐ์น์: pobi
Domain/Car.java
public void playGame(int tryCount) {
for (int i = 0; i < tryCount; i++) {
playOneRound();
List<Car> roundWinners = getWinners();
roundWinners.addAll(roundWinners);
}
roundWinners.addAll(getWinners());
}
๋๋ฒ์งธ๋ก, Race.java ํ์ผ์ ํ์ธํ์ต๋๋ค.
Domain/Race.java
public static void start(List<String> carNames, int tryCount) {
List<Car> cars = createCars(carNames);
Game game = new Game(cars);
game.playGame(tryCount);
List<Car> winners = game.getWinners();
OutputView.printHead();
OutputView.printRaceResult(cars);
OutputView.printWinners(winners);
}
IllegalArgumentException์ด ๋ฐ์๋์ด์ผ ํ์ง๋ง
-> CarNameException์ ๊ฒฝ์ฐ ์์ธ ์ฒ๋ฆฌ๊ฐ ์์ ๋ฐ์๋์ง ์๋๋ค.
->TryCountException์ ๊ฒฝ์ฐ NumberFormatException์ด ๋ฐ์ํ๋ค.
ํ๊ฐ์ง๋ง ๋ฌธ์ ๊ฐ ์๊ธฐ๋ฉด ์ผ๋ง๋ ์ข์๊น์??
ํ์ง๋ง ๊ทธ๋ด ์ ์์ฃ ๐ฉ
์ฐ์ ๋จผ์ CarNameException.java๋ฅผ ๊ฐ์ ธ์๋ณผ๊ฒ์.
Exception/CarNameException.java
package racingcar.Exception;
public class CarNameException extends IllegalArgumentException {
public CarNameException() {
super("์๋์ฐจ ์ด๋ฆ์ 1์ ์ด์, 5์ ์ดํ๋ง ๊ฐ๋ฅํฉ๋๋ค.");
}
public static void validateCarName(String name) {
if (name == null || name.length() < 1 || name.length() > 5) {
throw new CarNameException();
}
}
}
validateCarName์ ํตํด ์ด๋ฆ์ ๊ธธ์ด๊ฐ ๊ณต๋ฐฑ์ด๊ฑฐ๋, 1 ์ดํ, 5 ์ด์์ผ ๋ IllegalArgumentException์ด ๋ฐ์๋๋๋ก ๋ก์ง์ ๊ตฌ์ฑํ์ต๋๋ค. ํ์ง๋ง ์์ ์์ธ๋ก ์ฒ๋ฆฌ๋์ง ์์์ด์๐
๋ฐ๋ผ์ 3๊ฐ์ง๋ฅผ ํ๋ฒ์ ์ฒ๋ฆฌํ์ง ์๋๋ก ์ด๋ ๊ฒ ์์ ํด๋ดค์ง๋ง, ์ฌ์ ํ ์๋ํ์ง ์์์ต๋๋ค.
public class CarValidator {
public static void validateCarName(String name) {
if (name == null) {
throw new CarNameNullException();
}
if (name.length() < 1 || name.length() > 5) {
throw new CarNameLengthException();
}
}
}
๊ธฐ๋ณธ์ ์ผ๋ก ์ฃผ์ด์ง ํ ์คํธ๋ 2๊ฐ์ง์ธ๋ฐ,
-> ์ ์ง_์ ์ง()์์ test failed๊ฐ ๋ฐ์!
-> ์ ๊ธฐํ๊ฒ๋ ๊ทธ ๋ค์์ ์์ธ ์ฒ๋ฆฌ๋ ์ ์์ ์ผ๋ก ํ ์คํธ๊ฐ ํต๊ณผํ๋ค? ๋ถ๋ช ์์ธ๋ก ์ฒ๋ฆฌ๊ฐ ์๋๊ณ ๊ฒฝ์ฃผ๊ฐ ์งํ๋์๋๋ฐ ๋ง์ด์ง๐ง
๊ธฐ๋ณธ ์ ๊ณต๋ ํ
์คํธ๋ ์ ์ง ์ ์ง() ์ ์ด๋ฆ์ ๋ํ ์์ธ ์ฒ๋ฆฌ() ์ ์ด 2๊ฐ์ง๋ก ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค.
test/java/racingcar/ApplicationTest.java
@Test
void ์ ์ง_์ ์ง() {
assertRandomNumberInRangeTest(
() -> {
run("pobi,woni", "1");
assertThat(output()).contains("pobi : -", "woni : ", "์ต์ข
์ฐ์น์ : pobi");
},
MOVING_FORWARD, STOP
);
}
@Test
void ์ด๋ฆ์_๋ํ_์์ธ_์ฒ๋ฆฌ() {
assertSimpleTest(() ->
assertThatThrownBy(() -> runException("pobi,javaji", "1"))
.isInstanceOf(IllegalArgumentException.class)
);
}
์ฝ๋ ์ฌ๊ตฌ์ฑ ๊ฒฐ์ !! ๋ ๋ ๐ฉ๐ปโโ๏ธ
๊ฒฐ๊ตญ, ์ฝ๋๋ฅผ ์ฒ์๋ถํฐ ๋ค์ ์ง๋ ๊ฒ์ผ๋ก ํด๊ฒฐ์ ์ ์ฐพ์์ต๋๋ค!
๋ญ ํญ์ ๋ค๋ค ๊ทธ๋ ์ง ์๋์...?? ํํํํ๐คฆ๐ปโโ๏ธ
ํจํค์ง ๊ตฌ์กฐ๋ ์ด๋์ ๋ ์ ์งํ๋, ์๋ฌด๋๋ ์ฐจ์ ์ด๋ฆ์ ์์ธ๋ ์ ์ก์ง ๋ชปํ๊ณ ์ ์ง ์ ์ง๋ ์ ์ก์ง ๋ชปํ๋ Repository ๊ฐ๋ ์ ์ด์ฉํด ํจํค์ง์ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
Spring์ ์์ฃผ ์ฌ์ฉํ์ ๋ถ๋ค์๊ฒ ์กฐ๊ธ ๋ ์ต์ํ ํจํค์ง ์ด๋ฆ์ผ ์๋ ์์ด์!
์ ์ญ์๋ ๋งค์ฐ ์ต์ํฉ๋๋ค๐
๋๋ถ๋ถ DB์ ์ ๊ทผํ๊ธฐ ์ํ ์ฝ๋๋ฅผ ์ด๊ณณ์ ์์ฑํ์ฃ ?
ํ์ง๋ง, ์ ๊ฐ ์ฌ์ฉํ๋ ค๋ Repository ํจํค์ง ์ฌ์ฉ ๋ชฉ์ ์ ๋น์ทํ๋ฉด์๋ ์กฐ๊ธ์ ๋ค๋ฆ
๋๋ค.
์ค์ ๋ก DB์ ์ ์ฅํ์ง๋ ์์ง๋ง, ๋ฆฌ์คํธ ํํ๋ก ๊ฐ์ ์ ์ฅํ๊ธฐ ๋๋ฌธ์ DB์ ๋น์ทํ ์ญํ ์ ํ๋ค๊ณ ์๊ฐํ์ต๋๋ค.
์ด๋ ๊ฒ ๋๋ค๋ฉด
๋ง์ง๋ง์ผ๋ก, ์๋์ฐจ์ ์ด๋ฆ ์ ๋ณด๋ฅผ ๋ฌธ์์ด ์์ฒด๋ก ๊ธฐ์ตํ๋ ๊ฒ๋ ์ข์ง๋ง ๊ฐ์ธ์ ์ผ๋ก๋ ๊ณ ์ ์ ID๊ฐ์ด ์๋ค๋ฉด ์ฒ๋ฆฌ๊ฐ ์กฐ๊ธ ๋ ์ฉ์ดํ์ง ์์๊น?ํ๋ ๊ณ ๋ฏผ๋ ์์ด์ ๊ฒฐ์ ํ๋ต๋๋ค๐
๋ฒ์ธ๋ก ๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ๊ฐ ๊ถ๊ธํ์ ๋ถ๋ค์ ๐Spring Guide - Directory
ํจํค์ง ๊ตฌ์กฐ ๊ฐ์ด๋ ๋ฅผ ์ฐธ๊ณ ํ์๋ฉด ๊ธฐ๋ณธ์ ์ธ ํํ๋ฅผ ์์๋ณด์ค ์ ์์ด์!
๋ํ, Controller์ Servic ์ญ์ ์ด์ ์ 1์ฃผ์ฐจ ์จ๋ณด๋ฉ ๋ฏธ์ ์ด์๋ ์ซ์ ์ผ๊ตฌ ๊ฒ์์ ์ฌ์ฉ์ฑ๊ณผ ๋์ผํ๊ฒ ์ ์งํ๋ ๊ฒ์ผ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
์ฌ์ค Countroller๊ฐ ์ฝ๋์ ๋ชจ๋ ๊ด๋ฆฌ๋ฅผ ํ๊ณ ์งํฉ ์ ์ฅ์๊ฐ ๋๋ ๊ฒ์ด ์์กด๋๊ฐ ๊ณผํ๊ฒ ๋์์ง๋ ๊ฒ ๊ฐ์ ์ปจํธ๋กค๋ฌ์ ์ฑ ์์ ๋ถ์ฐํ๋ ค๋ ๋ชฉ์ ์ผ๋ก, Service ์ญ์ View์์ ์์กด๋๊ฐ ๋์ ๋ถ์ฐํ๋ ๊ฒ์ ๋ชฉ์ ์ผ๋ก ์ญํ ์ ๋ค๋ฅด๊ฒ ์ค์ ํ์์ต๋๋ค.
Domain๋ ํ์ผ ์์ฒด๋ฅผ ์ญํ ์ ๋ฐ๋ผ์ 4๊ฐ์ง๋ก ๋ถ์ฐํ์ผ๋ ์คํ๋ ค ์ค๋ฅ๊ฐ ๋ฒ์ง๋ ์์ธ์ด ๋๋ ๊ฒ์ผ๋ก ์๊ฐํ๊ฒ ๋์ด ์ด์ ์ ๋ฐฉ์์ ์ ์งํ๋ ๊ฒ์ด ์ด๋จ๊น ๊ณ ๋ฏผํ์ต๋๋ค.
๊ทธ๋ฌ๋ ๋๋ฌด ๋ง์ ์๊ฐ์ ๋ณด๋ด๊ณ ์๋ค๋ ์๊ฐ์ด ๋ค์ด ์ด๋ฒ ๋ฏธ์ ์์๋ ์ด์ ์ 1์ฃผ์ฐจ ๋ฏธ์ ์์์ ๊ฐ์ ๋ชฉ์ ์ ๊ฐ์ง ํจํค์ง๋ก ๊ตฌ์ฑํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค๐คฏ
๋ณ๊ฒฝ๋ ํจํค์ง ๊ตฌ์กฐ
...
โโโ src
โโโ main/java/racingcar
โโโ Controller
| โโโ RacingcargameController.java
|
โโโ Domain
| โโโ Car.java
| โโโ Game.java
|
โโโ Repository
| โโโ CarRepository.java
| โโโ GameRepository.java
|
โโโ Exception
| โโโ CarNameException.java
| โโโ TryCountNumberException.java
|
โโโ Service
| โโโ GameFlowManagementService.java
|
โโโ Util
| โโโ ComputerNumberGenerator.java
| โโโ StringToList.java
|
โโโ View
| โโโ InputView.java
| โโโ OutputView.java
|
โโโ Application.java
๊ธฐ์กด์ CarNameException ์ผ๋ถ
Exception/CarNameException.java
...
public class CarNameException {
private final StringToList stringToList = new StringToList();
private static final int MINIMUM_CARNAME_LENGTH = 1;
private static final int MAXIMUM_CARNAME_LENGTH = 5;
private static final String BLANK = "";
public void validateCarNameInput(String carNameInput) throws IllegalArgumentException {
List<String> carNameList = stringToList.analysisCarNames(carNameInput);
checkCarNameIsOutOfRangeAndBlank(carNameList);
checkCarNameIsDuplication(carNameList);
checkInputIsEmpty(carNameInput);
checkLastInputIsComma(carNameInput);
}
...
์ฌ๊ธฐ์์, validateCarNameInput์ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋ํ, ๊ณต๋ฐฑ๊ณผ ์ผํ ์ญ์ ๋ฉ์๋๋ฅผ ๋ถ๋ฆฌํด ํจ๊ป ๋ฃ์ด์ฃผ์์ต๋๋ค.
์ด ์ฝ๋๋ฅผ ํตํด Application์ ๊ตฌ๋ํ๋ฉด, ์ ์์ ์ผ๋ก ์์ธ๋ฅผ ์ถ๋ ฅํ ๊ฒ์ด๋ผ ์๊ฐํ๊ณ ๋ฌธ์ ์ ์ ํ์ ํ์ง ๋ชปํ๊ณ ์๋ ์ํ์์ต๋๋ค.
ํ์ง๋ง ๋ค์์ ํ ์คํธ๋ฅผ ํ ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์์ ์ ์ ์์์ต๋๋ค.
ํ
์คํธ ํ์ผ ์ ๋ฌธ์ ์ฒจ๋ถํ ๊ฒ์!
Test/java/racingcar/Exception/CarNameExceptionTest.java
package racingcar.Exception;
import org.junit.jupiter.api.Test;
import racingcar.Exception.CarNameException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class CarNameExceptionTest {
@Test
void testValidateCarNameInput_ValidInput_์ฌ๋ฐ๋ฅธ_์
๋ ฅ() {
// given
CarNameException carNameException = new CarNameException();
String carNameInput = "a,b,c";
// when, then
assertDoesNotThrow(() -> carNameException.validateCarNameInput(carNameInput));
}
@Test
void testValidateCarNameInput_NoInput_์
๋ ฅ๊ฐ_์์() {
// given
CarNameException carNameException = aCarNameException();
String carNameInput = "";
// when, then
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> carNameException.validateCarNameInput(carNameInput));
assertThat(exception.getMessage()).isEqualTo("๊ฐ์ ์
๋ ฅํด์ฃผ์ธ์.");
}
@Test
void testValidateCarNameInput_LastInputComma_์
๋ ฅ๊ฐ_๋_์ผํ() {
// given
CarNameException carNameException = aCarNameException();
String carNameInput = "a,b,c,";
// when, then
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> carNameException.validateCarNameInput(carNameInput));
assertThat(exception.getMessage()).isEqualTo("์๋์ฐจ ์ด๋ฆ์ 1๊ธ์ ์ด์์ด์ด์ผ ํฉ๋๋ค.");
}
@Test
void testValidateCarNameInput_InvalidLength_๊ธธ์ด_๋ฏธ๋ง() {
// given
CarNameException carNameException = aCarNameException();
String carNameInput = ",b,c";
// when, then
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> carNameException.validateCarNameInput(carNameInput));
assertThat(exception.getMessage()).isEqualTo("์๋์ฐจ ์ด๋ฆ์ 1๊ธ์ ์ด์์ด์ด์ผ ํฉ๋๋ค.");
}
@Test
void testValidateCarNameInput_InvalidLength_๊ธธ์ด_์ด๊ณผ() {
// given
CarNameException carNameException = new CarNameException();
String carNameInput = "a,bcdefgh,b";
// when, then
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> carNameException.validateCarNameInput(carNameInput));
assertThat(exception.getMessage()).isEqualTo("์๋์ฐจ ์ด๋ฆ์ 5๊ธ์ ์ดํ์ฌ์ผ ํฉ๋๋ค.");
}
@Test
void testValidateCarNameInput_CarNameWithSpace_๊ณต๋ฐฑ์ด_ํฌํจ๋_์ด๋ฆ() {
// given
CarNameException carNameException = new CarNameException();
String carNameInput = "a a,b,c";
// when, then
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> carNameException.validateCarNameInput(carNameInput));
assertThat(exception.getMessage()).isEqualTo("์๋์ฐจ ์ด๋ฆ์์๋ ๊ณต๋ฐฑ์ด ์์ด์๋ ์๋ฉ๋๋ค.");
}
@Test
void testValidateCarNameInput_DuplicateCarName_์ค๋ณต๋_์ด๋ฆ() {
// given
CarNameException carNameException = new CarNameException();
String carNameInput = "a,a,b";
// when, then
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> carNameException.validateCarNameInput(carNameInput));
assertThat(exception.getMessage()).isEqualTo("๊ฐ์ ์ด๋ฆ์ ๊ฐ์ง ์๋์ฐจ๊ฐ ์์ต๋๋ค.");
}
private CarNameException aCarNameException() {
return new CarNameException();
}
}
์๋ ๊ฒ ์ค๋ฅ๊ฐ ๋ฐ์ํ์์ ์ ์ ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์์ ์ด์ํ ์ ์ ๋ฐ๊ฒฌํ์ด์.
ApplicationTest์ ์ ์ง_์ ์ง() ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ฒ๋๋ค!
์ค๋ฅ๋ฅผ ๋ค์ ๋ณด์๐ง
๋จ์ํ ํ ์คํธ ์ฝ๋์์์ ๋ฌธ์ ๊ฐ ์๊ฒผ๋ค๊ณ ์๊ฐํ์ง๋ง ์๊ณ ๋ณด๋ CarNameException ์ฝ๋ ์์ฒด์ ๋ฌธ์ ๊ฐ ์๋ค๋ ๊ฒ์ ์๊ฒ ๋์์ด์:)
๋ค์ ํ๋ฒ ๋ณด๊ฒ ์ต๋๋ค!
Exception/CarNameException.java
...
public class CarNameException {
private final StringToList stringToList = new StringToList();
private static final int MINIMUM_CARNAME_LENGTH = 1;
private static final int MAXIMUM_CARNAME_LENGTH = 5;
private static final String BLANK = " ";
...
public void validateCarNameInput(String carNameInput) throws IllegalArgumentException {
checkInputIsEmpty(carNameInput);
checkLastInputIsComma(carNameInput);
List<String> carNameList = stringToList.analysisCarNames(carNameInput);
checkCarNameIsOutOfRangeAndBlank(carNameList);
checkCarNameIsDuplication(carNameList);
}
java๋ ์ฝ๋์ ์๋ถ๋ถ๋ถํฐ ์ฐจ๋ก๋๋ก ์ฒ๋ฆฌํด ๋๊ฐ๋ ํน์ฑ์ด ์๊ธฐ ๋๋ฌธ์, ์ฐ์ ์ ์ผ๋ก ์์ฑ๋ ์ฝ๋๊ฐ ์ฐ์ ๊ถ์ ๊ฐ์ง๋ค๊ณ ์๊ฐํ๋ฉด ์ข์์!
๊ทธ๋ผ, ๋ค์ ํ
์คํธ๋ฅผ ์งํํด๋ณด๊ฒ ์ต๋๋ค.
-> ์ฑ๊ณต์
๋๋ค๐