Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b260211
* feat : 1단계 구현
JihwanYeom Mar 12, 2025
d5a9797
* test : Car 객체 테스트 코드 작성
JihwanYeom Mar 12, 2025
92c56ec
* feat : 2단계 구현
JihwanYeom Mar 12, 2025
9e69781
* test : makeWinnerList() 테스트코드 작성
JihwanYeom Mar 12, 2025
d187dc8
* docs : README 작성
JihwanYeom Mar 12, 2025
15ed321
* docs : README 수정
JihwanYeom Mar 15, 2025
e38bd09
* fix : Car, Game 클래스 리뷰 1차 반영
JihwanYeom Mar 15, 2025
96b822e
* test : 테스트 코드 리뷰 1차 반영
JihwanYeom Mar 15, 2025
11094f8
* feat : 3단계 구현
JihwanYeom Mar 19, 2025
7b7c714
* test : 4단계 부분 구현
JihwanYeom Mar 19, 2025
a1b7358
Merge branch 'jihwanyeom' into jihwanyeom
JihwanYeom Mar 19, 2025
833a5a8
* test : Car 테스트 수정
JihwanYeom Mar 22, 2025
46cbdbf
* test : Cars 테스트 코드 작성
JihwanYeom Mar 22, 2025
1386774
* test : Game 테스트 코드 삭제 및 Racing 테스트 코드 작성
JihwanYeom Mar 22, 2025
e6e1089
* test : Controller 테스트 코드 작성
JihwanYeom Mar 22, 2025
40fd209
* test : View 테스트 코드 작성
JihwanYeom Mar 22, 2025
2943098
* refactor : Controller 인스턴스 변수 최소화
JihwanYeom Mar 22, 2025
e9de809
* refactor : 같은 거리의 자동차를 구하는 로직의 메서드 명 변경
JihwanYeom Mar 22, 2025
34995d0
* feat : 사용자 입력 안내 메세지 출력 메서드 추가
JihwanYeom Mar 22, 2025
759de06
* style : RacingApplicaion에 개행 추가
JihwanYeom Mar 22, 2025
bd2d256
* docs : README.md 업데이트
JihwanYeom Mar 22, 2025
df2090b
* chore : 생성자 중복제거
JihwanYeom Mar 22, 2025
30742b5
Merge remote-tracking branch 'origin/jihwanyeom' into jihwanyeom
JihwanYeom Mar 22, 2025
c916e39
docs : README.md 오타 변경
JihwanYeom Mar 22, 2025
2c48874
chore : 불필요해진 파일 삭제
JihwanYeom Mar 23, 2025
0c0ba23
style : 실행파일 불필요한 개행 제거
JihwanYeom Mar 23, 2025
cb2c86a
feat : 이름에 대한 예외처리 추가
JihwanYeom Mar 23, 2025
0050f0f
feat : 이름에 대한 예외처리를 입력단에 추가
JihwanYeom Mar 23, 2025
4995016
refactor : Cars 객체 생성전략 변경
JihwanYeom Mar 23, 2025
f4133eb
refactor : RandomNumberGenerator 클래스 수정
JihwanYeom Mar 23, 2025
eed3c57
refactor : OutputView 포맷 관련 메서드 수정
JihwanYeom Mar 23, 2025
1350e36
test : Cars 테스트에 Fixture 적용
JihwanYeom Mar 23, 2025
38976c5
style : 코드 서식 점검
JihwanYeom Mar 23, 2025
97bb64d
test : 입력 서식 검증 테스트 추가
JihwanYeom Mar 23, 2025
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
10 changes: 10 additions & 0 deletions src/main/java/RacingApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import controller.RacingController;
import domain.RandomNumberGenerator;

public class RacingApplication {

public static void main(String[] args) {
new RacingController().run(new RandomNumberGenerator());
}
Comment on lines +6 to +7

@TaeyeonRoyce TaeyeonRoyce Mar 22, 2025 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

줄바꿈도 의도가 담길 수 있어요. 필요 없는 줄바꿈이라면, 오해하지 않게 깔끔하게 관리해주세요

Suggested change
public static void main(String[] args) {
new RacingController().run(new RandomNumberGenerator());
}
public static void main(String[] args) {
new RacingController().run(new RandomNumberGenerator());
}


}
35 changes: 35 additions & 0 deletions src/main/java/controller/RacingController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package controller;

