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

java-racingcar(songpang) #3

Open
wants to merge 63 commits into
base: songpang
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
0a5d963
docs: 기능 구현 목록 및 클래스 정리
chae-heechan Mar 4, 2021
216cb6d
test: 입력 및 유효성 검사 클래스 테스트 케이스 작성
chae-heechan Mar 4, 2021
ae04e19
feat: Receiver 클래스 구현
chae-heechan Mar 4, 2021
a6e8c0f
feat: Validator 인터페이스 생성
chae-heechan Mar 4, 2021
804fe2d
docs: 클래스 분류 재정리
chae-heechan Mar 4, 2021
a02977d
feat: Message인터페이스 생성
chae-heechan Mar 4, 2021
3ac806d
test: validator클래스 구조 변경에 따른 테스트 변경
chae-heechan Mar 9, 2021
a973407
feat: 출력 메세지 인터페이스 작성
chae-heechan Mar 9, 2021
78bb06d
refactor: 메세지 호출 메서드 삭제, 입력 예외 추가
chae-heechan Mar 9, 2021
bb9c87b
feat: 프린터 클래스 구현
chae-heechan Mar 9, 2021
07f6628
feat: 게임 시작 기능 추가
chae-heechan Mar 9, 2021
cdfc826
docs: 클래스 및 메서드 분류 재정리
chae-heechan Mar 9, 2021
0ff13cc
feat: Car클래스 구현
chae-heechan Mar 9, 2021
6519379
feat: Message클래스 구현
chae-heechan Mar 9, 2021
7aaac17
feat: Validator클래스 구현
chae-heechan Mar 9, 2021
b115436
refactor: receiveLine 메서드 삭제
chae-heechan Mar 9, 2021
8d840f7
feat: 게임 실행 부분 구현
chae-heechan Mar 9, 2021
74d8054
feat: 난수 생성 기능 구현
chae-heechan Mar 9, 2021
02b5186
style: overSizeCharacters 메서드 이름 변경
chae-heechan Mar 10, 2021
6954307
test: Paramiterizedtest로 변경
chae-heechan Mar 10, 2021
305ea0d
feat: 게임 내 출력 메서드 추가
chae-heechan Mar 10, 2021
fc3b773
test: Receiver 테스트 케이스 작성
chae-heechan Mar 10, 2021
e0fe4fa
docs: Paramiterized 테스트 사용하기 위해 testCompile 부분 추가
chae-heechan Mar 10, 2021
2d34588
style: overSizeCharacters 메서드 이름 변경
chae-heechan Mar 10, 2021
e1c98f3
style: 불필요한 라인 제거
chae-heechan Mar 10, 2021
38feeaa
test: Car 테스트 케이스 작성
chae-heechan Mar 10, 2021
c47f82f
test: GamePlayer 테스트 케이스 작성
chae-heechan Mar 10, 2021
2c62d0c
test: Generator 테스트 케이스 작성
chae-heechan Mar 10, 2021
838a38b
test: Message 테스트 케이스 작성
chae-heechan Mar 10, 2021
1a10b46
test: Printer 테스트 케이스 작성
chae-heechan Mar 10, 2021
d9fbd3a
style: overSizeCharacters 메서드 이름 변경
chae-heechan Mar 10, 2021
932e5fe
feat: 게임 내 출력 메서드 추가
chae-heechan Mar 10, 2021
ed3d8ac
test: Receiver 테스트 케이스 작성
chae-heechan Mar 10, 2021
e0b9f8d
feat: 게임 내 출력 메서드 추가
chae-heechan Mar 10, 2021
0b4dd36
refactor: 출력 부분 printer 객체에서 처리하도록 변경
chae-heechan Mar 10, 2021
7bb1ace
docs: empty 파일 삭제
chae-heechan Mar 10, 2021
c7d7fd1
refactor: 불필요한 public 제거
songpang Mar 20, 2021
66dd3b6
refactor: 메소드 및 변수 네이밍 수정
songpang Mar 20, 2021
a595c43
refactor: 위험한 접근 제어자 수정 및 불필요한 코드 제거
songpang Mar 20, 2021
0852319
refactor: 위와 같음
songpang Mar 20, 2021
422c3da
refactor: assertThat actual과 expected의 오용 수정
songpang Mar 20, 2021
8d80c12
refactor: 절차지향적인 코드 수정
songpang Mar 21, 2021
645be80
refactor: 이번 미션에서 불필요한 생성자 제거
songpang Mar 21, 2021
302139e
refactor: 불필요한 코드제거 및 획일성을 위한 상수 설정
songpang Mar 21, 2021
93dde0d
refactor: Printer클래스의 역할 제한 및 관련 메소드 이동
songpang Mar 21, 2021
bfb6277
refactor: Car 클래스에 maxNumber를 확인하는 역할 부여
songpang Mar 21, 2021
b87577f
refactor: MessageInterface 삭제 및 Message클래스 내부 Hashmap에서 enum으로 변경
songpang Mar 25, 2021
9a31667
refactor: 이전 커밋의 변경사항 Validator Class에 적용
songpang Mar 25, 2021
51d46b3
refactor: GamePlayer Class 위의 커밋 내용 적용
songpang Mar 25, 2021
5d7064e
refactor: Printer Class의 Progress bar 만드는 메소드 Car Class로 위임
songpang Mar 25, 2021
b3444f0
refactor: 사용하지 사용하지 않거나 불필요한 interface 삭제
songpang Mar 25, 2021
978faee
refactor: Winner Class 생성, Gameplayer Class 역할 분리
songpang Mar 25, 2021
eb18b53
refactor: Car Class에 자신의 position을 Progress bar로 리턴하는 역할 부여
songpang Mar 26, 2021
021f98d
refactor: README 수정
songpang Mar 26, 2021
c296369
refactor: 컨벤션 수정 및 구현체를 인터페이스로 변경
songpang Mar 28, 2021
e577df7
refactor: 메소드 역할 분리
songpang Mar 28, 2021
560f251
refactor: 제한자 및 컨벤션 수정
songpang Mar 28, 2021
8f84168
Update src/main/java/domain/Validator.java
songpang Mar 28, 2021
0428c22
Merge branch 'songpang' of https://github.com/songpang/java-racingcar…
songpang Mar 28, 2021
ed92c1f
Update src/main/java/domain/Winner.java
songpang Mar 28, 2021
83eaf8c
refactor: 접근 제한자 설정 및 변수명 변경
songpang Mar 28, 2021
54109bd
refactor: 실패 케이스 삭제
songpang Mar 28, 2021
506b630
Merge branch 'songpang' of https://github.com/songpang/java-racingcar…
songpang Mar 28, 2021
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
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,73 @@
# 미션 - 자동차 경주 게임

