-
Notifications
You must be signed in to change notification settings - Fork 79
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
[자동차 경주] 이동훈 미션 제출합니다. #76
Changes from all commits
5857b3e
6cc9ddb
26708a2
963e2ef
a7a4c24
25b1a0e
102d013
682c30a
fba631e
4e45f28
c5b9d31
ff8481f
719ee11
7eaee37
e96b905
2921327
bacde73
710a5a9
7dd4136
b9b6084
9bc35c8
9c05c88
14fc87e
6a2af95
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import model.Car; | ||
import view.InputController; | ||
|
||
import java.util.List; | ||
|
||
public class Application { | ||
public static void main(String[] args) { | ||
InputController inputController = new InputController(); | ||
RacingGame racingGame = new RacingGame(); | ||
|
||
List<String> nameList = inputController.inputNames(); | ||
int times = inputController.inputTimes(); | ||
|
||
nameList.forEach((name) -> { | ||
racingGame.join(new Car(name)); | ||
}); | ||
|
||
racingGame.race(times); | ||
racingGame.printWinners(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import model.Car; | ||
import view.OutputController; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Random; | ||
import java.util.stream.Collectors; | ||
|
||
public class RacingGame { | ||
private final OutputController outputController = new OutputController(); | ||
private final List<Car> carList = new ArrayList<>(); | ||
private final Random random = new Random(); | ||
|
||
public void join(Car player) { | ||
carList.add(player); | ||
} | ||
|
||
public void race(int times) { | ||
while (times != 0) { | ||
carList.forEach( | ||
car -> car.move(random.nextInt(10)) | ||
); | ||
|
||
outputController.printProgressResult(carList); | ||
|
||
times--; | ||
} | ||
} | ||
Comment on lines
+18
to
+28
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. 하나의 함수에서 출력까지 담당하고 있는데, controller를 통해서 레이스의 결과를 출력 함수를 호출 하도록 하는건 어떨까요? |
||
|
||
public void printWinners() { | ||
List<Car> winners = getWinners(); | ||
outputController.printWinners(winners); | ||
} | ||
|
||
public List<Car> getWinners() { | ||
int maxPos = carList.stream().mapToInt(Car::getPos).max().orElse(Integer.MIN_VALUE); | ||
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. 스트림을 잘 활용하셨네요! |
||
|
||
return carList.stream().filter( | ||
car -> car.getPos() == maxPos | ||
).collect(Collectors.toList()); | ||
} | ||
|
||
public List<Car> getCarList() { | ||
return carList; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package model; | ||
|
||
public class Car { | ||
private final String name; | ||
private int pos; | ||
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. 변수명을 지을 때 약어보다 풀로 써주는 것이 변수의 역할을 쉽게 알 수 있어서 좋다고 생각해요. |
||
|
||
public Car(String name) { | ||
this.name = name; | ||
this.pos = 0; | ||
} | ||
|
||
public void move(int num) { | ||
if (num >= 4) | ||
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. 4가 무엇을 의미하는 숫자인지 상수로 표현해보는 것도 괜찮을 것 같아요 |
||
pos++; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public int getPos() { | ||
return pos; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package util; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class NameParser { | ||
public List<String> parseName(String str) { | ||
return Arrays.stream(str.split(",", -1)).toList(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package util; | ||
|
||
public class Validation { | ||
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. 유효성 검사를 하나의 validation클래스로 관리하도록 했군요! 이렇게 했을때의 장점과 단점은 어떤것이 있을까요? |
||
|
||
public void validName(String name) throws RuntimeException { | ||
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. 하나의 검증 내에서도 종류별로 분리하셨군요👍👍 |
||
validNameIsNullOrBlank(name); | ||
validNameSize(name); | ||
} | ||
|
||
public void validTimes(String strTimes) throws RuntimeException { | ||
validParseTimes(strTimes); | ||
validTimesRange(Integer.parseInt(strTimes)); | ||
|
||
} | ||
|
||
public void validNameIsNullOrBlank(String name) { | ||
if (name == null || name.isBlank()) | ||
throw new IllegalArgumentException("이름에 공백이 포함되었습니다."); | ||
} | ||
|
||
public void validNameSize(String name) { | ||
if (name.length() > 5) | ||
throw new IllegalArgumentException("이름의 길이가 5자를 넘었습니다."); | ||
} | ||
|
||
public void validParseTimes(String strTimes) { | ||
try { | ||
Integer.parseInt(strTimes); | ||
} catch (NumberFormatException e) { | ||
throw new IllegalArgumentException("정수가 아닌 값이 입력되었습니다."); | ||
} | ||
} | ||
|
||
public void validTimesRange(int times) { | ||
if (times < 0) { | ||
throw new IllegalArgumentException("시도 횟수에 음수가 입력되었습니다."); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package view; | ||
|
||
import util.NameParser; | ||
import util.Validation; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Scanner; | ||
|
||
public class InputController { | ||
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. View의 역할과 Controller의 역할이 공존하는 것 같습니다! |
||
Scanner sc = new Scanner(System.in); | ||
NameParser nameParser = new NameParser(); | ||
Validation validation = new Validation(); | ||
String strNames; | ||
String strTimes; | ||
int times; | ||
List<String> nameList = new ArrayList<>(); | ||
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로 두신 이유가 궁금합니다! |
||
|
||
public List<String> inputNames() { | ||
System.out.println("경주할 자동차 이름을 입력하세요(이름은 쉼표(,)를 기준으로 구분)."); | ||
strNames = sc.nextLine(); | ||
|
||
nameList = nameParser.parseName(strNames); | ||
|
||
try { | ||
nameList.forEach( | ||
(name) -> validation.validName(name) | ||
); | ||
} catch (IllegalArgumentException e) { | ||
System.out.println(e.getMessage()); | ||
System.exit(1); | ||
} | ||
|
||
return nameList; | ||
} | ||
|
||
public int inputTimes() { | ||
System.out.println("시도할 회수는 몇회인가요?"); | ||
strTimes = sc.nextLine(); | ||
|
||
try { | ||
validation.validTimes(strTimes); | ||
} catch(IllegalArgumentException e) { | ||
System.out.println(e.getMessage()); | ||
System.exit(1); | ||
} | ||
|
||
times = Integer.parseInt(strTimes); | ||
|
||
return times; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package view; | ||
|
||
import model.Car; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class OutputController { | ||
public void printProgressResult(List<Car> carList) { | ||
for (Car car : carList) { | ||
System.out.println(car.getName() + " : " + "-".repeat(car.getPos())); | ||
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. String.format을 이용하면 문자열 결합 비용을 줄일 수 있답니. |
||
} | ||
|
||
System.out.println(); | ||
} | ||
|
||
public void printWinners(List<Car> winnerList) { | ||
String winnerNames = winnerList.stream() | ||
.map(Car::getName) | ||
.collect(Collectors.joining(", ")); | ||
|
||
System.out.println(winnerNames + "가 최종 우승했습니다."); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import model.Car; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.Assertions.*; | ||
|
||
@DisplayName("움직이는 자동차 테스트 클래스") | ||
public class CarTest { | ||
private Car car; | ||
|
||
@BeforeEach | ||
public void beforeEach() { | ||
car = new Car("Kim"); | ||
} | ||
@Test | ||
@DisplayName("자동차 객체 생성이 제대로 되었는가") | ||
public void testCreateCar() { | ||
assertThat(car.getName()).isEqualTo("Kim"); | ||
assertThat(car.getPos()).isEqualTo(0); | ||
} | ||
|
||
@Test | ||
@DisplayName("자동차가 정상적으로 전진하는가") | ||
public void testMoveCar() { | ||
car.move(4); | ||
|
||
assertThat(car.getPos()).isEqualTo(1); | ||
} | ||
|
||
@Test | ||
@DisplayName("자동차가 정상적으로 정지하는가") | ||
public void testStopCar() { | ||
car.move(3); | ||
|
||
assertThat(car.getPos()).isEqualTo(0); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import model.Car; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.Assertions.*; | ||
|
||
@DisplayName("자동차 경주 관련 테스트 클래스") | ||
public class RacingGameTest { | ||
private RacingGame gc; | ||
private Car car1, car2, car3; | ||
|
||
@BeforeEach | ||
public void beforeEach() { | ||
gc = new RacingGame(); | ||
|
||
car1 = new Car("Kim"); | ||
car2 = new Car("Lee"); | ||
car3 = new Car("Park"); | ||
|
||
gc.join(car1); | ||
gc.join(car2); | ||
gc.join(car3); | ||
} | ||
|
||
@Test | ||
@DisplayName("자동차 참여가 정상적으로 되는가") | ||
public void testCarJoin() { | ||
assertThat(gc.getCarList()).hasSize(3); | ||
} | ||
|
||
@Test | ||
@DisplayName("단독 우승자가 정상적으로 구해지는가") | ||
public void testGetSoloWinners() { | ||
gc.getCarList().get(1).move(4); | ||
|
||
assertThat(gc.getWinners()) | ||
.extracting(Car::getName) | ||
.containsExactly("Lee"); | ||
} | ||
|
||
@Test | ||
@DisplayName("공동 우승자가 정상적으로 구해지는가") | ||
public void testGetSameWinners() { | ||
car1.move(9); | ||
car3.move(9); | ||
|
||
assertThat(gc.getWinners()) | ||
.containsExactlyInAnyOrder(car1, car3); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import org.junit.jupiter.api.Assertions; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.ValueSource; | ||
import util.NameParser; | ||
import util.Validation; | ||
|
||
import java.util.List; | ||
|
||
import static org.assertj.core.api.Assertions.*; | ||
|
||
@DisplayName("입력한 값을 검증하는 기능 테스트") | ||
public class ValidationTest { | ||
private Validation validation; | ||
private NameParser nameParser; | ||
|
||
@BeforeEach | ||
public void beforeEach() { | ||
validation = new Validation(); | ||
nameParser = new NameParser(); | ||
} | ||
|
||
@DisplayName("입력한 이름의 파싱이 제대로 되는가") | ||
@Test | ||
public void testNameParse() { | ||
String str = "neo,brie,brown"; | ||
|
||
List<String> nameList = nameParser.parseName(str); | ||
|
||
assertThat(nameList).containsExactly("neo", "brie", "brown"); | ||
|
||
} | ||
|
||
@DisplayName("이름들이 정상적으로 입력된 경우 예외를 발생하지 않는가") | ||
@Test | ||
public void testNameCorrectFormat() { | ||
String str = "neo,brie,brown"; | ||
|
||
List<String> nameList = nameParser.parseName(str); | ||
|
||
Assertions.assertDoesNotThrow(() -> { | ||
nameList.forEach((name) -> { | ||
validation.validName(name); | ||
}); | ||
} | ||
); | ||
} | ||
|
||
@DisplayName("이름들이 비정상적으로 입력된 경우 예외를 발생하지 않는가") | ||
@ParameterizedTest | ||
@ValueSource(strings = {"", ",", ",neo", "neo,"}) | ||
public void testNameIncorrectFormat(String str) { | ||
List<String> nameList = nameParser.parseName(str); | ||
|
||
Assertions.assertThrows(IllegalArgumentException.class, () -> { | ||
nameList.forEach((name) -> { | ||
validation.validName(name); | ||
}); | ||
} | ||
); | ||
} | ||
|
||
@DisplayName("시도 횟수가 정상적으로 입력된 경우 예외를 발생시키지 않는가") | ||
@Test | ||
public void testTimesCorrectFormat() { | ||
String strTimes = "5"; | ||
|
||
Assertions.assertDoesNotThrow(() -> { | ||
validation.validTimes(strTimes); | ||
}); | ||
} | ||
|
||
@DisplayName("시도 횟수가 비정상적으로 입력된 경우 예외를 발생시키지 않는가") | ||
@ParameterizedTest | ||
@ValueSource(strings = { "-5", "asdf", "!!!", "" }) | ||
public void testTimesInCorrectFormat(String strTimes) { | ||
Assertions.assertThrows(IllegalArgumentException.class, () -> { | ||
validation.validTimes(strTimes); | ||
}); | ||
} | ||
} |
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.
RacingGame은 Model에 속한다고 생각되는데 동훈님은 어떻게 생각하시나요?