ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,87 @@
+import { useContext, useEffect, useRef } from "react";
+import { QuantityContext } from "../../store/QuantityContext";
+import useProductList from "../../hooks/useProductList";
+import useCartItemList from "../../hooks/useCartItemList";
+import ProductItem from "../ProductItem/ProductItem";
+import * as S from "./ProductItemList.style";
+import { Category } from "../../interfaces/Product";
+import { Sorting } from "../../interfaces/Sorting";
+import useIntersectionObserver from "../../hooks/useIntersectionObserver";
+import Spinner from "../common/Spinner/Spinner";
+
+interface ProductItemListProp {
+  category: Category;
+  sortOption: Sorting;
+  onError: (error: string) => void;
+}
+
+function ProductItemList({
+  category,
+  sortOption,
+  onError,
+}: ProductItemListProp) {
+  const {
+    productList,
+    productListError,
+    productListLoading,
+    page,
+    fetchNextPage,
+    isLastPage,
+    setPage,
+  } = useProductList({
+    category,
+    sortOption,
+  });
+  const { cartItemList, isInCart, toggleCartItem, cartItemListError } =
+    useCartItemList();
+  const target = useRef(null);
+  const [observe, unobserve] = useIntersectionObserver(() => {
+    fetchNextPage();
+  });
+
+  useEffect(() => {
+    setPage(0);
+  }, [category, sortOption]);
+
+  useEffect(() => {
+    if (page === -1 || target.current === null) return;
+    observe(target.current);
+
+    const N = productList.length;
+
+    if (0 === N || isLastPage) {
+      unobserve(target.current);
+    }
+  }, [productList, page, observe, unobserve]);
+  const quantityContext = useContext(QuantityContext);
+  const setQuantity = quantityContext ? quantityContext.setQuantity : () => {};
+  setQuantity(cartItemList.length);
+
+  if (productListError) {
+    onError("상품 목록 조회 실패");
+  }
+  if (cartItemListError) {
+    onError("장바구니 목록 조회 실패");
+  }
+
+  return (
+    <>
+      <S.ProductList>
+        {productList.map((product, idx) => {
+          return (
+            <ProductItem
+              key={`${idx}_${product.id}`}
+              product={product}
+              isInCart={isInCart(product.id)}
+              toggleCartItem={() => toggleCartItem(product)}
+            />
+          );
+        })}
+      </S.ProductList>
+      <div ref={target} style={{ height: "1px" }}></div>
+      {productListLoading && <Spinner />}
+    </>
+  );
+}
+
+export default ProductItemList;

리뷰: 아무래도 이번 미션에서 가장 메인이 되는(?) 컴포넌트인 것 같아요. 비즈니스 로직과 UI 로직이 좀 더 잘 분리되면 더욱 읽기 좋을 것 같습니다!
@@ -0,0 +1,5 @@
+package model;
+
+public interface State {
+    int execute(int length);
+}

리뷰: 확장 가능성을 생각하여 인터페이스를 구현하였네요!! 각 다른 상태마다 객체를 만들어서 Car에서 갈아끼우는 것도 신선합니다!! State 패턴 좋은 것 배워갑니다 👍
@@ -0,0 +1,13 @@
+package function;
+
+import java.util.Random;
+
+public class RandomNumberMaker {
+
+    private static final Random random = new Random();
+    private static final int RANDOM_NUMBER_RANGE = 10;
+
+    public static int getRandomNumber() {
+        return random.nextInt(RANDOM_NUMBER_RANGE);
+    }
+}

