Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f301985
구현할 기능 목록을 정리
sungchan12 Mar 29, 2026
10a498c
1. 경주할 자동차 이름을 ,기준으로 입력받는다.
sungchan12 Mar 29, 2026
e9062b9
1. 자동차 이름 공백/빈값 검증
sungchan12 Mar 29, 2026
7fb3d41
1. 0~9 사이 무작위 값 발생
sungchan12 Mar 29, 2026
7863cdf
1. 각 횟수별 실행 결과 출력
sungchan12 Mar 29, 2026
501ebde
Merge pull request #1 from sungchan12/feature/input
sungchan12 Mar 29, 2026
24cb63d
refactor: [input 값과 output결과 보여주는 책임을 분리]
sungchan12 Apr 5, 2026
7eaa067
feature: 경주 자동차 입력 기능 구현
sungchan12 Apr 5, 2026
b563773
feature: 경주 자동차 시도 횟수 입력 기능 추가
sungchan12 Apr 5, 2026
6dcddaa
refactor : 차 이름 검증은 Car, Cars가 직접 검증, 횟수 검증은 util이 아닌 validation이 담당하…
sungchan12 Apr 5, 2026
39dd8b9
feature : 시도 횟수 검증 기능 구현
sungchan12 Apr 5, 2026
a396893
refactor : 이동 최소 횟수를 상수로 변경
sungchan12 Apr 5, 2026
1de88aa
refactor : Car 자신의 이름을 검증하게 수정
sungchan12 Apr 5, 2026
3829a16
refactor : Cars 차 이름이 중복이 있는지 자신이 검증하도록 수정
sungchan12 Apr 5, 2026
5c4d720
refactor : 레이싱 결과 출력을 Output이 담당하게 수정
sungchan12 Apr 5, 2026
548efde
refactor : 레이싱 최종 결과 출력을 Output이 담당하게 수정
sungchan12 Apr 5, 2026
2809654
refactor : 레이싱 최종 결과 출력을 Output이 담당하게 수정
sungchan12 Apr 5, 2026
8a07464
refactor : util class 삭제
sungchan12 Apr 5, 2026
9386a79
feature : getCars 기능 추가
sungchan12 Apr 5, 2026
ff9702f
refactor : 최고 이동횟수, 우승자 찾는 함수 분리
sungchan12 Apr 5, 2026
6edddbb
refactor : input/output 분리 및 운영 책임으로 전환
sungchan12 Apr 5, 2026
cf14d0d
Todo 주석 제거
sungchan12 Apr 5, 2026
a353413
Merge pull request #2 from sungchan12/refactor/main
sungchan12 Apr 5, 2026
20906f2
리펙토링 계획서 추가
sungchan12 Apr 5, 2026
35ca1f4
Merge pull request #3 from sungchan12/refactor/main
sungchan12 Apr 5, 2026
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
35 changes: 35 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 기능 목록

## 입력
- 경주할 자동차 이름을 ,기준으로 입력받는다.
- 시도할 횟수를 입력받는다.

## 입력 검증
- 자동차 이름이 공백이거나 빈값이면 `IllegalArgumentException`을 발생시킨다.
- 자동차 이름이 5자를 초과하면 `IllegalArgumentException`을 발생시킨다.
- 자동차 이름이 중복되면 `IllegalArgumentException`을 발생시킨다.
- 시도할 횟수가 숫자가 아니면 `IllegalArgumentException`을 발생시킨다.
- 시도할 횟수가 1 미만이면 `IllegalArgumentException`을 발생시킨다.

## 자동차 이동
- 0~9 사이의 무작위 값을 발생시킨다.
- 무작위 값이 4 이상이면 전진한다.

## 출력
- 각 횟수별 실행 결과를 자동차 이름과 함께 출력한다.
- 최종 우승자를 출력한다.
- 우승자가 여러 명일 경우 ,로 구분하여 출력한다.