import domain.Car;
import domain.Cars;
import domain.Racing;
import domain.NumberGenerator;
import view.InputView;
import view.OutputView;

public class RacingController {

Racing racing;
Cars carList;
Cars winnerList;
int RoundNumber;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Controller에 변경 가능한 형태의 상태(변수)가 존재하네요!
서로 다른 메서드에서 공용으로 사용 되기 때문에 이런 구조가 나온 것 같아요.

run()에서 메서드 내부에서만 사용 되는 변수도 제거 해볼 수 있고, playRace()에서도 사용 되는 변수는 호출할 때 필요한 값을 argument 전달하여 불필요한 상태 공유를 제거 할 수 있을 것 같아요.

메서드 내부에서만 사용 되는 변수도 제거

Cars winners = racing.findWinners();
OutputView.printWinners(winners.getCars());

인자로 넘겨 의미 전달하기

public void playRace(Cars cars, int roundNumber)

이렇게 줄여보면, RacingController는 상태가 없이도 정상적으로 run()을 실행 할 수 있어요.
선언한 변수들은 RacingController의 상태변수가 아니라 run()에서만 필요한 값이었던 것 같아요.


지환님이 작성해주셨던 객체의 변수를 인스턴스 변수라고도 불러요.
객체지향 관점에선 하나의 클래스에서 너무 많은 인스턴스 변수가 있는 것을 지양합니다.
특히 공유 되는 자원이면 더더욱 기피해야 합니다.

왜 인스턴스 변수를 줄이는 방향으로 설계 하는지, 인스턴스 변수는 어떤 의미를 가지는지 한번 고민해보세요!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

좋은 리뷰 감사합니다! 늘 공용으로 사용하는 변수가 많아지면 메서드 매개변수 관리가 어려워져서
습관적으로 인스턴스 변수로 선언했는데 객체지향에선 지양해야 하는군요...

왜 공유 되는 자원일 수록 인스턴스 변수를 기피해야 하는지 제 나름대로 고민한 결론은
인스턴스 변수로 선언하고 여러 메서드에서 해당 변수를 사용하게 되면 해당 인스턴스
변수가 어디서 어떻게 사용되고 있는지 파악하기 힘들어져 추후 코드를 수정하거나 확장할 때
해당 변수를 고려하기 매우 힘들어지기 때문인 것 같았어요. 변수의 안정성도 떨어질 것 같고요

매개변수로 전달하니 변수가 어떤 메서드에 어떻게 쓰이는지 비교적 명확하게 보이기 때문에
훨씬 코드를 파악하기 좋은 코드가 된 것 같습니다!


public void run(NumberGenerator numberGenerator) {
carList = Cars.create(InputView.getCarNames(), numberGenerator);
RoundNumber = InputView.getRoundNumber();
racing = new Racing(carList);

OutputView.printResult();
playRace();

winnerList = racing.findWinners();
OutputView.printWinners(winnerList.getCars());
}

public void playRace() {
for (int i = 0; i < RoundNumber; i++) {
racing.playRound();
OutputView.printProcess(carList.getCars());
}
}
}
34 changes: 34 additions & 0 deletions src/main/java/domain/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package domain;

public class Car {

private static final int CRITICAL_NUMBER_TO_MOVE = 4;

private final String name;
private int distance;
private NumberGenerator numberGenerator;

public Car(String name, NumberGenerator numberGenerator) {
this.name = name;
this.distance = 0;
this.numberGenerator = numberGenerator;
}

public void move() {
if (numberGenerator.generateNumber() >= CRITICAL_NUMBER_TO_MOVE) {
distance++;
}
}

public boolean isInPosition(int position) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

값이 같은지를 비교하는 메서드군요.
이름이 기능을 설명하지 못하는 것 같아요.
대중적으로 isInPosition이라는 네이밍을 보았을 때, 혹은 Car객체를 사용하는 다른 개발자가 "isInPosition 이런 메서드도 제공하네?" 하고 사용 하였을 때 혼동이 오진 않을지 생각보시면 적절한 이름을 찾는데 도움이 된답니다!

return distance == position;
}

public String getName() {
return name;
}