## 📋 기능 구현 목록
- 사용자 입력 요구문 출력
- 사용자 입력
- 예외 처리
- 플레이어 생성

- 경주 게임 실행
- 무작위 수 생성
- 4이상 인지 비교
- 1초 간격두고 라운드 결과 출력

- 우승자 판별
- 우승자 출력

## 🚬 클래스와 메서드?
- Application

- Receiver
- receiveName
- receiveNumber

- Printer
- printProgress
- printWinner
- printGeneralMessage
- printExceptionMessage
- printMessages

- GamePlayer
- run
- judgeAndMove
- inputNames
- inputNumber
- makeCarList
- launchAllRound

- Generator
- generateRandomNumber

- Car
- getPosition
- getName
- moveForward
- isMaxNumber
- isOverMaxNumber
getProgressWithSymbol

- Validate
- validateName(s)
- inputNothing(s)
- inputCommaInARow(s)
- inputCharactersOtherThanName(s)
- startWithComma(s)
- endWithComma(s)
- over5Characters(s)
- inputSameName(s))
- validateNumber(s)

- Winner
- makeWinnerToString
- checkWhoIsWinner
- initWinner

- Message
- selectMessageFromGeneral
- selectMessageFromException


## 🚀 기능 요구사항

- 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다.
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repositories {

dependencies {
testCompile("org.assertj:assertj-core:3.14.0")
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testCompile('org.junit.jupiter:junit-jupiter:5.6.0')
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}

Expand Down
8 changes: 8 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import domain.GamePlayer;

public class Application {
public static void main(String[] args){
GamePlayer gamePlayer = new GamePlayer();
gamePlayer.run();
}
}
29 changes: 28 additions & 1 deletion src/main/java/domain/Car.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,32 @@ public Car(String name) {
this.name = name;
}

// 추가 기능 구현
public int getPosition() {
return this.position;
}

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

public void moveForward() {
this.position++;
}

public boolean isMaxNumber(int maxNumber) {
return this.position == maxNumber;
}

public boolean isOverMaxNumber(int maxNumber) {
return this.position > maxNumber;
}

public String getProgressWithSymbol() {
String progress = "";
for(int i = 0;i < this.position;i++) {
progress += "-";
}

return progress;
}
Comment on lines +31 to +38
Copy link
Member

Choose a reason for hiding this comment

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

현재 위치를 "-" 로 표현된다는건 뷰의 관심사인것 같아요.
현재의 콘솔 환경에선 "-", 웹 환경이라면 자동차의 위치에 맞는 이미지가 될수도 있지 않을까요?

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

import io.Message;
import io.Printer;
import io.Receiver;

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

public class GamePlayer {
Copy link
Member

Choose a reason for hiding this comment

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

run을 제외한 모든 메서드들이 외부에서 호출될 필요가 없어보입니다.
public 접근 제어자로 설정하는 것이 괜찮을까요?

Copy link
Member

Choose a reason for hiding this comment

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

GamePlayer가 생각보다 많은 책임을 갖고 있는것 같아요.
차들을 생성해 내기도하고, 전진 가능한지를 판단하기도하고, 우승자를 찾기도하고 UI에 관련된 임무를 수행하기도 하네요!

클래스를 좀 더 분리해보는건 어떨까요? 🤔

Copy link
Member

Choose a reason for hiding this comment

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

대부분의 메소드의 접근 제한자가 default인데 의도하신 건가요?

[Java] 접근 제한자

Copy link
Member Author

Choose a reason for hiding this comment

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

처음에 public으로 설정했다가 동민님이 외부에서 사용하지 않는데 굳이 public을 사용한 이유가 있냐고 피드백을 주셔서 이에 대해 고민해 본 이후 default로 변경했습니다!

Copy link
Member

Choose a reason for hiding this comment

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

아마 클래스 내부에서만 사용되는 메소드를 public으로 설정해서 그런 피드백을 주지 않았나 생각이 되네요 🙂

클래스 내부에서만 사용되는 메소드는 private, 외부에서 메세지를 전달받는 메소드는 public으로 설정하는 것이 좋을 것 같아요.

private static final int WINNER_CONDITION = 4;

private final Printer printer;
private final Receiver receiver;
private final Generator generator;

public GamePlayer() {
this.printer = new Printer();
this.receiver = new Receiver();
this.generator = new Generator();
}

void moveAfterJudgement(Car car, int randomNumber) {
if (judgeToMove(randomNumber)) {
car.moveForward();
}
}

private boolean judgeToMove(int randomNumber) {
return randomNumber >= WINNER_CONDITION;
}

List<Car> inputNames() {
String messageCode = Message.GeneralMessages.INPUT_NAMEOFCAR.getMessage();
printer.printMessages(messageCode);
List<String> names = new ArrayList<>(Arrays.asList(receiver.receiveName()));
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
List<String> names = new ArrayList<>(Arrays.asList(receiver.receiveName()));
List<String> names = Arrays.asList(receiver.receiveName());

new ArrayList<>()를 안해줘도 괜찮습니다.


return makeCarList(names);
}

int inputNumber() {
String messageCode = Message.GeneralMessages.INPUT_COUNT.getMessage();
printer.printMessages(messageCode);

return receiver.receiveNumber();
}

List<Car> makeCarList(List<String> names) {
Copy link
Member

Choose a reason for hiding this comment

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

List<Car> 라는 return type으로 이미 List임을 알 수 있지 않을까요?

의미 있게 구분하라.
구분 짓지 못하는 변수명은 의미가 없다. 예를 들어 ProductInfo와 ProductData의 개념은 분리 되는가?
또 변수 뒤에 타입을 작성하는 것도 의미가 없다면 좋지 않다. NameString과 Name이 다른 점이 무엇인가?

- Clean Code

makeCars 정도로 표현 할 수 있을 것 같아요 🙂

List<Car> cars = new ArrayList<>();

for (int i = 0; i < names.size(); i++) {
cars.add(new Car(names.get(i)));
}

return cars;
}

void launchAllRound(List<Car> cars, int countRound) {
String messageCode = Message.GeneralMessages.DEFAULT_SPACE.getMessage();

for (int i = 0; i < countRound; i++) {
for (Car car : cars) {
moveAfterJudgement(car, generator.generateRandomNumber());
printer.printProgress(car.getName(), car.getProgressWithSymbol());
}
printer.printMessages(messageCode);
}
}

public void run() {
String messageCode = Message.GeneralMessages.OPERATION_RESULT.getMessage();
List<Car> cars = inputNames();
int countRound = inputNumber();

printer.printMessages(messageCode);
launchAllRound(cars, countRound);

List<Car> winner = Winner.checkWhoIsWinner(cars);
printer.printWinner(Winner.makeWinnerToString(winner));
}
}
8 changes: 8 additions & 0 deletions src/main/java/domain/Generator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package domain;

public class Generator {
private final int MAX_LIMIT_NUMBER = 10; //default value
public int generateRandomNumber() {
return (int) ((Math.random() * 10000) % MAX_LIMIT_NUMBER);
Copy link
Member

Choose a reason for hiding this comment

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

JAVA API의 Random 클래스를 사용하면 난수 생성을 쉽게 할 수 있습니다.

Copy link
Member Author

Choose a reason for hiding this comment

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

굳이 Random클래스를 사용하여 객체를 추가적으로 생성해야 한다는 것에 의문을 품어 Random 클래스를 사용하지 않았는데 지금와서 생각해보니 성능차이도 없거니와 모두가 주로 사용하는 클래스를 사용해야 가독성이 높아진다는 것을 깨달았습니다.

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

import io.Message;
import io.Printer;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

public class Validator {
private static final int MAX_NAME_SIZE = 5;
private static final String VALID_NUMBER = "^[0-9]+$";
private static final String COMMA_IN_ROW = "^.*(,,).*+$";
private static final String CHARACTER = "^[a-zA-Z,]+$";
private static final Character COMMA = ',';
private static final String NOTHING = "";

private final Printer printer;

public Validator() {
printer = new Printer();
}

public boolean validateName(String s) {
Copy link
Member

Choose a reason for hiding this comment

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

약어를 사용하기보단 적절한 이름을 사용해주세요!

return inputNothing(s)
&& inputCommaInARow(s)
&& inputCharactersOtherThanName(s)
&& startWithComma(s)
&& endWithComma(s)
&& overSizeCharacters(s)
&& inputSameName(s);
}

public boolean isValidNumber(String s) {
return s.matches(VALID_NUMBER);
}

public boolean inputNothing(String s) {
String messageCode = Message.ExceptionMessages.INPUT_NOTHING.getMessage();

if (s.equals(NOTHING)) {
printer.printMessages(messageCode);
return false;
}
return true;
}

public boolean inputCommaInARow(String s) {
String messageCode = Message.ExceptionMessages.INPUT_COMMA_IN_A_ROW.getMessage();

if (Pattern.matches(COMMA_IN_ROW, s)) {
printer.printMessages(messageCode);
return false;
}
return true;
}

public boolean startWithComma(String s) {
String messageCode = Message.ExceptionMessages.START_WITH_COMMA.getMessage();

if (s.charAt(0) == COMMA) {
printer.printMessages(messageCode);
return false;
}
return true;
}

public boolean endWithComma(String s) {
String messageCode = Message.ExceptionMessages.END_WITH_COMMA.getMessage();

if (s.charAt(s.length() - 1) == COMMA) {
printer.printMessages(messageCode);
return false;
}
return true;
}

public boolean inputCharactersOtherThanName(String s) {
String messageCode = Message.ExceptionMessages.INPUT_CHARACTERS_OTHER_THAN_NAME.getMessage();

if (!Pattern.matches(CHARACTER, s)) {
printer.printMessages(messageCode);
return false;
}
return true;
}

public boolean inputSameName(String s) {
String messageCode = Message.ExceptionMessages.INPUT_SAME_NAME.getMessage();
List<String> carNames = Arrays.asList(s.split(","));
Copy link
Member

Choose a reason for hiding this comment

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

","를 상수화 하여 의미를 표현해줄수 있지 않을까요?

int sizeOfNameList = carNames.size();

for (int i = 0; i < sizeOfNameList; i++) {
if (carNames.subList(i + 1, sizeOfNameList).contains(carNames.get(i))) {
printer.printMessages(messageCode);
return false;
}
}
return true;
}

public boolean overSizeCharacters(String s) {
String messageCode = Message.ExceptionMessages.OVER_SIZE_CHARACTERS.getMessage();
String[] splitName = s.split(",");

for (String i : splitName)
if (i.length() > MAX_NAME_SIZE) {
printer.printMessages(messageCode);
return false;
}
return true;
}

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

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

public class Winner {
public static String makeWinnerToString(List<Car> cars) {
StringBuilder winner = new StringBuilder(cars.get(0).getName());

if (cars.size() > 1) {
for (int i = 1; i < cars.size(); i++) {
winner.append(", ").append(cars.get(i).getName());
}
}

return winner.toString();
}
Comment on lines +7 to +17
Copy link
Member

Choose a reason for hiding this comment

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

Winner가 우승자가 컴마로 이어진다는("a,b") 사실을 알 필요가 있을까요?
Winner의 책임은 우승자가 누군지만 알려줘도 괜찮지 않을까요?
비지니스 로직과 뷰로직을 분리해봅시다!


public static List<Car> checkWhoIsWinner(List<Car> cars) {
List<Car> winner = new ArrayList<>();
int maxNumber = 0;

for (Car car : cars) {
if(car.isMaxNumber(maxNumber)){
winner.add(car);
}
if (car.isOverMaxNumber(maxNumber)) {
maxNumber = initWinner(winner, car);
}
}

return winner;
}

private static int initWinner(List<Car> winner, Car car) {
int maxNumber = car.getPosition();
winner.clear();
winner.add(car);

return maxNumber;
}
}
Empty file removed src/main/java/empty.txt
Empty file.
Loading