ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,67 @@
+package subway.controller;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import subway.command.Command;
+import subway.command.MainCommand;
+import subway.controller.handler.Handler;
+import subway.controller.handler.LineHandler;
+import subway.controller.handler.SectionHandler;
+import subway.controller.handler.StationHandler;
+import subway.controller.retryInputUtil.RetryInputUtil;
+import subway.dto.LineDto;
+import subway.service.LineService;
+import subway.service.SectionService;
+import subway.service.StationService;
+import subway.view.OutputView;
+
+public class SubwayController {
+    private final LineService lineService;
+    private final Map<MainCommand, Handler> commandHandlers;
+
+    public SubwayController(StationService stationService, LineService lineService, SectionService sectionService) {
+        this.lineService = lineService;
+
+        this.commandHandlers = new HashMap<>();
+        this.commandHandlers.put(MainCommand.STATION, new StationHandler(stationService));
+        this.commandHandlers.put(MainCommand.LINE, new LineHandler(lineService));
+        this.commandHandlers.put(MainCommand.SECTION, new SectionHandler(sectionService));
+    }
+
+    public void run() {
+        int state = 0;
+
+        while (state == 0) {
+            try {
+                OutputView.printMainMenu();
+                MainCommand mainCommand = Command.findCommand(RetryInputUtil.getMainCommand(), MainCommand.values());
+
+                state = mainLogic(mainCommand);
+            } catch (IllegalArgumentException error) {
+                OutputView.printError(error.getMessage());
+            }
+        }
+    }
+
+    private int mainLogic(MainCommand mainCommand) {
+        if (mainCommand == MainCommand.QUIT) {
+            return 1;
+        }
+
+        if (this.commandHandlers.containsKey(mainCommand)) {
+            this.commandHandlers.get(mainCommand).handle();
+        }
+        if (mainCommand == MainCommand.LINE_PRINT) {
+            printLineMap();
+        }
+
+        return 0;
+    }
+
+    private void printLineMap() {
+        List<LineDto> lines = lineService.retrieve().lines();
+        OutputView.printLineMap(lines);
+    }
+
+}

리뷰: 확실히 boolean이 메모리 절약이 될 것 같습니다
@@ -0,0 +1,67 @@
+package subway.controller;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import subway.command.Command;
+import subway.command.MainCommand;
+import subway.controller.handler.Handler;
+import subway.controller.handler.LineHandler;
+import subway.controller.handler.SectionHandler;
+import subway.controller.handler.StationHandler;
+import subway.controller.retryInputUtil.RetryInputUtil;
+import subway.dto.LineDto;
+import subway.service.LineService;
+import subway.service.SectionService;
+import subway.service.StationService;
+import subway.view.OutputView;
+
+public class SubwayController {
+    private final LineService lineService;
+    private final Map<MainCommand, Handler> commandHandlers;
+
+    public SubwayController(StationService stationService, LineService lineService, SectionService sectionService) {
+        this.lineService = lineService;
+
+        this.commandHandlers = new HashMap<>();
+        this.commandHandlers.put(MainCommand.STATION, new StationHandler(stationService));
+        this.commandHandlers.put(MainCommand.LINE, new LineHandler(lineService));
+        this.commandHandlers.put(MainCommand.SECTION, new SectionHandler(sectionService));
+    }
+
+    public void run() {
+        int state = 0;
+
+        while (state == 0) {
+            try {
+                OutputView.printMainMenu();
+                MainCommand mainCommand = Command.findCommand(RetryInputUtil.getMainCommand(), MainCommand.values());
+
+                state = mainLogic(mainCommand);
+            } catch (IllegalArgumentException error) {
+                OutputView.printError(error.getMessage());
+            }
+        }
+    }
+
+    private int mainLogic(MainCommand mainCommand) {
+        if (mainCommand == MainCommand.QUIT) {
+            return 1;
+        }
+
+        if (this.commandHandlers.containsKey(mainCommand)) {
+            this.commandHandlers.get(mainCommand).handle();
+        }
+        if (mainCommand == MainCommand.LINE_PRINT) {
+            printLineMap();
+        }
+
+        return 0;
+    }
+
+    private void printLineMap() {
+        List<LineDto> lines = lineService.retrieve().lines();
+        OutputView.printLineMap(lines);
+    }
+
+}

