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

자동차경주/제훈/step1 #4

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 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
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apply plugin: 'eclipse'

group = 'camp.nextstep'
version = '1.0.0'
sourceCompatibility = '1.8'
sourceCompatibility = "11"

repositories {
mavenCentral()
Expand All @@ -17,3 +17,4 @@ dependencies {
test {
useJUnitPlatform()
}
targetCompatibility = JavaVersion.VERSION_11
10 changes: 10 additions & 0 deletions src/main/java/study/racingcar/RacingCarApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package study.racingcar;

import study.racingcar.controller.CarController;

public class RacingCarApplication {

public static void main(String[] args) {
new CarController();
}
}
12 changes: 12 additions & 0 deletions src/main/java/study/racingcar/controller/CarController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package study.racingcar.controller;

import static study.racingcar.model.Car.raceStart;
import static study.racingcar.view.InputView.getAttemptNumber;
import static study.racingcar.view.InputView.getCarNumber;

public class CarController {
Copy link
Collaborator

Choose a reason for hiding this comment

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

'CarController' 에서 로직을 직접 구현해서 사용하고 있네요!
현재의 구조에서는 Car객체와 CarController가 서로 바뀐듯처럼 보이네요 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

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

CarController 라는 네이밍은 왜 나온것일까요?
게임기 컨트롤러 처럼 도메인 객체에게 어떠한 일을 하도록 시키는 녀석이 아닐까요?
현재의 구조에서는 Car 객체가 CarController에게 자동차 경주를 하도록 시키는 것으로 보이네요~

Copy link
Collaborator Author

@JoJeHuni JoJeHuni Jul 19, 2023

Choose a reason for hiding this comment

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

MVC 패턴이 컨트롤러 로직 실행 -> 비즈니스 로직 실행 후 결과를 받고 -> 결과 데이터를 모델에 저장 -> 컨트롤러에서 뷰 로직으로 권한을 넘겨준 뒤 뷰는 모델에서 데이터를 참조해 응답하는 것이라는걸 정리해놓고 활용할 때는 반대로 이행하고 있었네요.. 감사합니다!


public CarController() {
raceStart(getCarNumber(), getAttemptNumber());
}
}
52 changes: 52 additions & 0 deletions src/main/java/study/racingcar/model/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package study.racingcar.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import static study.racingcar.view.ResultView.printRaceResult;

public class Car {

private static final int MAX_BOUNDARY_OF_RANDOM_NUMBER= 10;
public Car(int carNum, List<Integer> positions) {
addCar(carNum, positions);
}

public static void raceStart(int carNum, int attemptNum) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Car 객체 내부에서 자동차 경주를 시작하고
자동차들을 생성하고 있네요!

뭔가 어색하다고 느껴지지 않나요?
raceStart()메서드는 컨트롤러로 보내고
컨트롤러의 raceStart()에서 자동차들을 생성하고
이동하라고 요청을 보내보는건 어떨까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

컨트롤러에서 자동차를 생성해서 요청을 보내면서 로직을 실행하고 모델에 저장한 뒤 뷰로 제어권을 넘겨주려고 수정하고 있습니다!! 감사합니다

List<Integer> positions = new ArrayList<>();

Car car = new Car(carNum, positions);

car.addCar(carNum, positions);

for (int i = 0; i < attemptNum; i++) {
car.requestCarsToMove(carNum, positions);
printRaceResult(positions);
Copy link
Collaborator

Choose a reason for hiding this comment

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

같은 이유로 raceStart() 메서드가 Car 객체로 들어와서
도메인이 "알 필요가 없는" print 로직이 존재하네요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

그렇네요.. print 로직은 ResultView로 옮기겠습니다!

}
}

private static void addCar(int carNum, List<Integer> positions) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

매서드 마다 static 키워드가 덕지덕지 붙어있는데, static 키워드를 붙이신 이유는 무엇일까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

static 사용할 때를 아직 잘 몰랐던 것 같습니다. 타입을 변경할 때, 특정 상수를 사용할 때 static을 사용하게끔 수정해보겠습니다!

for (int i = 0; i < carNum; i++) {
positions.add(i,0);
}
}

public static void requestCarsToMove(int carNum, List<Integer> positions) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

여기서도 Car객체가 Car객체한테 이동하라고 요청하는 형태가 되었군요 🤔

for (int i = 0; i < carNum; i++) {
forwardNumber(i, positions);
}
}