## 리팩토링
- `Input` : 사용자 입력을 받는 책임만 담당하도록 분리한다.
- `Output` : 경기 결과 및 우승자 출력 책임만 담당하도록 분리한다.
- `RunRacingGame` : 게임 흐름 제어 책임만 담당하도록 분리한다.
- `Utils` 클래스를 삭제하고 각 도메인이 자신의 책임을 직접 수행하도록 변경한다.

### 도메인은 자신이 검증
- `Car` : 자동차 이름의 유효성(공백, 길이)을 Car 스스로 검증한다.
- `Cars` : 자동차 이름 중복 여부를 Cars 스스로 검증한다.
- `validation` : 시도 횟수 검증은 입력 경계에서 담당한다.

### 이동횟수 관리
- 이동 기준값을 매직넘버로 관리한다.
3 changes: 2 additions & 1 deletion src/main/java/racingcar/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
public class Application {
public static void main(String[] args) {
// TODO: 프로그램 구현
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

템플릿 TODO 주석이 그대로 남아 있어 제출 코드의 완성도를 떨어뜨립니다. 구현이 완료된 상태라면 해당 TODO 주석을 제거해 주세요.

Suggested change
// TODO: 프로그램 구현

Copilot uses AI. Check for mistakes.
new RunRacingGame().run();
}
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

깃허브에 코드를 올릴때는 맨 마지막 라인에 공백이 들어와야 해요!

자료 참고바랍니당

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.

넵 감사합니다.

36 changes: 36 additions & 0 deletions src/main/java/racingcar/RunRacingGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package racingcar;


import java.util.ArrayList;
import java.util.List;
import racingcar.entity.Car;
import racingcar.entity.Cars;
import racingcar.view.racingCarInput;
import racingcar.view.racingCarOutput;

public class RunRacingGame {
private racingCarInput input = new racingCarInput();
private racingCarOutput output = new racingCarOutput();

public void run() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.

현재 run() 메소드는 너무 많은 일을 하고 있는 거 같아요 !
부분부분 메소드로 분리해보면 어떨까요 ?

String[] carNames = input.readCarNames();
int tryCount = input.readTryCount();

Cars cars = createCars(carNames);

System.out.println("\n실행 결과");
for (int i = 0; i < tryCount; i++) {
cars.moveAllCars();
output.printRaceResult(cars);
}
output.printWinner(cars.getWinners());
}

private Cars createCars(String[] carNames) {
List<Car> carList = new ArrayList<>();
for (String name : carNames) {
carList.add(new Car(name));
}
return new Cars(carList);
}
}
37 changes: 37 additions & 0 deletions src/main/java/racingcar/entity/Car.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package racingcar.entity;

import camp.nextstep.edu.missionutils.Randoms;

public class Car {
private final String name;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

final 선언을 한 이유가 있으신가요?

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.

이름의 값은 변하지 않는다와 혹시 모를 이름 변경이 되는 것을 막기 위해 final로 선언했습니다.

private int moveCnt;
private static final int MOVE_THRESHOLD = 4;

public Car(String name) {
validateName(this.name = name);
this.moveCnt = 0;
}

public String getName() {
return this.name;
}

public int getMoveCnt() {
return this.moveCnt;
}

public void setMoveCnt() {
if (Randoms.pickNumberInRange(0, 9) >= MOVE_THRESHOLD) {
this.moveCnt++;
}
}

private void validateName(String name) {
if (name.isBlank() || name.contains(" ")) {
throw new IllegalArgumentException("이름 공백 또는 빈값은 안됩니다.");
}
if (name.length() > 5) {
throw new IllegalArgumentException("5글자 초과했습니다.");
}
}
}
52 changes: 52 additions & 0 deletions src/main/java/racingcar/entity/Cars.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package racingcar.entity;

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