리뷰: 말씀해주신 내용이 이렇게 처리하는 것이었군요!
@@ -0,0 +1,67 @@
+package subway.controller;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import subway.command.Command;
+import subway.command.MainCommand;
+import subway.controller.handler.Handler;
+import subway.controller.handler.LineHandler;
+import subway.controller.handler.SectionHandler;
+import subway.controller.handler.StationHandler;
+import subway.controller.retryInputUtil.RetryInputUtil;
+import subway.dto.LineDto;
+import subway.service.LineService;
+import subway.service.SectionService;
+import subway.service.StationService;
+import subway.view.OutputView;
+
+public class SubwayController {
+    private final LineService lineService;
+    private final Map<MainCommand, Handler> commandHandlers;
+
+    public SubwayController(StationService stationService, LineService lineService, SectionService sectionService) {
+        this.lineService = lineService;
+
+        this.commandHandlers = new HashMap<>();
+        this.commandHandlers.put(MainCommand.STATION, new StationHandler(stationService));
+        this.commandHandlers.put(MainCommand.LINE, new LineHandler(lineService));
+        this.commandHandlers.put(MainCommand.SECTION, new SectionHandler(sectionService));
+    }
+
+    public void run() {
+        int state = 0;
+
+        while (state == 0) {
+            try {
+                OutputView.printMainMenu();
+                MainCommand mainCommand = Command.findCommand(RetryInputUtil.getMainCommand(), MainCommand.values());
+
+                state = mainLogic(mainCommand);
+            } catch (IllegalArgumentException error) {
+                OutputView.printError(error.getMessage());
+            }
+        }
+    }
+
+    private int mainLogic(MainCommand mainCommand) {
+        if (mainCommand == MainCommand.QUIT) {
+            return 1;
+        }
+
+        if (this.commandHandlers.containsKey(mainCommand)) {
+            this.commandHandlers.get(mainCommand).handle();
+        }
+        if (mainCommand == MainCommand.LINE_PRINT) {
+            printLineMap();
+        }
+
+        return 0;
+    }
+
+    private void printLineMap() {
+        List<LineDto> lines = lineService.retrieve().lines();
+        OutputView.printLineMap(lines);
+    }
+
+}

리뷰: Handler를 사용하니 controller의 역할이 분리되어 좋아보입니당
@@ -0,0 +1,57 @@
+package subway.controller.handler;
+
+import java.util.List;
+import subway.command.Command;
+import subway.command.LineCommand;
+import subway.controller.retryInputUtil.LineRetryInput;
+import subway.dto.LineDto;
+import subway.dto.LineRegisterDto.LineRegisterInputDto;
+import subway.dto.LineRemoveDto.LineRemoveInputDto;
+import subway.service.LineService;
+import subway.view.OutputView;
+
+public class LineHandler implements Handler {
+    private final LineService lineService;
+
+    public LineHandler(LineService lineService) {
+        this.lineService = lineService;
+    }
+
+    @Override
+    public void handle() {
+        OutputView.printLineManageMenu();
+        LineCommand lineCommand = Command.findCommand(LineRetryInput.getCommand(), LineCommand.values());
+
+        if (lineCommand == LineCommand.REGISTER) {
+            registerLine();
+        }
+        if (lineCommand == LineCommand.REMOVE) {
+            removeLine();
+        }
+        if (lineCommand == LineCommand.RETRIEVE) {
+            retrieveLine();
+        }
+        if (lineCommand == LineCommand.BACK) {
+            // nothing to do.
+        }
+
+    }
+
+    private void registerLine() {
+        String lineName = LineRetryInput.getRegisterLineName();
+        String startStationName = LineRetryInput.getRegisterLineStartStationName();
+        String endStationName = LineRetryInput.getRegisterLineEndStationName();
+        lineService.register(new LineRegisterInputDto(lineName, startStationName, endStationName));
+    }
+
+    private void removeLine() {
+        String lineName = LineRetryInput.getRemoveLineName();
+        lineService.remove(new LineRemoveInputDto(lineName));
+        OutputView.printLineRemovedMessage();
+    }
+
+    private void retrieveLine() {
+        List<LineDto> lines = lineService.retrieve().lines();
+        OutputView.printLines(lines);
+    }
+}