public int getDistance() {
return distance;
}
}
49 changes: 49 additions & 0 deletions src/main/java/domain/Cars.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package domain;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class Cars {

private List<Car> cars;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

가능한 곳은 최대한 불변을 유지해주세요.

Suggested change
private List<Car> cars;
private final List<Car> cars;

불변을 유지하려는 이유는 무엇일까요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

불변을 유지해야 하는 이유는 해당 변수가 잘못된 값이나 객체로 재할당되지 않게 하기 위함이라고 생각합니다!
의식적으로 늘 체크하고 불변을 유지해야 하는 변수는 잘 설정해야겠어요


private Cars(List<Car> cars) {
this.cars = cars;
}

public static Cars create(String[] carNames, NumberGenerator numberGenerator) {
List<Car> newCars = new ArrayList<Car>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
List<Car> newCars = new ArrayList<Car>();
List<Car> newCars = new ArrayList<>();

for (String carName : carNames) {
newCars.add(new Car(carName, numberGenerator));
}
return new Cars(newCars);
}

public void move() {
for (Car car : cars) {
car.move();
}
}

public int getMaxDistance() {
int maxDistance = 0;
for (Car car : cars) {
maxDistance = Math.max(maxDistance, car.getDistance());
}
return maxDistance;
}

public Cars findCarsInPosition(int position) {
List<Car> carsInPosition = new ArrayList<>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

사용하지 않는 변수는 과감하게 지워두세요!

Suggested change
List<Car> carsInPosition = new ArrayList<>();

return new Cars(
cars.stream()
.filter(car -> car.isInPosition(position))
.collect(Collectors.toList())
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stream을 잘 활용 하셨네요!

하나의 라인에서 여러 동작이 이루어져서 depth가 깊어졌네요.
괄호 안에서 여러 연산이 이루어지면 가독성이 많이 떨어져요. 글은 왼쪽에서부터 읽지만, 코드 흐름(연산)은 가장 안쪽의 괄호에서 이루어지잖아요!

Suggested change
return new Cars(
cars.stream()
.filter(car -> car.isInPosition(position))
.collect(Collectors.toList())
);
List<Car> carsInPosition = cars.stream()
.filter(car -> car.isInPosition(position))
.collect(Collectors.toList());
return new Cars(carsInPosition);

이렇게 분리해서 적용하면 좋아보여요! 이름을 주어서 stream 연산이 어떤 역할을 수행 하는지도 표현 할 수 있겠죠?

}

public List<Car> getCars() {
return cars;
}
Comment on lines +49 to +68

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

}
7 changes: 7 additions & 0 deletions src/main/java/domain/NumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package domain;

public interface NumberGenerator {

int generateNumber();

}
19 changes: 19 additions & 0 deletions src/main/java/domain/Racing.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package domain;

public class Racing {

private final Cars carList;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

사소하지만, 변수이름에 Collection 구현체 담지 마세요!
나중에 Set으로 수정하면 이름도 같이 바꿔야 해서요...!

Suggested change
private final Cars carList;
private final Cars cars;


public Racing(Cars carList) {
this.carList = carList;
}

public void playRound() {
carList.move();
}

public Cars findWinners() {
return carList.findCarsInPosition(carList.getMaxDistance());
}

}
12 changes: 12 additions & 0 deletions src/main/java/domain/RandomNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package domain;

import java.util.Random;

public class RandomNumberGenerator implements NumberGenerator {

@Override
public int generateNumber() {
return new Random().nextInt(10);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

new Random()을 매번 선언하면 불필요한 자원 낭비가 될 수 있어요.
상수로 선언하여 한번만 생성해서 성능을 좀 더 높일 수 있답니다!

Scanner를 선언 하신 것 처럼요!

}

}
17 changes: 17 additions & 0 deletions src/main/java/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package view;

import java.util.Scanner;

public class InputView {

private static Scanner scanner = new Scanner(System.in);

public static String[] getCarNames() {
return scanner.nextLine().split(",");
}

public static int getRoundNumber() {
return Integer.parseInt(scanner.nextLine());
}

}
40 changes: 40 additions & 0 deletions src/main/java/view/OutputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package view;

import domain.Car;
import java.util.ArrayList;
import java.util.List;

public class OutputView {

public static void printResult() {
System.out.println("실행 결과");
}

public static void printProcess(List<Car> cars) {
for (Car car : cars) {
System.out.println(formmatCarInfo(car));
}
System.out.println();
}

public static String formmatCarInfo(Car car) {
StringBuilder formatted;
formatted = new StringBuilder(car.getName() + " : ");
for (int i = 0; i < car.getDistance(); i++) {
formatted.append("-");
}
return formatted.toString();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

String의 함수를 잘 활용하면 이렇게도 줄여볼 수 있어요

Suggested change
StringBuilder formatted;
formatted = new StringBuilder(car.getName() + " : ");
for (int i = 0; i < car.getDistance(); i++) {
formatted.append("-");
}
return formatted.toString();
return car.getName() + " : " + "-".repeat(car.getDistance());

}

public static void printWinners(List<Car> winners) {
List<String> winnerNames = new ArrayList<>();
for (Car winner : winners) {
winnerNames.add(winner.getName());
}
System.out.println(formattWinnerNames(winnerNames) + "가 최종 우승했습니다.");
}

public static String formattWinnerNames(List<String> cars) {
return cars.toString().replace("[", "").replace("]", "");
}
Comment on lines +37 to +41

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

이렇게도 줄여 볼 수 있어요!
stream을 잘 활용하면 굉장히 강력해 보이지 않나요?

Suggested change
public static void printWinners(List<Car> winners) {
List<String> winnerNames = new ArrayList<>();
for (Car winner : winners) {
winnerNames.add(winner.getName());
}
System.out.println(formatWinnerNames(winnerNames) + "가 최종 우승했습니다.");
}
public static String formatWinnerNames(List<String> cars) {
return cars.toString().replace("[", "").replace("]", "");
}
public static void printWinners(List<Car> winners) {
String winnerNames = winners.stream()
.map(Car::getName)
.collect(Collectors.joining(", "));
System.out.println(winnerNames + "가 최종 우승했습니다.");
}

}
17 changes: 9 additions & 8 deletions src/test/java/CarTest.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import org.junit.jupiter.api.Test;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

import 다시 돌려주세요...ㅠ


import domain.Car;

import static org.assertj.core.api.Assertions.*;

Expand All @@ -9,21 +10,21 @@ public class CarTest {

@Test
void testCarName() {
Car car = new Car("KIA");
Car car = new Car("KIA", new MovableNumberGenerator());

assertThat(car.getName()).isEqualTo("KIA");
}

@Test
void testCarMove() {
Car car = new Car("TestCar");
car.move(MOVE_FORWARD);
assertThat(car.getDistance()).isEqualTo(1);

Car car = new Car("TestCar", new MovableNumberGenerator());
car.move();
}

@Test
void testCarNotMove() {
Car car = new Car("TestCar");
car.move(NOT_MOVE - 1);
assertThat(car.getDistance()).isEqualTo(0);
Car car = new Car("TestCar", new NotMovableNumberGenerator());
car.move();
}
}
24 changes: 13 additions & 11 deletions src/test/java/GameTest.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@

/*
import domain.Car;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.*;

public class GameTest {

private static final int MOVE_FORWARD = 4;
private static final int NOT_MOVE = 3;

@Test
public void testGetWinnerList() {
Game game = new Game();
game.carList.add(new Car("A"));
game.carList.add(new Car("B"));
game.carList.add(new Car("C"));
Cars carList = Cars;
racing.carList.add(new Car("A", new MovableNumberGenerator()));
racing.carList.add(new Car("B", new NotMovableNumberGenerator()));
racing.carList.add(new Car("C", new MovableNumberGenerator()));

game.carList.get(0).move(MOVE_FORWARD);
game.carList.get(1).move(NOT_MOVE);
game.carList.get(2).move(MOVE_FORWARD);
racing.carList.get(0).move(MOVE_FORWARD);
racing.carList.get(1).move(NOT_MOVE);
racing.carList.get(2).move(MOVE_FORWARD);

game.makeWinnerList();
racing.makeWinnerList();
assertThat(game.winnerList).containsOnly(game.carList.get(0), game.carList.get(2));
}

}
*/
12 changes: 12 additions & 0 deletions src/test/java/MovableNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import domain.NumberGenerator;

public class MovableNumberGenerator implements NumberGenerator {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

전략패턴을 활용하셨군요!👍


public static final int MOVABLE_NUMBER = 4;

@Override
public int generateNumber() {
return MOVABLE_NUMBER;
}

}
12 changes: 12 additions & 0 deletions src/test/java/NotMovableNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import domain.NumberGenerator;

public class NotMovableNumberGenerator implements NumberGenerator {

public static final int NOT_MOVABLE_NUMBER = 3;

@Override
public int generateNumber() {
return NOT_MOVABLE_NUMBER;
}

}