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

[5단계] 자동차 리팩토링 리뷰 부탁듣립니다 #2083

Merged
merged 1 commit into from
Mar 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/main/java/new_racingcar/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# [4단계] 레이싱카 정리
# [5단계] 레이싱카 리팩토링

## 이전 3단계 요구사항
## 3단계 요구사항
- 초간단 자동차 경주 게임을 구현한다.
- 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다.
- 사용자는 몇 대의 자동차로 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
Expand All @@ -13,6 +13,11 @@
- 자동차 이름은 쉼표(,)를 기준으로 구분한다.
- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다. 우승자는 한명 이상일 수 있다.

## 5단계 리팩토링 요구사항
- 핵심 비지니스 로직을 가지는 객체를 domain 패키지, UI 관련한 객체를 view 패키지에 구현한다.
- MVC 패턴 기반으로 리팩토링해 view 패키지의 객체가 domain 패키지 객체에 의존할 수 있지만, domain 패키지의 객체는 view 패키지 객체에 의존하지 않도록 구현한다.
- 테스트 가능한 부분과 테스트하기 힘든 부분을 분리해 테스트 가능한 부분에 대해서만 단위 테스트를 진행한다.

## 프로그래밍 3단계 요구사항
- 모든 로직에 단위 테스트를 구현한다. 단, UI(System.out, System.in) 로직은 제외
- 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.
Expand Down Expand Up @@ -47,7 +52,7 @@
- [X] 라운드마다 결과저장
- [X] 레이스 종료 후 결과 출력

## 추가 요구사항
## 4단계, 추가 요구사항
- [X] 자동차 이름을 받는다
- [X] , 구분으로 여러대의 이름을 한번에 받음
- [X] 자동차의 이름은 최대 5글자
Expand All @@ -56,6 +61,10 @@
- [X] 최대한 주행한 자동차 구하기
- [X] UI, 도메인을 패키지로 구분

## 5단계, 리팩토링 요구사항
- 모든 원시값과 문자열을 포장한다 (객체화)
- 불변 객체로 만든다

## 변경된 요구사항으로 없어진 내용
- [X] 경주에 참가할 자동차 수를 입력 받는다
- [X] 1명 이 성공 확인
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/new_racingcar/controller/RacingController.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package new_racingcar.controller;

import new_racingcar.domain.Round;
import new_racingcar.domain.RoundRecord;
import new_racingcar.service.GrandPrix;
import new_racingcar.view.InputView;
import new_racingcar.view.ResultView;
Expand All @@ -15,9 +15,9 @@ public void run() {
int turnCount = inputView.inputTurn();

GrandPrix grandPrix = new GrandPrix(carNames, turnCount);
List<Round> rounds = grandPrix.start();
List<RoundRecord> roundRecords = grandPrix.start();

ResultView resultView = new ResultView();
resultView.printGrandPrixRecords(rounds);
resultView.printGrandPrixRecords(roundRecords);
}
}
24 changes: 8 additions & 16 deletions src/main/java/new_racingcar/domain/Car.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,23 @@
import new_racingcar.constant.MsgConstants;