리뷰: view의 메소드들을 static으로 처리하면, 의존하지 않아도 되니 제가 고민하던 부분이 풀리는군요.
@@ -0,0 +1,30 @@
+package subway.controller.retryInputUtil;
+
+import subway.command.Command;
+import subway.command.LineCommand;
+import subway.validator.InputValidator;
+import subway.view.InputView;
+import subway.view.LineInputView;
+
+public class LineRetryInput {
+
+    public static String getCommand() {
+        return RetryInputUtil.retryLogics(InputView::getCommand, (input) -> Command.findCommand(input, LineCommand.values()));
+    }
+
+    public static String getRegisterLineName() {
+        return RetryInputUtil.retryLogics(LineInputView::getRegisterLineName, InputValidator::nullValidate);
+    }
+
+    public static String getRegisterLineStartStationName() {
+        return RetryInputUtil.retryLogics(LineInputView::getRegisterLineStartStationName, InputValidator::nullValidate);
+    }
+
+    public static String getRegisterLineEndStationName() {
+        return RetryInputUtil.retryLogics(LineInputView::getRegisterLineEndStationName, InputValidator::nullValidate);
+    }
+
+    public static String getRemoveLineName() {
+        return RetryInputUtil.retryLogics(LineInputView::getRemoveLineName, InputValidator::nullValidate);
+    }
+}

리뷰: 공백을 추가하면 가독성이 더 좋을 것 같습니당
@@ -1,15 +1,45 @@
 package subway.domain;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import subway.validator.LineValidator;