리뷰: getRandomNumber 가 호출될 때마다 새로운 Random객체가 만들어지지 않아도 될 것 같아요!!
그리고 Random값의boundary를 파라미터로 받은 이유가 있을까요??
@@ -2,22 +2,28 @@
 
 public class Car{
 
-    private String name;
-    private int position = 0;
+    long number;
+    int length;
+    State state;
 
-    public Car(String name){
-        this.name = name;
+    public Car(long number) {
+        this.number = number;
+        length = 0;
     }
 
-    public String getName() {
-        return name;
+    public int moveCount() {
+        return length;
     }
 
-    public int getPosition(){
-        return position;
+    public long getCarNum() {
+        return number;
     }
 
-    public void move(){
-        position++;
+    public void changeState(State cmd) {
+        state = cmd;
+    }
+
+    public void move() {
+        length = state.execute(length);
     }
 }
\ No newline at end of file

리뷰: number를 Car를 식별해주는 멤버로 사용하고 있는 것 같아요!! 접근지정자와 final 키워드를 붙여주는 것에 대해 어떻게 생각하실까요?
@@ -1,21 +1,18 @@
 package view;
 
-import controller.RacingGame;
 import model.Car;
 
-import java.util.Collections;
 import java.util.List;
 
 public class ResultView {
 
-    public static void printTrialResult(List<Car> cars){
-        for (Car car : cars){
-            System.out.print(car.getName() + " : " + String.join("", Collections.nCopies(car.getPosition(), "*")) + "\n");
+    private static final String RESULT_SYMBOL = "-";
+
+    public static void printAllCarsState(long id, int len) {
+        System.out.println("car" + id);
+        for (int i = 0; i < len; i++) {
+            System.out.print(RESULT_SYMBOL);
         }
         System.out.println();
     }
-
-    public static void printFinalWinner(RacingGame racingGame, List<Car> cars){
-        System.out.print(String.join(",",  racingGame.searchWinners(cars)) + "가 최종 우승했습니다.");
-    }
 }
\ No newline at end of file

리뷰: 현재 출력하는 용도로 지금 --- 이렇게 보여주고 있지만, 나중에는 다른 기호로 바뀔수도 있을 것 같아요!! 이 기호들 뿐만 아니라 InputView와 ResultView의 입출력 메세지, 매직넘버들을 상수화 해주면 좋을 것 같아요
@@ -0,0 +1,38 @@
+package controller;
+
+import function.RandomNumberMaker;
+import model.Car;
+import model.State;
+import model.Movable;
+import model.UnMovable;
+
+import java.util.List;
+
+public class CarController {
+
+    private static final int MOVE_CONDITION = 4;
+
+    public void registerCars(List<Car> cars, long len) {
+        for (int i = 0; i < len; i++) {
+            cars.add(new Car(i));
+        }
+    }
+
+    public void moveCar(List<Car> cars) {
+        for (Car car : cars) {
+            car.changeState(checkMoveOrStop(car));
+            car.move();
+        }
+    }
+
+    private State checkMoveOrStop(Car car) {
+        if (getRandomNumber() >= MOVE_CONDITION) {
+            return new Movable();
+        }
+        return new UnMovable();
+    }
+
+    private int getRandomNumber() {
+        return RandomNumberMaker.getRandomNumber();
+    }
+}

리뷰: 전체적으로 Car들을 관리해주는 역할을 하고 있는 것 같아요! 
제가 생각하는 Controller의 역할과는 조금 다르다고 생각이 듭니다. 
제가 생각하는 Controller의 역할은 사용자가 입력한 요청값을 받아, 요청값을 가지고 비즈니스 로직을 실행하고 필요한 데이터를 가공해서 View에게 보내주는 역할이라고 생각을 합니다. 
저는 CarController보다 Cars같은 이름이 더 어울린다고 생각이 드는데 현우님은 어떻게 생각하실까요??
이 자료 참고하시면 좋을 것 같습니다!
https://tecoble.techcourse.co.kr/post/2020-05-08-First-Class-Collection/
@@ -0,0 +1,47 @@
+package engine;
+
+import controller.CarController;
+import model.Car;
+import view.InputView;
+import view.ResultView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RacingGame {
+
+    private List<Car> cars;
+    private CarController carController;
+    private InputView inputView;
+
+    public RacingGame() {
+        cars = new ArrayList<>();
+        carController = new CarController();
+        inputView = new InputView();
+    }
+
+    public void run() {
+        long carNum = inputView.inputTotalCarNum();
+        int trial = inputView.inputTotalTrial();
+
+        register(carNum);
+        executeGame(trial);
+        printAll(cars);
+    }
+
+    private void executeGame(int trial) {
+        for (int i = 0; i < trial; i++) {
+            carController.moveCar(cars);
+        }
+    }
+
+    private void register(long carNum) {
+        carController.registerCars(cars, carNum);
+    }
+
+    private void printAll(List<Car> cars) {
+        for (Car car : cars) {
+            ResultView.printAllCarsState(car.getCarNum(), car.moveCount());
+        }
+    }
+}

리뷰: InputView는 인스턴스로 관리하고 ResultView는 유틸리티 클래스로 선언한 이유가 궁금하네요!! 저도 View를 구현을 할 때, 고민이 많이 되는데요! View 같은 경우에 상태가 없어서 유틸리티 클래스로 구현을 해도 될 것 같지만, 유틸성 클래스와는 색깔이 조금 다른 느낌도 있어서요!! 정답은 없겠지만, 저는 이번에 View 구현을 할 때 싱글턴 패턴을 사용해보았어요!! 현우님이 InputView와 OutputView를 다르게 구현한점이 궁금하네요!
@@ -0,0 +1,38 @@
+package controller;
+
+import function.RandomNumberMaker;
+import model.Car;
+import model.State;
+import model.Movable;
+import model.UnMovable;
+
+import java.util.List;
+
+public class CarController {
+
+    private static final int MOVE_CONDITION = 4;
+
+    public void registerCars(List<Car> cars, long len) {
+        for (int i = 0; i < len; i++) {
+            cars.add(new Car(i));
+        }
+    }
+
+    public void moveCar(List<Car> cars) {
+        for (Car car : cars) {
+            car.changeState(checkMoveOrStop(car));
+            car.move();
+        }
+    }
+
+    private State checkMoveOrStop(Car car) {
+        if (getRandomNumber() >= MOVE_CONDITION) {
+            return new Movable();
+        }
+        return new UnMovable();
+    }
+
+    private int getRandomNumber() {
+        return RandomNumberMaker.getRandomNumber();
+    }
+}

리뷰: 랜덤값 때문에 checkMoveOrStop 메서드를 테스트 코드 작성하기 어려웠을 거예요!!
https://tecoble.techcourse.co.kr/post/2020-05-07-appropriate_method_for_test_by_parameter/
https://tecoble.techcourse.co.kr/post/2020-05-17-appropriate_method_for_test_by_interface/
자료 참고하시면 좋을 것 같아요!! 하지만 인터페이스를 분리하는게 무조건 좋은 방법은 아니라고 생각이 듭니다!! 의심하면서 보면 좋을 것 같아요!! 현우님은 생각이 다르실 수 도 있구요!
@@ -0,0 +1,13 @@
+package function;
+
+import java.util.Random;
+
+public class RandomNumberMaker {
+
+    private static final Random random = new Random();
+    private static final int RANDOM_NUMBER_RANGE = 10;
+
+    public static int getRandomNumber() {
+        return random.nextInt(RANDOM_NUMBER_RANGE);
+    }
+}

리뷰: 1. getRandomNumber 가 호출될 때마다 새로운 Random객체가 만들어지지 않아도 될 것 같아요!!

동건님 말씀대로 getRandomNumber를 호출할 때마다 Random 객체를 만들지 않는 것이 좋다고 생각이 듭니다
Random객체를 싱글톤 패턴을 이용하여 구현하면 리소스 부분에서 낭비를 줄일 수 있을 것 같습니다!! :)

2. Random값의 boundary를 파라미터로 받은 이유가 있을까요??

제가 생각하기에는 나중에 10에서 다른 숫자로 바꾸고 싶은 "변경 사항"을 생각해봤습니다.
차를 움직이게 하는 "CarController"에서 수정해주는 것이 좋다고 생각했습니다.
@@ -0,0 +1,13 @@
+package function;
+
+import java.util.Random;
+
+public class RandomNumberMaker {
+
+    private static final Random random = new Random();
+    private static final int RANDOM_NUMBER_RANGE = 10;
+
+    public static int getRandomNumber() {
+        return random.nextInt(RANDOM_NUMBER_RANGE);
+    }
+}

리뷰: ```java
private static Random random = new Random();
private static final int RANDOM_BOUNDARY = 10;

public static int getRandomNumber() {
   return random.nextInt(RANDOM_BOUNDARY);
}
```
이라고 해줄 수 있을 것 같아서요!! 
랜덤 값을 생성해주는 역할을 하는 것 같은데, 랜덤값의 범위도 랜덤값이 생성해주는 곳에서 알아야 하지 않을까 싶네요!
@@ -0,0 +1,13 @@
+package function;
+
+import java.util.Random;
+
+public class RandomNumberMaker {
+
+    private static final Random random = new Random();
+    private static final int RANDOM_NUMBER_RANGE = 10;
+
+    public static int getRandomNumber() {
+        return random.nextInt(RANDOM_NUMBER_RANGE);
+    }
+}

리뷰: "랜덤값의 범위도 랜덤값이 생성해주는 곳에서 알아야 하지 않을까 싶네요"
이 부분이 맞는 것 같습니다. 생각해보니 CarController가 랜덤값의 범위를 정한다면 결국 Random값을 생성해주는 곳에 의존하게 되어 결합도가 높아지겠네요!!
결합도를 줄이는 방법 너무 좋습니다 감사합니다!
@@ -1,16 +1,54 @@
 package view;
 
+import java.io.InputStream;
+import java.util.InputMismatchException;
 import java.util.Scanner;
 
-public class InputView{
+public class InputView {
 
-    public static String[] inputCarName(Scanner scanner){
-        System.out.println("경주할 차의 이름을 입력하세요. (이름은 쉼표(,) 기준으로 구분)");
-        return scanner.nextLine().split(",");
+    Scanner sc;
+    private static final String CARS_COUNT = "자동차 대수는 몇 대 인가요?";
+    private static final String PUT_NATURAL_NUMBER = "음수가 아닌 자연수를 입력해주세요";
+    private static final String TRIAL_COUNT = "시도할 횟수는 몇 회 인가요?";
+    private static final String DO_NOT_PUT_STRING = "문자열이 아닌 자연수를 입력해주세요";
+
+    public InputView() {
+        sc = new Scanner(System.in);
+    }
+
+    public long inputTotalCarNum() {
+        System.out.println(CARS_COUNT);
+        long carCount = 0L;
+        try {
+            carCount = Long.parseLong(sc.nextLine());
+            if (carCount <= 0) {
+                throw new IllegalArgumentException();
+            }
+        } catch (IllegalArgumentException exception) {
+            System.out.println(PUT_NATURAL_NUMBER);
+            return inputTotalCarNum();
+        } catch (InputMismatchException exception) {
+            System.out.println(DO_NOT_PUT_STRING);
+            return inputTotalCarNum();
+        }
+        return carCount;
     }
 
-    public static int inputNumberOfTrials(Scanner scanner){
-        System.out.println("시도할 횟수는 몇회인가요?");
-        return scanner.nextInt();
+    public int inputTotalTrial() {
+        System.out.println(TRIAL_COUNT);
+        int trial = 0;
+        try {
+            trial = Integer.parseInt(sc.nextLine());
+            if (trial <= 0) {
+                throw new IllegalArgumentException();
+            }
+        } catch (IllegalArgumentException exception) {
+            System.out.println(PUT_NATURAL_NUMBER);
+            return inputTotalTrial();
+        } catch (InputMismatchException exception) {
+            System.out.println(DO_NOT_PUT_STRING);
+            return inputTotalTrial();
+        }
+        return trial;
     }
-}
\ No newline at end of file
+}

리뷰: 음수가 입력됐을 경우에 예외가 던져지도록 처리를 해주셨네요! 음수일 경우 말고도 숫자가 아닌 값이 입력 됐을 경우도 예외가 던져지도록 명시적으로 처리해주면 더 좋을 것 같습니다!
@@ -1,16 +1,54 @@
 package view;
 
+import java.io.InputStream;
+import java.util.InputMismatchException;
 import java.util.Scanner;
 
-public class InputView{
+public class InputView {
 
-    public static String[] inputCarName(Scanner scanner){
-        System.out.println("경주할 차의 이름을 입력하세요. (이름은 쉼표(,) 기준으로 구분)");
-        return scanner.nextLine().split(",");
+    Scanner sc;
+    private static final String CARS_COUNT = "자동차 대수는 몇 대 인가요?";
+    private static final String PUT_NATURAL_NUMBER = "음수가 아닌 자연수를 입력해주세요";
+    private static final String TRIAL_COUNT = "시도할 횟수는 몇 회 인가요?";
+    private static final String DO_NOT_PUT_STRING = "문자열이 아닌 자연수를 입력해주세요";
+
+    public InputView() {
+        sc = new Scanner(System.in);
+    }
+
+    public long inputTotalCarNum() {
+        System.out.println(CARS_COUNT);
+        long carCount = 0L;
+        try {
+            carCount = Long.parseLong(sc.nextLine());
+            if (carCount <= 0) {
+                throw new IllegalArgumentException();
+            }
+        } catch (IllegalArgumentException exception) {
+            System.out.println(PUT_NATURAL_NUMBER);
+            return inputTotalCarNum();
+        } catch (InputMismatchException exception) {
+            System.out.println(DO_NOT_PUT_STRING);
+            return inputTotalCarNum();
+        }
+        return carCount;
     }
 
-    public static int inputNumberOfTrials(Scanner scanner){
-        System.out.println("시도할 횟수는 몇회인가요?");
-        return scanner.nextInt();
+    public int inputTotalTrial() {
+        System.out.println(TRIAL_COUNT);
+        int trial = 0;
+        try {
+            trial = Integer.parseInt(sc.nextLine());
+            if (trial <= 0) {
+                throw new IllegalArgumentException();
+            }
+        } catch (IllegalArgumentException exception) {
+            System.out.println(PUT_NATURAL_NUMBER);
+            return inputTotalTrial();
+        } catch (InputMismatchException exception) {
+            System.out.println(DO_NOT_PUT_STRING);
+            return inputTotalTrial();
+        }
+        return trial;
     }
-}
\ No newline at end of file
+}

리뷰: 저도 동건님께 배운건데 if문 바디가 한 문장이더라도 중괄호 {}를 사용해주는것이 관례라고 하네요!
@@ -2,22 +2,28 @@
 
 public class Car{
 
-    private String name;
-    private int position = 0;
+    long number;
+    int length;
+    State state;
 
-    public Car(String name){
-        this.name = name;
+    public Car(long number) {
+        this.number = number;
+        length = 0;
     }
 
-    public String getName() {
-        return name;
+    public int moveCount() {
+        return length;
     }
 
-    public int getPosition(){
-        return position;
+    public long getCarNum() {
+        return number;
     }
 
-    public void move(){
-        position++;
+    public void changeState(State cmd) {
+        state = cmd;
+    }
+
+    public void move() {
+        length = state.execute(length);
     }
 }
\ No newline at end of file

리뷰: 접근제한자는 가능한 가장 좁은 범위로 선언해주는것이 좋다고 합니다. number, length, state 같은 경우에는 private로 선언해주면 어떨까요?
@@ -0,0 +1,38 @@
+package controller;
+
+import function.RandomNumberMaker;
+import model.Car;
+import model.State;
+import model.Movable;
+import model.UnMovable;
+
+import java.util.List;
+
+public class CarController {
+
+    private static final int MOVE_CONDITION = 4;
+
+    public void registerCars(List<Car> cars, long len) {
+        for (int i = 0; i < len; i++) {
+            cars.add(new Car(i));
+        }
+    }
+
+    public void moveCar(List<Car> cars) {
+        for (Car car : cars) {
+            car.changeState(checkMoveOrStop(car));
+            car.move();
+        }
+    }
+
+    private State checkMoveOrStop(Car car) {
+        if (getRandomNumber() >= MOVE_CONDITION) {
+            return new Movable();
+        }
+        return new UnMovable();
+    }
+
+    private int getRandomNumber() {
+        return RandomNumberMaker.getRandomNumber();
+    }
+}

리뷰: RANDOM_NUMBER_RANGE 는 어떨까요?
@@ -1,66 +0,0 @@
-package controller;
-
-import model.Car;
-import util.RandomGenerator;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class RacingGame {
-
-    public static final int CRITICAL_POINT = 5;
-    public static final int MAX_NAME_LENGTH = 5;
-
-    public void oneTrial(List<Car> cars){
-        for (Car car : cars){
-            check(car);
-        }
-    }
-
-    public void check(Car car){
-        if (RandomGenerator.randInt(10) > CRITICAL_POINT){
-            car.move();
-        }
-    }
-
-    public List<String> searchWinners(List<Car> cars){
-        List<String> winnerNames = new ArrayList<>();
-        int maxPosition = searchMaxPosition(cars);
-
-        for (Car car : cars){
-            checkWinner(car, winnerNames, maxPosition);
-        }
-        return winnerNames;
-    }
-
-    public int searchMaxPosition(List<Car> cars){
-        List<Integer> carPosition = new ArrayList<>();
-
-        for (Car car : cars){
-            carPosition.add(car.getPosition());
-        }
-        return Collections.max(carPosition);
-    }
-
-    public void checkWinner(Car car, List<String> winnerNames, int maxPosition){
-        if (car.getPosition() == maxPosition){
-            winnerNames.add(car.getName());
-        }
-    }
-
-    public static List<Car> generateCars(String[] carNames) throws StringOutOfBoundsException{
-        List<Car> cars = new ArrayList<>();
-        for (String carName : carNames){
-            checkNameLength(carName, cars);
-        }
-        return cars;
-    }
-
-    public static void checkNameLength(String carName, List<Car> cars) throws StringOutOfBoundsException {
-        if(carName.length() >  MAX_NAME_LENGTH){
-            throw new StringOutOfBoundsException();
-        }
-        cars.add(new Car(carName));
-    }
-}

리뷰: 메서드명은 행위를 표현하는 동사로 시작하는게 어떨까요?
@@ -1,66 +0,0 @@
-package controller;
-
-import model.Car;
-import util.RandomGenerator;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class RacingGame {
-
-    public static final int CRITICAL_POINT = 5;
-    public static final int MAX_NAME_LENGTH = 5;
-
-    public void oneTrial(List<Car> cars){
-        for (Car car : cars){
-            check(car);
-        }
-    }
-
-    public void check(Car car){
-        if (RandomGenerator.randInt(10) > CRITICAL_POINT){
-            car.move();
-        }
-    }
-
-    public List<String> searchWinners(List<Car> cars){
-        List<String> winnerNames = new ArrayList<>();
-        int maxPosition = searchMaxPosition(cars);
-
-        for (Car car : cars){
-            checkWinner(car, winnerNames, maxPosition);
-        }
-        return winnerNames;
-    }
-
-    public int searchMaxPosition(List<Car> cars){
-        List<Integer> carPosition = new ArrayList<>();
-
-        for (Car car : cars){
-            carPosition.add(car.getPosition());
-        }
-        return Collections.max(carPosition);
-    }
-
-    public void checkWinner(Car car, List<String> winnerNames, int maxPosition){
-        if (car.getPosition() == maxPosition){
-            winnerNames.add(car.getName());
-        }
-    }
-
-    public static List<Car> generateCars(String[] carNames) throws StringOutOfBoundsException{
-        List<Car> cars = new ArrayList<>();
-        for (String carName : carNames){
-            checkNameLength(carName, cars);
-        }
-        return cars;
-    }
-
-    public static void checkNameLength(String carName, List<Car> cars) throws StringOutOfBoundsException {
-        if(carName.length() >  MAX_NAME_LENGTH){
-            throw new StringOutOfBoundsException();
-        }
-        cars.add(new Car(carName));
-    }
-}

리뷰: check 는 무엇을 체크한다는건지 알기 어려운 것 같아요~ 내부에서만 활용되는 클래스면 private 키워드를 붙이고 메서드명을 좀 더 풀어써보면 어떨까요?
@@ -0,0 +1,8 @@
+package model;
+
+public class Movable implements State {
+    @Override
+    public int execute(int length) {
+        return length + 1;
+    }
+}

리뷰: ~able 은 interface 의 접미사로 활용되는데
구현체의 네이밍인 경우에는 이 타입이 무엇이 가능한지보다는 무엇을 하는지 구체적인 단어를 활용하면 어떨까요?
예를 들어 Forward 나 Stop 처럼요
@@ -2,22 +2,28 @@
 
 public class Car{
 
-    private String name;
-    private int position = 0;
+    long number;
+    int length;
+    State state;
 
-    public Car(String name){
-        this.name = name;
+    public Car(long number) {
+        this.number = number;
+        length = 0;
     }
 
-    public String getName() {
-        return name;
+    public int moveCount() {
+        return length;
     }
 
-    public int getPosition(){
-        return position;
+    public long getCarNum() {
+        return number;
     }
 
-    public void move(){
-        position++;
+    public void changeState(State cmd) {
+        state = cmd;
+    }
+
+    public void move() {
+        length = state.execute(length);
     }
 }
\ No newline at end of file

리뷰: 자동차의 위치를 나타내는 변수 같은데 position 은 어떨까요?
@@ -2,22 +2,28 @@
 
 public class Car{
 
-    private String name;
-    private int position = 0;
+    long number;
+    int length;
+    State state;
 
-    public Car(String name){
-        this.name = name;
+    public Car(long number) {
+        this.number = number;
+        length = 0;
     }
 
-    public String getName() {
-        return name;
+    public int moveCount() {
+        return length;
     }
 
-    public int getPosition(){
-        return position;
+    public long getCarNum() {
+        return number;
     }
 
-    public void move(){
-        position++;
+    public void changeState(State cmd) {
+        state = cmd;
+    }
+
+    public void move() {
+        length = state.execute(length);
     }
 }
\ No newline at end of file

리뷰: 의미가 불분명한 number 보다는 식별이 가능한 값을 표현하는 id 도 괜찮을 것 같습니다 ~
@@ -2,22 +2,28 @@
 
 public class Car{
 
-    private String name;
-    private int position = 0;
+    long number;
+    int length;
+    State state;
 
-    public Car(String name){
-        this.name = name;
+    public Car(long number) {
+        this.number = number;
+        length = 0;
     }
 
-    public String getName() {
-        return name;
+    public int moveCount() {
+        return length;
     }
 
-    public int getPosition(){
-        return position;
+    public long getCarNum() {
+        return number;
     }
 
-    public void move(){
-        position++;
+    public void changeState(State cmd) {
+        state = cmd;
+    }
+
+    public void move() {
+        length = state.execute(length);
     }
 }
\ No newline at end of file

리뷰: Num 도 줄임말이니 number, no 로 통일해보면 어떨까요?
그리고 getter 는 get{field명} 이라는 java bean 컨벤션이 있으니 따르면 좋을 것 같습니다
@@ -2,22 +2,28 @@
 
 public class Car{
 
-    private String name;
-    private int position = 0;
+    long number;
+    int length;
+    State state;
 
-    public Car(String name){
-        this.name = name;
+    public Car(long number) {
+        this.number = number;
+        length = 0;
     }
 
-    public String getName() {
-        return name;
+    public int moveCount() {
+        return length;
     }
 
-    public int getPosition(){
-        return position;
+    public long getCarNum() {
+        return number;
     }
 
-    public void move(){
-        position++;
+    public void changeState(State cmd) {
+        state = cmd;
+    }
+
+    public void move() {
+        length = state.execute(length);
     }
 }
\ No newline at end of file

리뷰: count 를 이동시킨다 라는 뜻의 메서드명인 것 같아요~ getLength 는 어떨까요?