private static void forwardNumber(int current, List<Integer> positions) {
Random random = new Random();
int forward = random.nextInt(MAX_BOUNDARY_OF_RANDOM_NUMBER); // 0부터 9

if (forward >= 4) { // 전진하는 조건
int currentValue = positions.get(current);
int newValue = currentValue + 1;

positions.set(current, newValue);
}
}
}
24 changes: 24 additions & 0 deletions src/main/java/study/racingcar/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package study.racingcar.view;

import java.util.Scanner;

public class InputView {
public static int getCarNumber() {
Scanner scanner = new Scanner(System.in);

System.out.println("자동차 대수는 몇 대 인가요?");
int carNum = scanner.nextInt();

return carNum;
}

public static int getAttemptNumber() {
Scanner scanner = new Scanner(System.in);

System.out.println("시도할 횟수는 몇 회인가요?");
int attemptNum = scanner.nextInt();
System.out.println();

return attemptNum;
}
}
16 changes: 16 additions & 0 deletions src/main/java/study/racingcar/view/ResultView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package study.racingcar.view;

import java.util.Collections;
import java.util.List;
import java.util.Random;

public class ResultView {
public static void printRaceResult(List<Integer> positions) {
for (int pos : positions) {
for (int k = 0; k < pos; k++) {
System.out.print("ㅡ");
}
System.out.println();
}
}
}
36 changes: 36 additions & 0 deletions src/main/java/study/stringcalculator/StringCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package study.stringcalculator;

import java.util.List;

public class StringCalculator {

private StringCalculator() { }
public static int calculate(String text) {
List<String> values = StringParser.parse(text);
int number = Integer.parseInt(values.get(0));

for (int i = 1; i < values.size(); i += 2) {

int operand = Integer.parseInt(values.get(i + 1));
String operator = values.get(i);

number = getNumber(number, operand, operator);
}

return number;
}

private static int getNumber(int number, int operand, String operator) {
if ("+".equals(operator)) return number + operand;
if ("-".equals(operator)) return number - operand;
if ("*".equals(operator)) return number * operand;
if ("/".equals(operator)) {
if (operand == 0) {
throw new IllegalArgumentException();
}
return number / operand;
}

throw new IllegalArgumentException("잘못된 연산자 입니다.");
}
}
14 changes: 14 additions & 0 deletions src/main/java/study/stringcalculator/StringParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package study.stringcalculator;

import java.util.List;

public class StringParser {

private StringParser() { }

static List<String> parse(String input) {
return List.of(input.split(" "));
// 알아둘 것. ArrayList로 만들면 가변 + null값 허용
// List.of 메서드로 만들면 불변 + null값은 허용 X
}
}
13 changes: 0 additions & 13 deletions src/test/java/study/StringTest.java

This file was deleted.

84 changes: 84 additions & 0 deletions src/test/java/study/exam/SetTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package study.exam;

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.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;

