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

Step 5 - 자동차경주(리팩토링) #5815

Open
wants to merge 14 commits into
base: sparcsjara
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions src/main/java/racingcar/Main.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package racingcar;

import racingcar.domain.RacingCarSimulator;
import racingcar.domain.movableStrategy.RandomMovableStrategy;
import racingcar.dto.RacingResultDTO;
import racingcar.ui.InputView;
import racingcar.ui.ResultView;
import racingcar.view.InputView;
import racingcar.view.ResultView;

import java.util.List;

Expand All @@ -12,8 +13,7 @@ public class Main {
public static void main(String[] args) {
List<String> carNames = InputView.inputCarNames();
int tryNumber = InputView.inputTryNumber();

RacingResultDTO result = RacingCarSimulator.simulate(carNames, tryNumber);
RacingResultDTO result = RacingCarSimulator.simulate(carNames, tryNumber, RandomMovableStrategy.getInstance());
Copy link
Member

Choose a reason for hiding this comment

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

이동 전략을 Main에서 주입하도록 개선해주셨네요 👍

ResultView.printRacingResult(result);
}
}
47 changes: 17 additions & 30 deletions src/main/java/racingcar/domain/CarRacing.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,33 @@
package racingcar.domain;

import racingcar.domain.movableStrategy.RandomMovableStrategy;
import racingcar.dto.RacingCarStatesDTO;
import racingcar.dto.RacingWrapResultDTO;
import racingcar.dto.RacingWrapResultsDTO;
import racingcar.domain.movableStrategy.MovableStrategy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