public class Car {
private String name;
private Name name;
private MoveStrategy moveStrategy;
private int distance;
private Distance distance;

public Car(String name, MoveStrategy moveStrategy) {
this(name, moveStrategy, 0);
this(new Name(name), moveStrategy, new Distance());
}

public Car(String name, MoveStrategy moveStrategy, int distance) {
isNameValid(name);
public Car(Name name, MoveStrategy moveStrategy, Distance distance) {
this.name = name;
this.distance = distance;
this.moveStrategy = moveStrategy;
}

public Car move() {
if (moveStrategy.isMoveable()) {
++distance;
distance = distance.addDistance();
}

return new Car(name, moveStrategy, distance);
Expand All @@ -31,7 +30,7 @@ public Car move(MoveStrategy strategy) {
setMoveStrategy(strategy);

if (moveStrategy.isMoveable()) {
++distance;
distance = distance.addDistance();
}

return new Car(name, moveStrategy, distance);
Expand All @@ -42,17 +41,10 @@ private void setMoveStrategy(MoveStrategy strategy) {
}

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

public int getDistance() {
return distance;
}

private void isNameValid(String name) {
if (name.length() > 5
|| name.trim().isEmpty()) {
throw new IllegalArgumentException(MsgConstants.CAR_NAME_ERROR_MESSAGE);
}
return distance.getDistance();
}
}
36 changes: 36 additions & 0 deletions src/main/java/new_racingcar/domain/Distance.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package new_racingcar.domain;

import java.util.Objects;

public class Distance {

Choose a reason for hiding this comment

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

원시값 wrapping 👍

private final int distance;

public Distance() {
this.distance = 0;
}

private Distance(int distance) {
this.distance = distance;
}

public Distance addDistance() {
return new Distance(distance + 1);
}

public int getDistance() {
return this.distance;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Distance distance1 = (Distance) o;
return getDistance() == distance1.getDistance();
}

@Override
public int hashCode() {
return Objects.hash(getDistance());
}
}
23 changes: 23 additions & 0 deletions src/main/java/new_racingcar/domain/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package new_racingcar.domain;

import new_racingcar.constant.MsgConstants;

public class Name {

Choose a reason for hiding this comment

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

요구사항 잘 반영해주셨습니다~

private String name;

public Name(String name) {
isNameValid(name);
this.name = name;
}

public String getName() {
return name;
}

private void isNameValid(String name) {
if (name.length() > 5
|| name.trim().isEmpty()) {
throw new IllegalArgumentException(MsgConstants.CAR_NAME_ERROR_MESSAGE);
}
}
}
50 changes: 32 additions & 18 deletions src/main/java/new_racingcar/domain/Round.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,46 @@
package new_racingcar.domain;

import java.util.List;
import java.util.stream.Collectors;
import new_racingcar.constant.MsgConstants;

import java.util.Objects;

public class Round {
private final Cars cars;
private int round;

public Round(Cars cars) {
this.cars = cars;
public Round(int round) {
isRoundCountVaild(round);
this.round = round;
}

public List<Car> getRoundInfo() {
return cars.getUnmodifiableCars();
private void isRoundCountVaild(int roundCount) {
if (roundCount < 1) {
throw new IllegalArgumentException(MsgConstants.ROUND_ERROR_MESSAGE);
}
}

public int getMaxDistance() {
return getRoundInfo().stream()
.mapToInt(Car::getDistance)
.max()
.getAsInt();
public Boolean isGameEnd() {
if (round > 0) {
nextRound();
return true;
}

return false;
}

public String getWinnerNames(int maxDistance) {
List<String> winners = getRoundInfo().stream()
.filter(c -> c.getDistance() == getMaxDistance())
.map(Car::getName)
.collect(Collectors.toList());
private void nextRound() {
--round;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Round round1 = (Round) o;
return round == round1.round;
}

return String.join(",", winners);
@Override
public int hashCode() {
return Objects.hash(round);
}
}
32 changes: 32 additions & 0 deletions src/main/java/new_racingcar/domain/RoundRecord.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package new_racingcar.domain;

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

public class RoundRecord {

Choose a reason for hiding this comment

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

좀 더 네이밍이 좋아졌군요.... ⚡

private final Cars cars;

public RoundRecord(Cars cars) {
this.cars = cars;
}

public List<Car> getRoundInfo() {
return cars.getUnmodifiableCars();
}

public int getMaxDistance() {
return getRoundInfo().stream()
.mapToInt(Car::getDistance)
.max()
.getAsInt();
}

public String getWinnerNames(int maxDistance) {
List<String> winners = getRoundInfo().stream()
.filter(c -> c.getDistance() == getMaxDistance())
.map(Car::getName)
.collect(Collectors.toList());

return String.join(",", winners);
}
}
27 changes: 11 additions & 16 deletions src/main/java/new_racingcar/service/GrandPrix.java
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
package new_racingcar.service;

import new_racingcar.domain.Round;
import new_racingcar.strategy.MoveOneStrategy;
import new_racingcar.constant.MsgConstants;
import new_racingcar.domain.Cars;
import new_racingcar.domain.Round;
import new_racingcar.strategy.MoveZeroStrategy;
import new_racingcar.domain.RoundRecord;

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

public class GrandPrix {
private Cars cars;
private List<Round> rounds = new ArrayList<>();
private List<RoundRecord> roundRecords = new ArrayList<>();

private int roundCount;
private Round round;

public GrandPrix(List<String> names, int roundCount) {
isRoundCountVaild(roundCount);
this.cars = new Cars(names, new MoveOneStrategy());
this.roundCount = roundCount;
this.round = new Round(roundCount);
}

private void isRoundCountVaild(int roundCount) {
if (roundCount < 1) {
throw new IllegalArgumentException(MsgConstants.ROUND_ERROR_MESSAGE);
}
}

public List<Round> start() {
for(int i = 0; i < roundCount; i++) {
public List<RoundRecord> start() {
while (round.isGameEnd()) {
Cars newCars = cars.run();
rounds.add(new Round(newCars));
roundRecords.add(new RoundRecord(newCars));
}

return rounds;
return roundRecords;
}


}
12 changes: 6 additions & 6 deletions src/main/java/new_racingcar/view/ResultView.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

import new_racingcar.constant.MsgConstants;
import new_racingcar.domain.Car;
import new_racingcar.domain.Round;
import new_racingcar.domain.RoundRecord;

import java.util.List;

public class ResultView {

public void printGrandPrixRecords(List<Round> rounds) {
public void printGrandPrixRecords(List<RoundRecord> roundRecords) {
System.out.println("");
System.out.println(MsgConstants.RESULT_RACING_END_MESSAGE);

rounds.stream()
roundRecords.stream()
.forEach(r -> printRound(r.getRoundInfo()));

printRacingWinner(rounds.get(rounds.size()-1));
printRacingWinner(roundRecords.get(roundRecords.size()-1));
}

private void printRound(List<Car> cars) {
Expand All @@ -34,8 +34,8 @@ private void printLab(String name, int distance) {
System.out.println(stringBuilder.toString());
}

private void printRacingWinner(Round round) {
String winners = round.getWinnerNames(round.getMaxDistance());
private void printRacingWinner(RoundRecord roundRecord) {
String winners = roundRecord.getWinnerNames(roundRecord.getMaxDistance());
System.out.println(winners + "가 최종 우승했습니다.");
}
}