import java.util.HashSet;
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class SetTest {
Copy link
Collaborator

Choose a reason for hiding this comment

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

저번 요구사항을 반영해서 구체적인 테스트로 바꿔주셨군요 👍

private Set<Integer> numbers;

@BeforeEach
@DisplayName("HashSet에 값을 추가한다.")
void setUp() {
numbers = new HashSet<>();
numbers.add(1);
numbers.add(1);
numbers.add(2);
numbers.add(3);
}

@Test
@DisplayName("집합의 크기를 확인할 수 있다.")
void setSize() {
int result = numbers.size();
assertEquals(result, 3); // Set은 중복을 허용하지 않는다.
}

@Test
@DisplayName("집합에 값이 포함되어있는지 비교할 수 있다.")
void compareContains() {
numbers = new HashSet<>();

numbers.add(1);
numbers.add(1);
numbers.add(2);
numbers.add(3);

assertThat(numbers.contains(1)).isTrue();
assertThat(numbers.contains(2)).isTrue();
assertThat(numbers.contains(3)).isTrue();
}

@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
@DisplayName("ValueSource를 사용해 입력 받은 숫자가 각각 numbers에 포함되는지 확인한다.")
void compareContains(int value) {
numbers = new HashSet<>();

numbers.add(1);
numbers.add(1);
numbers.add(2);
numbers.add(3);

assertThat(numbers.contains(value)).isTrue();
}

@ParameterizedTest
@CsvSource({
"1, true",
"2, true",
"3, true",
"4, false",
"5, false"
})
@DisplayName("CsvSource로 true 값만 비교하는 것이 아닌 false 값도 비교할 수 있다.")
void compareContains(int value, boolean expected) {
numbers = new HashSet<>();

numbers.add(1);
numbers.add(1);
numbers.add(2);
numbers.add(3);

assertThat(numbers.contains(value)).isEqualTo(expected);
}
}
47 changes: 47 additions & 0 deletions src/test/java/study/exam/StringTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package study.exam;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class StringTest {
Copy link
Collaborator

Choose a reason for hiding this comment

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

좋습니다~ 💪

@Test
@DisplayName("abc에서 b를 d로 대체했을 때 같은지 테스트하는 코드")
void replace() {
String actual = "abc".replace("b", "d");
assertThat(actual).isEqualTo("adc");
}
// 요구사항 1
@Test
@DisplayName("특정 문자열로 분리하는 테스트 코드")
public void split() {
String[] values = "1,2".split(",");
assertThat(values).containsExactly("1", "2");
values = "1".split(",");
assertThat(values).contains("1");
}
@Test
@DisplayName("특정 문자열까지 읽어서 비교하는 테스트 코드")
public void subString() {
String input = "(1,2)";
String result = input.substring(1, input.length() - 1); //문자열 인덱스 1부터 input의 길이 - 1 즉 2까지.
assertThat(result).isEqualTo("1,2");
}
@Test
@DisplayName("String의 특정 위치의 문자 가져오기")
public void getIndexValue() {
String values = "abc";
assertEquals('a', values.charAt(0));
}

@Test
@DisplayName("위치 값을 벗어났을 때의 예외")
public void stringIndexOutOfBoundsException() {
String values = "abc";
assertThrows(StringIndexOutOfBoundsException.class, () -> values.charAt(-1));
assertThrows(StringIndexOutOfBoundsException.class, () -> values.charAt(3));
}
}
44 changes: 44 additions & 0 deletions src/test/java/study/racingcar/CarTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package study.racingcar;

import org.junit.jupiter.api.Test;
import study.racingcar.model.Car;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class CarTest {

private static final int POSITIONS_INDEX = 0;
@Test
public void 자동차_대수와_시도_횟수를_1로_정해준_뒤_이동_로직을_확인한다() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

자동차의 대수와 시도 횟수가 꼭 1이여야 하는 이유가 있을까요?

Copy link
Collaborator

Choose a reason for hiding this comment

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

자동차의 입장에서는 횟수가 몇번인지, 자동차 갯수가 몇개인지를 알 필요가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

맞습니다 이동 로직을 확인하는데 자동차의 대수는 상관없으니 수정해보겠습니다!!

int carNum = 1;
int attemptNum = 1;
List<Integer> positions = new ArrayList<>();

Car car = new Car(carNum, positions);
car.raceStart(carNum, attemptNum);

int carPosition = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

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

carPosition 변수가 필요한 이유는 무엇인가요? 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

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

자동차 내부에서 여러대의 자동차를 생성하고 레이스를 실행하는 기형적인 형태를 가지게 되어서,
테스트 할때 자동차의 갯수와 횟수를 특정 숫자로 강제하는 형태가 되었네요.

Copy link
Collaborator

Choose a reason for hiding this comment

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

자동차를 생성하고 레이스를 실행하는 책임을 다른 객체에게 위임하고
자동차는 위치, 이동할지 말지에 대한 책임만을 가지고 관리하게 만들어 보면 어떨까요?

Copy link
Collaborator

Choose a reason for hiding this comment

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

이런식으로 책임을 나누게 되면 번거롭게 carPosition 변수를 만들고 할 필요없이,
바로 Car 객체한테 현재의 위치를 알려달라고 요청하는 형태로 바꿀 수 있겠네요~

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

자동차 생성, 레이스 실행의 책임은 컨트롤러에게, 자동차는 이동하는 '기능'만 가지게끔 수정해보겠습니다. 조언 감사합니다


for (int i = 0; i < positions.size(); i++) {
carPosition = positions.get(i);
}

assertEquals(carPosition >= 0 && carPosition <= 1, true);
}

@Test
public void 자동차_대수를_1대로_정해준_뒤_전진_로직을_확인한다() {
int carNum = 1;
List<Integer> positions = new ArrayList<>();

Car car = new Car(carNum, positions);
car.requestCarsToMove(carNum, positions);

int carPosition = positions.get(POSITIONS_INDEX);

assertEquals(carPosition == 0 || carPosition == 1, true);
}
}
Loading