-
Notifications
You must be signed in to change notification settings - Fork 8
[자동차 경주] 표현록 미션 제출합니다. #3
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
base: main
Are you sure you want to change the base?
Changes from all commits
6bf339c
fa3f1d7
90d345a
c56d886
c2d2972
34ebfc9
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 |
|---|---|---|
| @@ -1 +1,89 @@ | ||
| # java-racingcar-precourse | ||
| # 2주차 미션 : 자동차 경주 | ||
| <details> | ||
| <summary>과제 세부 내용</summary> | ||
|
|
||
| ## 과제 | ||
| - 초간단 자동차 경주 게임을 구현한다. | ||
| - 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다. | ||
| - 각 자동차에 이름을 부여할 수 있다. 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다. | ||
| - 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다. | ||
| - 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다. | ||
| - 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우이다. | ||
| - 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한 명 이상일 수 있다. | ||
| - 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다. | ||
| - 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시킨 후 애플리케이션은 종료되어야 한다. | ||
| ### 입출력 | ||
| - 경주 할 자동차 이름(이름은 쉽표(,) 기준으로 구분) | ||
|
|
||
| pobi,woni,jun | ||
|
|
||
| - 시도할 횟수 | ||
|
|
||
| 5 | ||
|
|
||
| - 각 차수별 실행 결과 | ||
|
|
||
| pobi : -- | ||
| woni : ---- | ||
| jun : --- | ||
|
|
||
| - 단독 우승자 안내 문구 | ||
|
|
||
| 최종 우승자 : pobi | ||
|
|
||
| - 공동 우승자 안내 문구 | ||
|
|
||
| 최종 우승자 : pobi, jun | ||
|
|
||
| ### 실행 결과 예시 | ||
| 경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분) | ||
| pobi,woni,jun | ||
| 시도할 회수는 몇회인가요? | ||
| 5 | ||
|
|
||
| 실행 결과 | ||
| pobi : - | ||
| woni : | ||
| jun : - | ||
|
|
||
| pobi : -- | ||
| woni : - | ||
| jun : -- | ||
|
|
||
| pobi : --- | ||
| woni : -- | ||
| jun : --- | ||
|
|
||
| pobi : ---- | ||
| woni : --- | ||
| jun : ---- | ||
|
|
||
| pobi : ----- | ||
| woni : ---- | ||
| jun : ----- | ||
|
|
||
| 최종 우승자 : pobi, jun | ||
|
|
||
| </details> | ||
|
|
||
| ## 구현할 기능 목록 | ||
| ### Model | ||
| Car() // Class | ||
| - name | ||
| - count | ||
| - getName() | ||
| - getCount() | ||
| - forward() | ||
| - printResult() | ||
| ### Service | ||
| - sliceName() | ||
| - getWinner() | ||
| - checkInput() | ||
| ### View | ||
| - input() | ||
| - inputTimes() | ||
| - interimTally() | ||
| - outputResult() | ||
| - output() | ||
| ### Controller | ||
| - startRace() | ||
|
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. 저는 readme에 구현할 기능 목록을 글로만 작성했는데 메소드명과 함께 적는 것을 배워가요! |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| package racingcar; | ||
|
|
||
| import racingcar.controller.RaceController; | ||
|
|
||
| public class Application { | ||
| public static void main(String[] args) { | ||
| // TODO: 프로그램 구현 | ||
| RaceController.startRace(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package racingcar.controller; | ||
|
|
||
| import racingcar.model.Car; | ||
| import racingcar.service.CheckInput; | ||
| import racingcar.service.GetWinner; | ||
| import racingcar.service.SliceName; | ||
| import racingcar.view.RaceView; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class RaceController { | ||
| public static void startRace() { | ||
| String p = RaceView.inputCars(); | ||
| int times = CheckInput.checkNumber(RaceView.inputTimes()); | ||
|
|
||
| List<String> participant = CheckInput.checkName(p); | ||
|
|
||
| for (String s : participant) { | ||
| Car.cars.add(new Car(s)); | ||
| } | ||
|
|
||
| RaceView.outputResult(times); | ||
|
|
||
| RaceView.outputWinner(GetWinner.getWinner(Car.cars.stream(), GetWinner.getMax(Car.cars.stream()))); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package racingcar.model; | ||
|
|
||
| import camp.nextstep.edu.missionutils.Randoms; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| public class Car { | ||
| public static List<Car> cars = 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. cars 라는 리스트가 static으로 선언되면 데이터전송을 위한 단순 데이터객체라면 DTO에서 해야하지만, carlist를 관리하는 로직을 같이 분리해서 service에 넣는 것은 어떨까요? 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 name; | ||
| int count; | ||
|
|
||
|
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. 개인적으로 Car 객체 속 변수들은 private 접근 지정자를 사용하는게 어떨까 싶습니다 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.count = 0; | ||
| } | ||
|
|
||
| public String getName() { | ||
| return name; | ||
| } | ||
|
|
||
| public int getCount() { | ||
| return count; | ||
| } | ||
|
|
||
| public void forward() { | ||
| if (Randoms.pickNumberInRange(0, 9) >= 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. 자동차 이동로직은 자동자 객체에 포함시키기보다 비즈니스 로직이니 service에서 처리하는 것은 어떨까용? 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. 그리고 상수도 적극적으로 활용하면 유지보수성면에서 더 좋아질 듯 해용
Contributor
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. 저는 개인적으로 자동차 이동 로직이 자동차 객체에 있어도 된다고 생각해요! 자동차의 이동 자체는 프로그램의 비지니스 로직이라기 보다는 자동차라는 데이터에 내재된 비지니스 로직, 즉 행동이니 모델에 있는게 더 적절하다고 볼 수 있는 부분도 충분히 있다고 생각합니다 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. 흠 그렇게 생각하니까 그렇게 보는게 더 좋을 것 같기두 하네용 |
||
| count++; | ||
| } | ||
| } | ||
|
|
||
| public void printResult() { | ||
| System.out.println(name + " : " + "-".repeat(count)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package racingcar.service; | ||
|
|
||
| import java.util.List; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| public class CheckInput { | ||
| public static List<String> checkName(String s) { | ||
| if (s.isEmpty()) throw new IllegalArgumentException("자동차 이름들이 비어있습니다."); | ||
|
|
||
| if (s.split(",").length < 2) throw new IllegalArgumentException("자동차 이름이 부족하거나 구분자가 없습니다."); | ||
|
|
||
| List<String> l = SliceName.slice(s); | ||
|
|
||
| for (String p : l) { | ||
| if (Pattern.matches("\\s+", p)) throw new IllegalArgumentException("자동차 이름이 비어있습니다."); | ||
| if (p.length() > 5) throw new IllegalArgumentException("자동차 이름이 5자 초과입니다."); | ||
| } | ||
|
|
||
| return l; | ||
| } | ||
|
|
||
| public static int checkNumber(String s) { | ||
| if (s.isEmpty()) throw new IllegalArgumentException("횟수값이 비어있습니다."); | ||
|
|
||
| try { | ||
| Integer.parseInt(s); | ||
|
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.
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. 추가로 checkNumber에 대한 예외처리를 좀 분리하는 건 어떨까용? 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.
동의합니다. 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.
동의합니다. 어떤 예외를 처리하는지 메소드명에 추가해서 분리하면 가독성이 증가할 것 같은데 어떻게 생각하시나요? @Regyung |
||
| }catch (NumberFormatException e) { | ||
| throw new IllegalArgumentException("횟수값이 숫자가 아니거나 너무 많습니다."); | ||
| } | ||
|
|
||
| if (Integer.parseInt(s) <= 0) throw new IllegalArgumentException("횟수값이 양수가 아닙니다."); | ||
|
|
||
| return Integer.parseInt(s); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package racingcar.service; | ||
|
|
||
| import racingcar.model.Car; | ||
|
|
||
| import java.util.List; | ||
| import java.util.stream.Stream; | ||
|
|
||
| public class GetWinner { | ||
|
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. class명은 동사로 하지 않는게 좋아보입니다! 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. 동의합니다 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. 동의합니다 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 static int getMax(Stream<Car> c) { | ||
| return c.map(Car::getCount).max(Integer::compare).get(); | ||
| } | ||
|
|
||
| public static String getWinner(Stream<Car> c, int max) { | ||
| List<String> result = c.filter(car -> car.getCount() == max).map(Car::getName).toList(); | ||
| return String.join(", ", result); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package racingcar.service; | ||
|
|
||
| import java.util.Arrays; | ||
| import java.util.List; | ||
|
|
||
| public class SliceName { | ||
| public static List<String> slice(String s) { | ||
| return Arrays.asList(s.split(",")); | ||
| } | ||
| } | ||
|
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. 서비스 파일을 너무 쪼개놓은것 같다고 생각이 드는데,,, 제가 아직 잘 몰라서 그렇게 생각하는걸수도 있어요,,! 쪼개는게 더 좋은 방식이라면 알려주시면 감사하겠습니다! |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package racingcar.view; | ||
|
|
||
| import camp.nextstep.edu.missionutils.Console; | ||
| import racingcar.model.Car; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class RaceView { | ||
| public static String inputCars() { | ||
| System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); | ||
| return Console.readLine(); | ||
| } | ||
| public static String inputTimes() { | ||
| System.out.println("시도할 회수는 몇회인가요?"); | ||
| return Console.readLine(); | ||
| } | ||
|
|
||
| public static void interimTally(List<Car> c) { | ||
|
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는 사용자에게 데이터를 입력받고 출력하는 용도로만 사용하는 게 좋을 것 같아서 이 비즈니스로직은 service로 분리하는 것이 좋아보여용
Contributor
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. 뷰와 모델 사이에 직접적인 의존성을 갖는 것이 유지보수성 등을 이유로 MVC 패턴에는 바람직하지 않다고 생각합니다. 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. 이 부분은 저도 동의합니다 |
||
| for (Car car : c ) { | ||
| car.forward(); | ||
| car.printResult(); | ||
| } | ||
| System.out.println(); | ||
| } | ||
|
|
||
| public static void outputResult(int t) { | ||
| System.out.println("실행 결과"); | ||
| for (int i = 0; i < t; i++) { | ||
| RaceView.interimTally(Car.cars); | ||
| } | ||
| } | ||
|
|
||
| public static void outputWinner(String winner) { | ||
| System.out.println("최종 우승자 : " + winner); | ||
| } | ||
| } | ||
|
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. 저도 잘 모르는 입장에서 input output 뷰 파일 나누면 더 좋을 것 같아요..... 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. 저도 이번에 처음 MVC 패턴을 도입해서 Input과 Output을 나누어서 하긴 하였는데 Racing Game과 같은 소규모는 굳이 나눌 필요성을 잘 못느끼겠더라고요 저는 이정도의 규모의 코드는 View안에 전부 구현해도 될 것 같습니당 |
||
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.
구현할 기능 목록에 미리 변수와 메소드명을 미리 구성하는 것도 정리에 도움이 많이 될 것 같네요
메소드의 길이가 길어져서 메소드를 더 분리한다던가 할 땐 어떻게 하시나요?