public class Cars {
private List<Car> cars;

public Cars(List<Car> cars) {
validateDuplicate(cars);
this.cars = cars;
Comment on lines +6 to +12
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

Cars 생성자가 ArrayList<Car>를 그대로 받아 필드에 저장하면 외부에서 전달된 리스트를 수정해 내부 상태가 예기치 않게 변할 수 있습니다. 타입은 List<Car>로 받도록 좁히고, 내부에서는 방어적 복사(예: new ArrayList<>(cars)) 및 final 필드로 불변성을 높여 주세요.

Suggested change
public class Cars {
private ArrayList<Car> cars;
public Cars(ArrayList<Car> cars) {
this.cars = cars;
import java.util.List;
public class Cars {
private final List<Car> cars;
public Cars(List<Car> cars) {
this.cars = new ArrayList<>(cars);

Copilot uses AI. Check for mistakes.
}
public List<Car> getCars() {
return cars;
}
public void moveAllCars() {
for (Car car : this.cars) {
car.setMoveCnt();
}
}

private int findMaxMoveCnt() {
int max = 0;
for (Car car : this.cars) {
if (car.getMoveCnt() > max) {
max = car.getMoveCnt();
}
}
return max;
}
Comment on lines +23 to +31
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

depth를 더 줄인다면 이렇게도 될 거 같아요 !
Java에서 기본적으로 제공해주는 유용한 메소드들도 많아서, 한 번 찾아보면 좋을 거 같아요 👍

Suggested change
private int findMaxMoveCnt() {
int max = 0;
for (Car car : this.cars) {
if (car.getMoveCnt() > max) {
max = car.getMoveCnt();
}
}
return max;
}
private int findMaxMoveCnt() {
int max = -1;
for (Car car : this.cars) {
max = Math.max(max, car.getMoveCnt();
}
return max;
}


public List<String> getWinners() {
int max = findMaxMoveCnt();
List<String> winners = new ArrayList<>();
for (Car car : this.cars) {
if (car.getMoveCnt() == max) {
winners.add(car.getName());
}
}
Comment on lines +36 to +40
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

스트림을 적용해보셔도 좋을 것 같아요 (스트림쓰면 코드가 더 간지나고 예뻐보여요)

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.

넵 한번 적용해보겠습니다!

return winners;
}

private void validateDuplicate(List<Car> cars) {
HashSet<String> set = new HashSet<>();
for (Car car : cars) {
if (!set.add(car.getName())) {
throw new IllegalArgumentException("이름 중복은 허용 안됩니다.");
}
}
}
}
15 changes: 15 additions & 0 deletions src/main/java/racingcar/validation/TryCountValidation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package racingcar.validation;

public class TryCountValidation {
public static int validate(String input) {
try {
int number = Integer.parseInt(input);
if (number < 1) {
throw new IllegalArgumentException("1 미만의 숫자는 입력할 수 없습니다.");
}
return number;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("숫자를 입력해야 합니다.");
}
}
}
15 changes: 15 additions & 0 deletions src/main/java/racingcar/view/racingCarInput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package racingcar.view;

import camp.nextstep.edu.missionutils.Console;
import racingcar.validation.TryCountValidation;

public class racingCarInput {
public String[] readCarNames() {
System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)");
return Console.readLine().split(",");
}
public int readTryCount() {
System.out.println("시도할 회수는 몇회인가요?");
return TryCountValidation.validate(Console.readLine());
}
}
19 changes: 19 additions & 0 deletions src/main/java/racingcar/view/racingCarOutput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package racingcar.view;

import java.util.List;
import racingcar.entity.Car;
import racingcar.entity.Cars;

public class racingCarOutput {

public void printRaceResult(Cars cars) {
for (Car car : cars.getCars()) {
System.out.println(car.getName() + " : " + "-".repeat(car.getMoveCnt()));
}
System.out.println();
}

public void printWinner(List<String> winners) {
System.out.println("최종 우승자 : " + String.join(", ", winners));
}
}