+
 public class Line {
     private String name;
+    private List<Station> stations;
 
-    public Line(String name) {
+    public Line(String name, Station startStation, Station endStation) {
+        LineValidator.validate(name, startStation, endStation);
         this.name = name;
+        this.stations = new ArrayList<>(List.of(startStation, endStation));
+    }
+
+    public void addStation(Station station) {
+        stations.add(station);
+    }
+
+    public void addStation(Station station, int index) {
+        stations.add(index, station);
+    }
+
+    public void removeStation(Station station) {
+        stations.remove(station);
+    }
+
+    public List<Station> getStations() {
+        return stations;
+    }
+
+    public int getStationCount() {
+        return stations.size();
+    }
+
+    public List<String> getStationNames() {
+        return stations.stream().map(Station::getName).collect(Collectors.toList());
     }
 
     public String getName() {
         return name;
     }
-
-    // 추가 기능 구현
 }

리뷰: 저는 객체의 불변성을 위해 등록이나 삭제 등이 일어날 경우 기존 객체를 대체할 새로운 객체를 생성하는 식으로 구현했습니다. 
또, getStations()가 리스트를 복사하지 않고 그대로 반환하고 있는 것 같습니다!
unmodifiableList에 대해 알아보시면 좋을 것 같아요!
@@ -0,0 +1,27 @@
+package subway.command;
+
+public enum LineCommand implements Command {
+    REGISTER("1", "노선 등록"),
+    REMOVE("2", "노선 삭제"),
+    RETRIEVE("3", "노선 조회"),
+    BACK("B", "돌아가기");
+
+    private final String command;
+    private final String description;
+
+    LineCommand(String command, String description) {
+        this.command = command;
+        this.description = description;
+    }
+
+    @Override
+    public String getCommand() {
+        return command;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+}

리뷰: view 객체의 출력을 확인해보니 여기서 생성한 문자열을 그대로 받아서 출력하고 있는 것 같습니다. 그렇다면 도메인이 UI 생성 로직에도 관여하고 있는 설계가 아닐까요?
@@ -0,0 +1,78 @@
+package subway.config;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import subway.domain.Line;
+import subway.domain.Station;
+import subway.exception.ReaderException;
+import subway.repository.LineRepository;
+import subway.repository.StationRepository;
+import subway.utils.LineFieldsDto;
+import subway.utils.LineParser;
+import subway.utils.StationFieldsDto;
+import subway.utils.StationParser;
+
+public class SubwayFileInitializer {
+    private final StationParser stationParser;
+    private final LineParser lineParser;
+    private final StationRepository stationRepository;
+    private final LineRepository lineRepository;
+
+    public SubwayFileInitializer(StationParser stationParser, LineParser lineParser,
+                                 StationRepository stationRepository, LineRepository lineRepository) {
+        this.stationParser = stationParser;
+        this.lineParser = lineParser;
+        this.stationRepository = stationRepository;
+        this.lineRepository = lineRepository;
+    }
+
+    public void init() {
+        try {
+            initStations();
+            initLines();
+        } catch (IOException e) {
+            throw new ReaderException();
+        } catch (IllegalArgumentException error) {
+            throw new IllegalArgumentException(error.getMessage());
+        }
+    }
+
+    private void initStations() throws IOException {
+        while (true) {
+            StationFieldsDto stationFieldsDto = stationParser.nextStation();
+            if (stationFieldsDto == null) {
+                break;
+            }
+
+            stationRepository.add(new Station(stationFieldsDto.stationName()));
+        }
+    }
+
+    private void initLines() throws IOException {
+        while (true) {
+            LineFieldsDto lineFieldsDto = lineParser.nextLine();
+            if (lineFieldsDto == null) {
+                break;
+            }
+
+            List<Station> stations = new ArrayList<>();
+            for (String stationName : lineFieldsDto.stationNames()) {
+                Station station = stationRepository.findByName(stationName);
+                if (station == null) {
+                    throw new IllegalArgumentException();
+                }
+
+                stations.add(station);
+            }
+
+            Line line = new Line(lineFieldsDto.lineName(), stations.getFirst(), stations.getLast());
+            lineRepository.add(line);
+            for (int i = 1; i < stations.size() - 1; i++) {
+                Station station = stations.get(i);
+                lineRepository.addStation(line, station, i);
+            }
+        }
+    }
+
+}

리뷰: 다시 새로운 예외를 던지기 보다는 `throw error` 이런식으로 기존 예외를 그대로 넘기는 것이 어떨까요?
@@ -0,0 +1,78 @@
+package subway.config;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import subway.domain.Line;
+import subway.domain.Station;
+import subway.exception.ReaderException;
+import subway.repository.LineRepository;
+import subway.repository.StationRepository;
+import subway.utils.LineFieldsDto;
+import subway.utils.LineParser;
+import subway.utils.StationFieldsDto;
+import subway.utils.StationParser;
+
+public class SubwayFileInitializer {
+    private final StationParser stationParser;
+    private final LineParser lineParser;
+    private final StationRepository stationRepository;
+    private final LineRepository lineRepository;
+
+    public SubwayFileInitializer(StationParser stationParser, LineParser lineParser,
+                                 StationRepository stationRepository, LineRepository lineRepository) {
+        this.stationParser = stationParser;
+        this.lineParser = lineParser;
+        this.stationRepository = stationRepository;
+        this.lineRepository = lineRepository;
+    }
+
+    public void init() {
+        try {
+            initStations();
+            initLines();
+        } catch (IOException e) {
+            throw new ReaderException();
+        } catch (IllegalArgumentException error) {
+            throw new IllegalArgumentException(error.getMessage());
+        }
+    }
+
+    private void initStations() throws IOException {
+        while (true) {
+            StationFieldsDto stationFieldsDto = stationParser.nextStation();
+            if (stationFieldsDto == null) {
+                break;
+            }
+
+            stationRepository.add(new Station(stationFieldsDto.stationName()));
+        }
+    }
+
+    private void initLines() throws IOException {
+        while (true) {
+            LineFieldsDto lineFieldsDto = lineParser.nextLine();
+            if (lineFieldsDto == null) {
+                break;
+            }
+
+            List<Station> stations = new ArrayList<>();
+            for (String stationName : lineFieldsDto.stationNames()) {
+                Station station = stationRepository.findByName(stationName);
+                if (station == null) {
+                    throw new IllegalArgumentException();
+                }
+
+                stations.add(station);
+            }
+
+            Line line = new Line(lineFieldsDto.lineName(), stations.getFirst(), stations.getLast());
+            lineRepository.add(line);
+            for (int i = 1; i < stations.size() - 1; i++) {
+                Station station = stations.get(i);
+                lineRepository.addStation(line, station, i);
+            }
+        }
+    }
+
+}

리뷰: Optional을 이용한다면 가독성이 더 좋아질 것 같습니다!
@@ -0,0 +1,78 @@
+package subway.config;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import subway.domain.Line;
+import subway.domain.Station;
+import subway.exception.ReaderException;
+import subway.repository.LineRepository;
+import subway.repository.StationRepository;
+import subway.utils.LineFieldsDto;
+import subway.utils.LineParser;
+import subway.utils.StationFieldsDto;
+import subway.utils.StationParser;
+
+public class SubwayFileInitializer {
+    private final StationParser stationParser;
+    private final LineParser lineParser;
+    private final StationRepository stationRepository;
+    private final LineRepository lineRepository;
+
+    public SubwayFileInitializer(StationParser stationParser, LineParser lineParser,
+                                 StationRepository stationRepository, LineRepository lineRepository) {
+        this.stationParser = stationParser;
+        this.lineParser = lineParser;
+        this.stationRepository = stationRepository;
+        this.lineRepository = lineRepository;
+    }
+
+    public void init() {
+        try {
+            initStations();
+            initLines();
+        } catch (IOException e) {
+            throw new ReaderException();
+        } catch (IllegalArgumentException error) {
+            throw new IllegalArgumentException(error.getMessage());
+        }
+    }
+
+    private void initStations() throws IOException {
+        while (true) {
+            StationFieldsDto stationFieldsDto = stationParser.nextStation();
+            if (stationFieldsDto == null) {
+                break;
+            }
+
+            stationRepository.add(new Station(stationFieldsDto.stationName()));
+        }
+    }
+
+    private void initLines() throws IOException {
+        while (true) {
+            LineFieldsDto lineFieldsDto = lineParser.nextLine();
+            if (lineFieldsDto == null) {
+                break;
+            }
+
+            List<Station> stations = new ArrayList<>();
+            for (String stationName : lineFieldsDto.stationNames()) {
+                Station station = stationRepository.findByName(stationName);
+                if (station == null) {
+                    throw new IllegalArgumentException();
+                }
+
+                stations.add(station);
+            }
+
+            Line line = new Line(lineFieldsDto.lineName(), stations.getFirst(), stations.getLast());
+            lineRepository.add(line);
+            for (int i = 1; i < stations.size() - 1; i++) {
+                Station station = stations.get(i);
+                lineRepository.addStation(line, station, i);
+            }
+        }
+    }
+
+}

리뷰: Stream을 이용하여 indent를 줄여보는 것은 어떨까요?
@@ -0,0 +1,49 @@
+package subway.controller.handler;
+
+import subway.command.Command;
+import subway.command.SectionCommand;
+import subway.controller.retryInputUtil.SectionRetryInput;
+import subway.dto.SectionRegisterDto.SectionRegisterInputDto;
+import subway.dto.SectionRemoveDto.SectionRemoveInputDto;
+import subway.service.SectionService;
+import subway.view.OutputView;
+
+public class SectionHandler implements Handler {
+    private final SectionService sectionService;
+
+    public SectionHandler(SectionService sectionService) {
+        this.sectionService = sectionService;
+    }
+
+    @Override
+    public void handle() {
+        OutputView.printSectionManageMenu();
+        SectionCommand sectionCommand = Command.findCommand(SectionRetryInput.getCommand(),
+                SectionCommand.values());
+
+        if (sectionCommand == SectionCommand.REGISTER) {
+            registerSection();
+        }
+        if (sectionCommand == SectionCommand.REMOVE) {
+            removeSection();
+        }
+        if (sectionCommand == SectionCommand.BACK) {
+            // nothing to do.
+        }
+
+    }
+
+    private void registerSection() {
+        String lineName = SectionRetryInput.getLineName();
+        String stationName = SectionRetryInput.getStationName();
+        int orderNumber = SectionRetryInput.getOrderNumber();
+        sectionService.register(new SectionRegisterInputDto(lineName, stationName, orderNumber));
+    }
+
+    private void removeSection() {
+        String lineName = SectionRetryInput.getRemoveLineName();
+        String stationName = SectionRetryInput.getRemoveStationName();
+        sectionService.remove(new SectionRemoveInputDto(lineName, stationName));
+        OutputView.printSectionRemovedMessage();
+    }
+}

리뷰: 이 조건문을 굳이 작성하신 이유가 있을까요? 저는 BACK일 경우, 아무 기능도 수행하지 않기 때문에 따로 조건문으로 분리하지 않았기 때문에 궁금합니다.
@@ -1,15 +1,45 @@
 package subway.domain;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import subway.validator.LineValidator;
+
 public class Line {
     private String name;
+    private List<Station> stations;
 
-    public Line(String name) {
+    public Line(String name, Station startStation, Station endStation) {
+        LineValidator.validate(name, startStation, endStation);
         this.name = name;
+        this.stations = new ArrayList<>(List.of(startStation, endStation));
+    }
+
+    public void addStation(Station station) {
+        stations.add(station);
+    }
+
+    public void addStation(Station station, int index) {
+        stations.add(index, station);
+    }
+
+    public void removeStation(Station station) {
+        stations.remove(station);
+    }
+
+    public List<Station> getStations() {
+        return stations;
+    }
+
+    public int getStationCount() {
+        return stations.size();
+    }
+
+    public List<String> getStationNames() {
+        return stations.stream().map(Station::getName).collect(Collectors.toList());
     }
 
     public String getName() {
         return name;
     }
-
-    // 추가 기능 구현
 }

리뷰: 불변 리스트로 반환하는 것이 어떨까요?