public class CarRacing {
private final RacingFleet racingFleet;
private final RacingWrapResultsDTO wrapResults;
private final RacingHistories histories;
private final MovableStrategy movableStrategy;
Comment on lines +10 to +11
Copy link
Member

Choose a reason for hiding this comment

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

histories 객체는 proceedWraps 메서드의 결과인데요.
proceedWraps 메서드를 수행할 때마다 이력이 계속 쌓이게 됩니다.
그렇다보니 DB의 역할을 겸하고 있다고 생각되는데요, 이력을 상태로 가지기 보다 proceedWraps 메서드 내부에서 생성해서 반환하면 어떨까요?

movablesStrategy 변수는 racingFleet.raceAll 메서드에만 필요합니다.
RacingCar 처럼 변수로 선언하기 보다 해당 로직을 수행할 때 메서드의 인자로 받으면 어떨까요?


private CarRacing(RacingFleet racingFleet, RacingWrapResultsDTO wrapResults) {
private CarRacing(RacingFleet racingFleet, RacingHistories histories, MovableStrategy movableStrategy) {
this.racingFleet = racingFleet;
this.wrapResults = wrapResults;
this.histories = histories;
this.movableStrategy = movableStrategy;
}

public static CarRacing valueOf(List<String> carNames) {
public static CarRacing valueOf(List<String> carNames, MovableStrategy movableStrategy) {
RacingFleet racingFleet = initializeRacingCars(carNames);
List<RacingWrapResultDTO> wrapResults = initializeWrapResults(racingFleet);
return new CarRacing(racingFleet, RacingWrapResultsDTO.valueOf(wrapResults));
RacingHistories histories = initializeRacingHistories(racingFleet);
return new CarRacing(racingFleet, histories, movableStrategy);
}

private static RacingFleet initializeRacingCars(List<String> carNames) {
return RacingFleet.valueOf(carNames);
}

private static List<RacingWrapResultDTO> initializeWrapResults(RacingFleet racingFleet) {
List<RacingWrapResultDTO> wrapResults = new ArrayList<>();
wrapResults.add(RacingWrapResultDTO.valueOf(0, RacingCarStatesDTO.valueOf(racingFleet.getRacingCars())));
return wrapResults;
private static RacingHistories initializeRacingHistories(RacingFleet racingFleet) {
return RacingHistories.newInstance(racingFleet);
}

public void proceedWraps(int tryNumber) {
Expand All @@ -43,19 +37,12 @@ public void proceedWraps(int tryNumber) {
}

private void proceedWrap() {
Copy link
Member

Choose a reason for hiding this comment

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

자동차들이 1회 이동을 시도한 결과를 반환하면 이력을 분리할 수 있을 것 같아요.

Suggested change
private void proceedWrap() {
private RacingFleet proceedWrap() {

int currentWrapNo = findCurrentWrapNo();
List<RacingCar> racingCars = this.racingFleet.getRacingCars();
racingCars.forEach(racingCar -> racingCar.race(RandomMovableStrategy.getInstance()));
RacingCarStatesDTO carStates = RacingCarStatesDTO.valueOf(racingCars);
this.wrapResults.getWrapResults().add(RacingWrapResultDTO.valueOf(currentWrapNo + 1, carStates));
racingFleet.raceAll(movableStrategy);
this.histories.recordRacingState(racingFleet);
}

private int findCurrentWrapNo() {
return Collections.max(this.wrapResults.getWrapResults(), Comparator.comparingInt(RacingWrapResultDTO::getWrapNumber)).getWrapNumber();
}

public RacingWrapResultsDTO getWrapResults() {
return this.wrapResults;
public RacingHistories getHistories() {
return this.histories;
}

public List<RacingCar> getRacingCars() {
Expand All @@ -71,11 +58,11 @@ public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CarRacing carRacing = (CarRacing) o;
return Objects.equals(racingFleet, carRacing.racingFleet) && Objects.equals(wrapResults, carRacing.wrapResults);
return Objects.equals(racingFleet, carRacing.racingFleet) && Objects.equals(histories, carRacing.histories);
}

@Override
public int hashCode() {
return Objects.hash(racingFleet, wrapResults);
return Objects.hash(racingFleet, histories);
}
}
5 changes: 3 additions & 2 deletions src/main/java/racingcar/domain/RacingCarSimulator.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package racingcar.domain;

import racingcar.domain.movableStrategy.MovableStrategy;
import racingcar.dto.RacingResultDTO;

import java.util.List;

public class RacingCarSimulator {
public static RacingResultDTO simulate(List<String> carNames, int tryNumber) {
CarRacing carRacing = CarRacing.valueOf(carNames);
public static RacingResultDTO simulate(List<String> carNames, int tryNumber, MovableStrategy movableStrategy) {
Copy link
Member

Choose a reason for hiding this comment

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

RacingCarSimulator 클래스는 상태도 없고 simulate 메서드의 로직은 컨트롤러의 로직이라고 생각되는데요.
로직을 main 메서드로 이동하고 RacingCarSimulator 클래스는 제거하면 어떨까요?
MVC 패턴으로 리팩터링하는 것이 요구사항이니 어느 클래스 컨트롤러의 역할을 하는지 명시해 주시면 좋을 것 같아요

CarRacing carRacing = CarRacing.valueOf(carNames, movableStrategy);
proceedRacing(tryNumber, carRacing);
return RacingResultDTO.valueOf(carRacing);
}
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/racingcar/domain/RacingCarState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package racingcar.domain;

import java.util.Objects;

public class RacingCarState {
Copy link
Member

Choose a reason for hiding this comment

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

CarRacing 내부에 RacingHistories 필드를 가지다 보니 많은 클래스가 추가되고 전체적인 복잡도가 상승한 것 같아요.
새롭게 추가된 클래스들은 DTO와 다르지 않은 것 같은데요. 기존의 DTO를 활용할 수 없는걸까요?

private final String carName;
private final int carNo;
private final int position;

private RacingCarState(String carName, int carNo, int position) {
this.carName = carName;
this.carNo = carNo;
this.position = position;
}

public static RacingCarState valueOf(RacingCar racingCar) {
return new RacingCarState(racingCar.getName(), racingCar.getCarNo(), racingCar.getPosition());
}

public String getCarName() {
return this.carName;
}

public int getCarNo() {
return this.carNo;
}

public int getPosition() {
return this.position;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RacingCarState that = (RacingCarState) o;
return getCarNo() == that.getCarNo() && getPosition() == that.getPosition() && Objects.equals(getCarName(), that.getCarName());
}

@Override
public int hashCode() {
return Objects.hash(getCarName(), getCarNo(), getPosition());
}
}
39 changes: 39 additions & 0 deletions src/main/java/racingcar/domain/RacingCarStates.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package racingcar.domain;

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

public class RacingCarStates {
private final List<RacingCarState> carStates;

private RacingCarStates(List<RacingCarState> carStates) {
this.carStates = carStates;
}

public static RacingCarStates valueOf(RacingFleet fleet) {
List<RacingCar> racingCars = fleet.getRacingCars();
List<RacingCarState> carStates = new ArrayList<>();
for (RacingCar racingCar : racingCars) {
carStates.add(RacingCarState.valueOf(racingCar));
}
return new RacingCarStates(carStates);
}

public List<RacingCarState> value() {
return this.carStates;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RacingCarStates that = (RacingCarStates) o;
return Objects.equals(value(), that.value());
}

@Override
public int hashCode() {
return Objects.hashCode(value());
}
}
6 changes: 6 additions & 0 deletions src/main/java/racingcar/domain/RacingFleet.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package racingcar.domain;

import racingcar.domain.movableStrategy.MovableStrategy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
Expand All @@ -25,6 +27,10 @@ public List<RacingCar> getRacingCars() {
return this.racingCars;
}

public void raceAll(MovableStrategy movableStrategy) {
racingCars.forEach(racingCar -> racingCar.race(movableStrategy));
}

public List<RacingCar> findWinners() {
int topDistance = findTopDistance();
return findCarNamesWithDistance(topDistance);
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/racingcar/domain/RacingHistories.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package racingcar.domain;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

public class RacingHistories {
private final List<RacingHistory> value;

private RacingHistories(List<RacingHistory> histories) {
this.value = histories;
}

public static RacingHistories newInstance(RacingFleet racingFleet) {
List<RacingHistory> histories = new ArrayList<>();
histories.add(RacingHistory.valueOf(0, RacingCarStates.valueOf(racingFleet)));
return new RacingHistories(histories);
}

public List<RacingHistory> value() {
return value;
}

public void recordRacingState(RacingFleet racingFleet) {
RacingCarStates carStates = RacingCarStates.valueOf(racingFleet);
value.add(RacingHistory.valueOf(findCurrentWrapNo() + 1, carStates));
Copy link
Member

Choose a reason for hiding this comment

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

기존에 lap + 1 로직을 보고 auto increment와 굉장히 유사하다는 느낌을 받았습니다.
그래서 CarRacing 클래스가 RacingHistories 필드가 더 DB 같다는 생각이었는데요,
인상적인 부분이었지만, 요구사항과는 거리가 좀 있는 구현이라 오버 엔지니어링이 아닌지 고민해 보시면 좋을 것 같아요.

}

private int findCurrentWrapNo() {
return Collections.max(value, Comparator.comparingInt(RacingHistory::getWrapNumber)).getWrapNumber();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RacingHistories that = (RacingHistories) o;
return Objects.equals(value, that.value);
}

@Override
public int hashCode() {
return Objects.hashCode(value);
}
}
38 changes: 38 additions & 0 deletions src/main/java/racingcar/domain/RacingHistory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package racingcar.domain;

import java.util.Objects;

public class RacingHistory {
private final int wrapNumber;
private final RacingCarStates carStates;

private RacingHistory(int wrapNumber, RacingCarStates catStates) {
this.wrapNumber = wrapNumber;
this.carStates = catStates;
}

public static RacingHistory valueOf(int wrapNumber, RacingCarStates catStates) {
return new RacingHistory(wrapNumber, catStates);
}

public int getWrapNumber() {
return this.wrapNumber;
}

public RacingCarStates getCarStates() {
return this.carStates;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RacingHistory that = (RacingHistory) o;
return getWrapNumber() == that.getWrapNumber() && Objects.equals(getCarStates(), that.getCarStates());
}

@Override
public int hashCode() {
return Objects.hash(getWrapNumber(), getCarStates());
}
}
5 changes: 5 additions & 0 deletions src/main/java/racingcar/dto/RacingCarStateDTO.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package racingcar.dto;

import racingcar.domain.RacingCar;
import racingcar.domain.RacingCarState;

public final class RacingCarStateDTO {
private final String carName;
Expand All @@ -17,6 +18,10 @@ public static RacingCarStateDTO valueOf(RacingCar racingCar) {
return new RacingCarStateDTO(racingCar.getName(), racingCar.getCarNo(), racingCar.getPosition());
}

public static RacingCarStateDTO valueOf(RacingCarState state) {
return new RacingCarStateDTO(state.getCarName(), state.getCarNo(), state.getPosition());
}

public String getCarName() {
return this.carName;
}
Expand Down
16 changes: 14 additions & 2 deletions src/main/java/racingcar/dto/RacingCarStatesDTO.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
package racingcar.dto;

import racingcar.domain.RacingCar;
import racingcar.domain.RacingCarState;
import racingcar.domain.RacingCarStates;
import racingcar.domain.RacingFleet;

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

public final class RacingCarStatesDTO {
public final List<RacingCarStateDTO> carStates;
private final List<RacingCarStateDTO> carStates;

private RacingCarStatesDTO(List<RacingCarStateDTO> carStates) {
this.carStates = carStates;
}

public static RacingCarStatesDTO valueOf(List<RacingCar> racingCars) {
public static RacingCarStatesDTO valueOf(RacingFleet fleet) {
List<RacingCar> racingCars = fleet.getRacingCars();
List<RacingCarStateDTO> carStates = new ArrayList<>();
for (RacingCar racingCar : racingCars) {
carStates.add(RacingCarStateDTO.valueOf(racingCar));
}
return new RacingCarStatesDTO(carStates);
}

public static RacingCarStatesDTO valueOf(RacingCarStates states) {
List<RacingCarStateDTO> carStates = new ArrayList<>();
for (RacingCarState state : states.value()) {
carStates.add(RacingCarStateDTO.valueOf(state));
}
return new RacingCarStatesDTO(carStates);
}

public List<RacingCarStateDTO> getCarStates() {
return this.carStates;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/racingcar/dto/RacingResultDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private RacingResultDTO(RacingWinnerNamesDTO winners, RacingWrapResultsDTO wrapR
}

public static RacingResultDTO valueOf(CarRacing carRacing) {
return new RacingResultDTO(RacingWinnerNamesDTO.valueOf(carRacing.findWinners()), carRacing.getWrapResults());
return new RacingResultDTO(RacingWinnerNamesDTO.valueOf(carRacing.findWinners()), RacingWrapResultsDTO.valueOf(carRacing.getHistories()));
}

public RacingWinnerNamesDTO getWinners() {
Expand Down
Loading