diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 000000000..2e3a3bb51
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,140 @@
+# 지하철 노선도 경로 조회 미션
+- 등록된 지하철 노선도에서 경로를 조회하는 기능을 구현한다.
+
+
+
+## 🚀 기능 요구사항
+
+> 프리코스 3주차 미션에서 사용한 코드를 참고해도 무관하다.
+
+### 초기 설정
+- 프로그램 시작 시 역, 노선, 구간 정보를 초기 설정 해야 한다.
+- 거리와 소요 시간은 양의 정수이며 단위는 km와 분을 의미한다.
+- 아래의 사전 등록 정보로 반드시 초기 설정을 한다.
+
+```
+ 1. 지하철역으로 교대역, 강남역, 역삼역, 남부터미널역, 양재역, 양재시민의숲역, 매봉역이 등록되어 있다.
+ 2. 지하철 노선으로 2호선, 3호선, 신분당선이 등록되어 있다.
+ 3. 노선에 역이 아래와 같이 등록되어 있다.(왼쪽 끝이 상행 종점)
+ - 2호선: 교대역 - ( 2km / 3분 ) - 강남역 - ( 2km / 3분 ) - 역삼역
+ - 3호선: 교대역 - ( 3km / 2분 ) - 남부터미널역 - ( 6km / 5분 ) - 양재역 - ( 1km / 1분 ) - 매봉역
+ - 신분당선: 강남역 - ( 2km / 8분 ) - 양재역 - ( 10km / 3분 ) - 양재시민의숲역
+ ```
+
+## Livenow 프로그램 구현
+## 🚩 객체 책임 (아는 것과 하는 것)
+### **지하철 역**
+- 아는 것
+ - 역 이름
+
+
+
+- 하는 것
+
+
+### **지하철 역 저장소**
+- 아는 것
+ - 지하철 역
+
+
+
+- 하는 것
+ - 지하철 역 저장
+
+### **거리**
+- 아는 것
+ - 거리(km)
+
+
+
+- 하는 것
+
+### **시간**
+- 아는 것
+ - 분
+
+
+
+- 하는 것
+
+### **거리(분)**
+- 아는 것
+ - 거리(분)
+
+
+
+- 하는 것
+
+### **노선**
+- 아는 것
+ - 노선 이름
+ - 지하철 역(들)
+
+
+
+- 하는 것
+
+### **라인(들)**
+- 아는 것
+ - 라인
+
+
+
+- 하는 것
+### **라인 저장소**
+- 아는 것
+ - 라인
+
+
+
+- 하는 것
+ - 라인저장
+
+
+## 🚩 구현할 기능
+### **메인 화면**
+- [x] 객체 모델링
+- [x] 메인화면 출력
+- [x] 보장된 값 입력
+ - 보장된 값(1,Q 만을 허용)
+ - 보장된 값이 아닐 시 에러 출력
+ - `SelectionException`
+- [x] Q가 입력될 시, 종료 ( 소문자 q 도 허용 함. )
+
+### **경로 조회**
+- [x] 경로 조회 화면 출력
+- [x] 보장된 값 입력
+ - 보장된 값(1,2,B 만을 허용)
+ - 보장된 값이 아닐 시 에러 출력
+ - `SelectionException`
+- [x] 지하철 역 저장
+- [x] 노선 저장
+- [x] 구간 저장
+- [x] 초기 저장 (시간(분) 미포함)
+- [x] 초기 저장(구간마다 거리, 시간 포함)
+- [x] 1을 입력시 최단 거리 조회
+ - [x] 출발역을 입력
+ - [x] 저장소에 저장되어 있는 지하철 역이 아닐 시 에러가 발생한다.
+ - `StationException`
+ - [x] 도착역 역을 입력
+ - [x] 저장소에 저장되어 있는 지하철 역이 아닐 시 에러가 발생한다.
+ - `StationException`
+ - [x] 출발역과 도착역이 같으면 에러를 출력한다
+ - `StationException`
+ - [x] 최단 거리를 조회한다.
+
+- [x] 2를 입력시 최소 시간 조회
+ - [x] 출발역을 입력
+ - [x] 저장소에 저장되어 있는 지하철 역이 아닐 시 에러가 발생한다.
+ - `에러 발생`
+ - [x] 도착역 역을 입력
+ - [x] 저장소에 저장되어 있는 지하철 역이 아닐 시 에러가 발생한다.
+ - `에러 발생`
+ - [x] 출발역과 도착역이 같으면 에러를 출력한다
+ - `에러 발생`
+ - [x] 최소 시간를 조회한다.
+
+- [ ] 최단 거리 최소시간 같이 출력
+
+### **에러가 발생해도 서비스가 죽지 않아야 한다**
+- [x] 에러 핸들링
diff --git a/src/main/java/subway/Application.java b/src/main/java/subway/Application.java
index 0bcf786cc..489a0d3ae 100644
--- a/src/main/java/subway/Application.java
+++ b/src/main/java/subway/Application.java
@@ -1,10 +1,21 @@
package subway;
+import subway.domain.section.SectionRepository;
+import subway.domain.section.SectionService;
+import subway.domain.station.StationService;
+import subway.view.InputView;
+import subway.view.OutputView;
+
import java.util.Scanner;
public class Application {
public static void main(String[] args) {
final Scanner scanner = new Scanner(System.in);
// TODO: 프로그램 구현
+ DataInitService dataInitService = new DataInitService(new StationService(), new SectionService(new SectionRepository()));
+ dataInitService.init();
+
+ SubwayManageApp subwayManageApp = new SubwayManageApp(new InputView(scanner), new OutputView(new StringBuilder()));
+ subwayManageApp.startApp();
}
}
diff --git a/src/main/java/subway/DataInitService.java b/src/main/java/subway/DataInitService.java
new file mode 100644
index 000000000..fbc44d6ff
--- /dev/null
+++ b/src/main/java/subway/DataInitService.java
@@ -0,0 +1,120 @@
+package subway;
+
+import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
+import org.jgrapht.graph.DefaultWeightedEdge;
+import org.jgrapht.graph.WeightedMultigraph;
+import subway.domain.distanceTime.Distance;
+import subway.domain.distanceTime.Time;
+import subway.domain.section.SectionService;
+import subway.domain.section.dto.SectionSaveReqDto;
+import subway.domain.section.dto.SectionStationAddReqDto;
+import subway.domain.station.StationService;
+import subway.domain.station.dto.StationSaveReqDto;
+
+public class DataInitService {
+ private static final String STATION_GYODAE = "교대역";
+ private static final String STATION_GANGNAM = "강남역";
+ private static final String STATION_YEOKSAM = "역삼역";
+ private static final String STATION_SOUTH_TERMINAL = "남부터미널역";
+ private static final String STATION_YANGJAE = "양재역";
+ private static final String STATION_CITIZEN_FOREST = "양재시민의숲역";
+ private static final String STATION_MAEBONG = "매봉역";
+ private static final String LINE_TWO = "2호선";
+ private static final String LINE_THREE = "3호선";
+ private static final String LINE_SINBUNDANG = "신분당선";
+
+ private static final int SECOND = 2;
+ private static final int THIRD = 3;
+
+ private static final int KM_ONE = 1;
+ private static final int KM_TWO = 2;
+ private static final int KM_THREE = 3;
+ private static final int KM_SIX = 6;
+ private static final int KM_TEN = 10;
+
+ private static final int MINUTE_ONE = 1;
+ private static final int MINUTE_TWO = 2;
+ private static final int MINUTE_THREE = 3;
+ private static final int MINUTE_FIVE = 5;
+ private static final int MINUTE_EIGHT = 8;
+
+ private final StationService stationService;
+ private final SectionService sectionService;
+
+ public DataInitService(StationService stationService, SectionService sectionService) {
+ this.stationService = stationService;
+ this.sectionService = sectionService;
+ }
+
+ public void init() {
+ saveStation();
+ saveSection();
+ saveDistance();
+ saveTime();
+ }
+
+ private void saveDistance() {
+ WeightedMultigraph graph = getStringDefaultWeightedEdgeWeightedMultigraph();
+
+ graph.setEdgeWeight(graph.addEdge(STATION_GYODAE, STATION_GANGNAM), new Distance(KM_TWO).getKm());
+ graph.setEdgeWeight(graph.addEdge(STATION_GANGNAM, STATION_YEOKSAM), new Distance(KM_TWO).getKm());
+
+ graph.setEdgeWeight(graph.addEdge(STATION_GYODAE, STATION_SOUTH_TERMINAL), new Distance(KM_THREE).getKm());
+ graph.setEdgeWeight(graph.addEdge(STATION_SOUTH_TERMINAL, STATION_YANGJAE), new Distance(KM_SIX).getKm());
+ graph.setEdgeWeight(graph.addEdge(STATION_YANGJAE, STATION_MAEBONG), new Distance(KM_ONE).getKm());
+
+ graph.setEdgeWeight(graph.addEdge(STATION_GANGNAM, STATION_YANGJAE), new Distance(KM_TWO).getKm());
+ graph.setEdgeWeight(graph.addEdge(STATION_YANGJAE, STATION_CITIZEN_FOREST), new Distance(KM_TEN).getKm());
+
+ DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(graph);
+ SearchService.addDijkstraShortestPath(dijkstraShortestPath);
+ }
+
+ private void saveTime() {
+ WeightedMultigraph graph = getStringDefaultWeightedEdgeWeightedMultigraph();
+
+ graph.setEdgeWeight(graph.addEdge(STATION_GYODAE, STATION_GANGNAM), new Time(MINUTE_THREE).getMinute());
+ graph.setEdgeWeight(graph.addEdge(STATION_GANGNAM, STATION_YEOKSAM), new Time(MINUTE_THREE).getMinute());
+
+ graph.setEdgeWeight(graph.addEdge(STATION_GYODAE, STATION_SOUTH_TERMINAL), new Time(MINUTE_TWO).getMinute());
+ graph.setEdgeWeight(graph.addEdge(STATION_SOUTH_TERMINAL, STATION_YANGJAE), new Time(MINUTE_FIVE).getMinute());
+ graph.setEdgeWeight(graph.addEdge(STATION_YANGJAE, STATION_MAEBONG), new Time(MINUTE_ONE).getMinute());
+
+ graph.setEdgeWeight(graph.addEdge(STATION_GANGNAM, STATION_YANGJAE), new Time(MINUTE_EIGHT).getMinute());
+ graph.setEdgeWeight(graph.addEdge(STATION_YANGJAE, STATION_CITIZEN_FOREST), new Time(MINUTE_THREE).getMinute());
+
+ DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(graph);
+ SearchService.addDijkstraShortestPath(dijkstraShortestPath);
+ }
+
+ private WeightedMultigraph getStringDefaultWeightedEdgeWeightedMultigraph() {
+ WeightedMultigraph graph = new WeightedMultigraph(DefaultWeightedEdge.class);
+ graph.addVertex(STATION_GYODAE);
+ graph.addVertex(STATION_GANGNAM);
+ graph.addVertex(STATION_YEOKSAM);
+ graph.addVertex(STATION_SOUTH_TERMINAL);
+ graph.addVertex(STATION_YANGJAE);
+ graph.addVertex(STATION_MAEBONG);
+ graph.addVertex(STATION_CITIZEN_FOREST);
+ return graph;
+ }
+
+ private void saveSection() {
+ sectionService.saveSection(new SectionSaveReqDto(LINE_TWO, STATION_GYODAE, STATION_YEOKSAM));
+ sectionService.addStation(new SectionStationAddReqDto(LINE_TWO, STATION_GANGNAM, SECOND));
+
+ sectionService.saveSection(new SectionSaveReqDto(LINE_THREE, STATION_GYODAE, STATION_MAEBONG));
+ sectionService.addStation(new SectionStationAddReqDto(LINE_THREE, STATION_SOUTH_TERMINAL, SECOND));
+ sectionService.addStation(new SectionStationAddReqDto(LINE_THREE, STATION_YANGJAE, THIRD));
+
+ sectionService.saveSection(new SectionSaveReqDto(LINE_SINBUNDANG, STATION_GANGNAM, STATION_CITIZEN_FOREST));
+ sectionService.addStation(new SectionStationAddReqDto(LINE_SINBUNDANG, STATION_YANGJAE, SECOND));
+ }
+
+ private void saveStation() {
+ String[] stationNames = {STATION_GYODAE, STATION_GANGNAM, STATION_YEOKSAM, STATION_SOUTH_TERMINAL, STATION_YANGJAE, STATION_CITIZEN_FOREST, STATION_MAEBONG};
+ for (String stationName : stationNames) {
+ stationService.saveStation(new StationSaveReqDto(stationName));
+ }
+ }
+}
diff --git a/src/main/java/subway/SearchService.java b/src/main/java/subway/SearchService.java
new file mode 100644
index 000000000..a7891d206
--- /dev/null
+++ b/src/main/java/subway/SearchService.java
@@ -0,0 +1,79 @@
+package subway;
+
+import org.jgrapht.GraphPath;
+import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
+import subway.domain.station.Station;
+import subway.domain.station.StationRepository;
+import subway.exception.ErrorCode;
+import subway.exception.StationException;
+import subway.view.InputView;
+import subway.view.screen.SearchView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SearchService {
+ private static final List dijkstraShortestPaths = new ArrayList<>();
+ private static final int DISTANCE_INDEX = 0;
+ private static final int TIME_INDEX = 1;
+
+ private final InputView inputView;
+ private final SearchView searchView;
+
+ public SearchService(InputView inputView, SearchView searchView) {
+ this.inputView = inputView;
+ this.searchView = searchView;
+ }
+
+ public static void addDijkstraShortestPath(DijkstraShortestPath dijkstraShortestPath) {
+ dijkstraShortestPaths.add(dijkstraShortestPath);
+ }
+
+ public void findShortestDistance() {
+ searchView.printAdd();
+ String firstStationName = inputView.inputNextLine();
+ Station firstStation = StationRepository.findByName(firstStationName);
+
+ searchView.printSecondAdd();
+ String secondStationName = inputView.inputNextLine();
+ Station secondStation = StationRepository.findByName(secondStationName);
+ checkSameName(firstStationName, secondStationName);
+
+ searchView.printAfterAdd();
+ printDistance(firstStation, secondStation);
+ }
+
+ public void findShortestTime() {
+ searchView.printAdd();
+ String firstStationName = inputView.inputNextLine();
+ Station firstStation = StationRepository.findByName(firstStationName);
+
+ searchView.printSecondAdd();
+ String secondStationName = inputView.inputNextLine();
+ Station secondStation = StationRepository.findByName(secondStationName);
+ checkSameName(firstStationName, secondStationName);
+
+ searchView.printAfterAdd();
+ printTime(firstStation, secondStation);
+ }
+
+ private void printTime(Station firstStation, Station secondStation) {
+ DijkstraShortestPath dijkstraShortestPathDistance = dijkstraShortestPaths.get(TIME_INDEX);
+ double pathWeight = dijkstraShortestPathDistance.getPathWeight(firstStation.getName(), secondStation.getName());
+ GraphPath path = dijkstraShortestPathDistance.getPath(firstStation.getName(), secondStation.getName());
+ searchView.printTimeList(path, pathWeight);
+ }
+
+ private void printDistance(Station firstStation, Station secondStation) {
+ DijkstraShortestPath dijkstraShortestPathDistance = dijkstraShortestPaths.get(DISTANCE_INDEX);
+ double pathWeight = dijkstraShortestPathDistance.getPathWeight(firstStation.getName(), secondStation.getName());
+ GraphPath path = dijkstraShortestPathDistance.getPath(firstStation.getName(), secondStation.getName());
+ searchView.printDistanceList(path, pathWeight);
+ }
+
+ private void checkSameName(String firstStationName, String secondStationName) {
+ if (firstStationName.equals(secondStationName)) {
+ throw new StationException(ErrorCode.STATION_SAME_NAME);
+ }
+ }
+}
diff --git a/src/main/java/subway/SubwayManageApp.java b/src/main/java/subway/SubwayManageApp.java
new file mode 100644
index 000000000..7f951dcf7
--- /dev/null
+++ b/src/main/java/subway/SubwayManageApp.java
@@ -0,0 +1,71 @@
+package subway;
+
+import subway.view.InputView;
+import subway.view.Prefix;
+import subway.view.screen.SearchView;
+import subway.view.selection.MainSelection;
+import subway.view.OutputView;
+import subway.view.selection.SearchSelection;
+import subway.view.screen.MainView;
+
+public class SubwayManageApp {
+ private final InputView inputView;
+ private final OutputView outputView;
+
+ public SubwayManageApp(InputView inputView, OutputView outputView) {
+ this.inputView = inputView;
+ this.outputView = outputView;
+ }
+
+ public void startApp() {
+ MainView mainView = new MainView(outputView);
+ while (true) {
+ mainView.showOptions();
+ MainSelection mainSelection;
+ try {
+ mainSelection = new MainSelection(inputView.inputNextLine());
+ chooseOption(mainSelection);
+ } catch (Exception exception) {
+ System.out.println(Prefix.ENTER.getPrefix() + Prefix.ERROR.getPrefix() + exception.getMessage());
+ continue;
+ }
+ if (mainSelection.isQuit()) {
+ break;
+ }
+ }
+ }
+
+ private void chooseOption(MainSelection mainSelection) {
+ if (mainSelection.isOptionOne()) {
+ manageSearch();
+ }
+ }
+
+ private void manageSearch() {
+ SearchView searchView = new SearchView(outputView);
+ while (true) {
+ try {
+ searchView.showOptions();
+ SearchSelection searchSelection = new SearchSelection(inputView.inputNextLine());
+ chooseSearchOption(searchSelection);
+ break;
+ } catch (Exception exception) {
+ System.out.println(Prefix.ENTER.getPrefix() + Prefix.ERROR.getPrefix() + exception.getMessage());
+ continue;
+ }
+ }
+ }
+
+ private void chooseSearchOption(SearchSelection searchSelection) {
+ SearchService searchService = new SearchService(inputView, new SearchView(outputView));
+ if (searchSelection.isOptionOne()) {
+ searchService.findShortestDistance();
+ }
+ if (searchSelection.isOptionTwo()) {
+ searchService.findShortestTime();
+ }
+ if (searchSelection.isBack()) {
+ return;
+ }
+ }
+}
diff --git a/src/main/java/subway/domain/Station.java b/src/main/java/subway/domain/Station.java
deleted file mode 100644
index bdb142590..000000000
--- a/src/main/java/subway/domain/Station.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package subway.domain;
-
-public class Station {
- private String name;
-
- public Station(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- // 추가 기능 구현
-}
diff --git a/src/main/java/subway/domain/distanceTime/Distance.java b/src/main/java/subway/domain/distanceTime/Distance.java
new file mode 100644
index 000000000..a92033ab6
--- /dev/null
+++ b/src/main/java/subway/domain/distanceTime/Distance.java
@@ -0,0 +1,23 @@
+package subway.domain.distanceTime;
+
+import subway.exception.DistanceTimeException;
+import subway.exception.ErrorCode;
+
+public class Distance {
+ private int km;
+
+ public Distance(int km) {
+ this.km = km;
+ validate(km);
+ }
+
+ private void validate(int km) {
+ if (km < 1) {
+ throw new DistanceTimeException(ErrorCode.INPUT_VALUE_MUST_NATURAL);
+ }
+ }
+
+ public int getKm() {
+ return km;
+ }
+}
diff --git a/src/main/java/subway/domain/distanceTime/Time.java b/src/main/java/subway/domain/distanceTime/Time.java
new file mode 100644
index 000000000..d45a381be
--- /dev/null
+++ b/src/main/java/subway/domain/distanceTime/Time.java
@@ -0,0 +1,23 @@
+package subway.domain.distanceTime;
+
+import subway.exception.DistanceTimeException;
+import subway.exception.ErrorCode;
+
+public class Time {
+ private int minute;
+
+ public Time(int minute) {
+ this.minute = minute;
+ validate(minute);
+ }
+
+ private void validate(int minute) {
+ if (minute < 1) {
+ throw new DistanceTimeException(ErrorCode.INPUT_VALUE_MUST_NATURAL);
+ }
+ }
+
+ public int getMinute() {
+ return minute;
+ }
+}
diff --git a/src/main/java/subway/domain/line/Line.java b/src/main/java/subway/domain/line/Line.java
new file mode 100644
index 000000000..0280b0d50
--- /dev/null
+++ b/src/main/java/subway/domain/line/Line.java
@@ -0,0 +1,34 @@
+package subway.domain.line;
+
+import subway.exception.ErrorCode;
+import subway.exception.LineException;
+
+public class Line {
+ private static final int MIN_SIZE = 2;
+ private static final String MUST_CONTAIN_LAST = "선";
+ private static final String PERMIT_CHARACTER = "^[가-힣|0-9]*$";
+
+ private String name;
+
+ public Line(String name) {
+ this.name = name;
+ validateName(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ // 추가 기능 구현
+ private void validateName(String name) {
+ if (name.length() < MIN_SIZE) {
+ throw new LineException(ErrorCode.LINE_NAME_LENGTH_ERROR);
+ }
+ if (!name.endsWith(MUST_CONTAIN_LAST)) {
+ throw new LineException(ErrorCode.LINE_INVALID_LAST_NAME);
+ }
+ if (!name.matches(PERMIT_CHARACTER)) {
+ throw new LineException(ErrorCode.LINE_INVALID_CHARACTER);
+ }
+ }
+}
diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/line/LineRepository.java
similarity index 59%
rename from src/main/java/subway/domain/LineRepository.java
rename to src/main/java/subway/domain/line/LineRepository.java
index 2c4a723c9..2c98c6fe5 100644
--- a/src/main/java/subway/domain/LineRepository.java
+++ b/src/main/java/subway/domain/line/LineRepository.java
@@ -1,4 +1,7 @@
-package subway.domain;
+package subway.domain.line;
+
+import subway.exception.ErrorCode;
+import subway.exception.LineException;
import java.util.ArrayList;
import java.util.Collections;
@@ -23,4 +26,12 @@ public static boolean deleteLineByName(String name) {
public static void deleteAll() {
lines.clear();
}
+
+ public static Line findByName(String lineName) {
+ Line findLine = lines.stream()
+ .filter(line -> line.getName().equals(lineName))
+ .findAny()
+ .orElseThrow(() -> new LineException(ErrorCode.LINE_NOT_FOUND));
+ return findLine;
+ }
}
diff --git a/src/main/java/subway/domain/line/LineService.java b/src/main/java/subway/domain/line/LineService.java
new file mode 100644
index 000000000..a025029c9
--- /dev/null
+++ b/src/main/java/subway/domain/line/LineService.java
@@ -0,0 +1,21 @@
+package subway.domain.line;
+
+import subway.domain.line.dto.LineSaveReqDto;
+import subway.exception.ErrorCode;
+import subway.exception.LineException;
+
+public class LineService {
+ public LineService() {
+ }
+
+ public Line saveLine(LineSaveReqDto saveReqDto) {
+ try {
+ LineRepository.findByName(saveReqDto.getName());
+ } catch (LineException lineException) {
+ Line line = new Line(saveReqDto.getName());
+ LineRepository.addLine(line);
+ return line;
+ }
+ throw new LineException(ErrorCode.LINE_ALREADY_EXIST);
+ }
+}
diff --git a/src/main/java/subway/domain/line/Lines.java b/src/main/java/subway/domain/line/Lines.java
new file mode 100644
index 000000000..fbeecad44
--- /dev/null
+++ b/src/main/java/subway/domain/line/Lines.java
@@ -0,0 +1,12 @@
+package subway.domain.line;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Lines {
+ private final List lines;
+
+ public Lines(List lines) {
+ this.lines = new ArrayList<>(lines);
+ }
+}
diff --git a/src/main/java/subway/domain/Line.java b/src/main/java/subway/domain/line/dto/LineSaveReqDto.java
similarity index 53%
rename from src/main/java/subway/domain/Line.java
rename to src/main/java/subway/domain/line/dto/LineSaveReqDto.java
index f4d738d5a..45067758f 100644
--- a/src/main/java/subway/domain/Line.java
+++ b/src/main/java/subway/domain/line/dto/LineSaveReqDto.java
@@ -1,15 +1,13 @@
-package subway.domain;
+package subway.domain.line.dto;
-public class Line {
+public class LineSaveReqDto {
private String name;
- public Line(String name) {
+ public LineSaveReqDto(String name) {
this.name = name;
}
public String getName() {
return name;
}
-
- // 추가 기능 구현
}
diff --git a/src/main/java/subway/domain/section/Section.java b/src/main/java/subway/domain/section/Section.java
new file mode 100644
index 000000000..e937c22e8
--- /dev/null
+++ b/src/main/java/subway/domain/section/Section.java
@@ -0,0 +1,40 @@
+package subway.domain.section;
+
+import subway.domain.line.Line;
+import subway.domain.station.Station;
+import subway.domain.station.Stations;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class Section {
+ private final Line line;
+ private final Stations stations;
+
+ private Section(Line line, Stations stations) {
+ this.line = line;
+ this.stations = stations;
+ }
+
+ public static Section of(Line line, Stations stations) {
+ return new Section(line, stations);
+ }
+
+ public void addStation(Station station, int sequence) {
+ stations.addStation(station, sequence);
+ }
+
+ public String getLineName() {
+ return line.getName();
+ }
+
+ public int getStationsLength() {
+ return stations.size();
+ }
+
+ public List getStationsName() {
+ return stations.getStations().stream()
+ .map(Station::getName)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/subway/domain/section/SectionRepository.java b/src/main/java/subway/domain/section/SectionRepository.java
new file mode 100644
index 000000000..306611950
--- /dev/null
+++ b/src/main/java/subway/domain/section/SectionRepository.java
@@ -0,0 +1,37 @@
+package subway.domain.section;
+
+import subway.exception.ErrorCode;
+import subway.exception.SectionException;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+public class SectionRepository {
+ private static final Map sections = new ConcurrentHashMap<>();
+
+ public SectionRepository() {
+ }
+
+ public Section addSection(Section section) {
+ if (findByName(section.getLineName()) != null) {
+ throw new SectionException(ErrorCode.LINE_ALREADY_EXIST);
+ }
+ sections.put(section.getLineName(), section);
+ return section;
+ }
+
+ public Section findByName(String lineName) {
+ Section section = sections.get(lineName);
+ return section;
+ }
+
+ public List sections() {
+ return sections.values().stream().collect(Collectors.toList());
+ }
+
+ public void removeAll() {
+ sections.clear();
+ }
+}
diff --git a/src/main/java/subway/domain/section/SectionService.java b/src/main/java/subway/domain/section/SectionService.java
new file mode 100644
index 000000000..09ce59425
--- /dev/null
+++ b/src/main/java/subway/domain/section/SectionService.java
@@ -0,0 +1,95 @@
+package subway.domain.section;
+
+import subway.domain.line.Line;
+import subway.domain.line.LineRepository;
+import subway.domain.section.dto.SectionSaveReqDto;
+import subway.domain.section.dto.SectionStationAddReqDto;
+import subway.domain.station.Station;
+import subway.domain.station.StationRepository;
+import subway.domain.station.Stations;
+import subway.exception.ErrorCode;
+import subway.exception.LineException;
+import subway.exception.SectionException;
+import subway.exception.StationException;
+
+import java.util.Arrays;
+
+public class SectionService {
+ public static final int CONVERT_SEQUENCE = 1;
+
+ private final SectionRepository sectionRepository;
+
+ public SectionService(SectionRepository sectionRepository) {
+ this.sectionRepository = sectionRepository;
+ }
+
+ public Section saveSection(SectionSaveReqDto saveReqDto) {
+ Line line = new Line(saveReqDto.getLineName());
+ checkAlreadyExist(line.getName());
+
+ Station upwardStation = new Station(saveReqDto.getUpwardStationName());
+ checkUpwardNotFound(upwardStation.getName());
+
+ Station downwardStation = new Station(saveReqDto.getDownwardStationName());
+ checkDownwardNotFound(downwardStation.getName());
+ checkSameName(upwardStation.getName(), downwardStation.getName());
+
+ LineRepository.addLine(line);
+ Section section = Section.of(line, new Stations(Arrays.asList(upwardStation, downwardStation)));
+ return sectionRepository.addSection(section);
+ }
+
+ public void addStation(SectionStationAddReqDto sectionStationAddReqDto) {
+ Section section = findByName(sectionStationAddReqDto.getLineName());
+ Station station = StationRepository.findByName(sectionStationAddReqDto.getStationName());
+ int sequence = sectionStationAddReqDto.getSequence();
+ if (sequence > section.getStationsLength()) {
+ sequence = section.getStationsLength() + CONVERT_SEQUENCE;
+ }
+ section.addStation(station, sequence - CONVERT_SEQUENCE);
+ }
+
+ public Section findByName(String lineName) {
+ Section findSection = sectionRepository.findByName(lineName);
+ if (findSection == null) {
+ throw new SectionException(ErrorCode.SECTION_NOT_FOUND);
+ }
+ return findSection;
+ }
+
+ private void checkSameName(String upwardStationName, String downwardStationName) {
+ if (upwardStationName.equals(downwardStationName)) {
+ throw new SectionException(ErrorCode.SECTION_SAME_STATION_NAME);
+ }
+ }
+
+ public void checkUpwardNotFound(String stationName) {
+ try {
+ StationRepository.findByName(stationName);
+ } catch (StationException stationException) {
+ throw new SectionException(ErrorCode.SECTION_NOT_FOUND);
+ }
+ }
+
+ public void checkDownwardNotFound(String stationName) {
+ try {
+ StationRepository.findByName(stationName);
+ } catch (StationException stationException) {
+ throw new SectionException(ErrorCode.SECTION_NOT_FOUND);
+ }
+ }
+
+ private void checkAlreadyExist(String name) {
+ try {
+ LineRepository.findByName(name);
+ } catch (LineException lineException) {
+ return;
+ }
+ throw new SectionException(ErrorCode.LINE_ALREADY_EXIST);
+ }
+
+ public void removeAll() {
+ sectionRepository.removeAll();
+ LineRepository.deleteAll();
+ }
+}
diff --git a/src/main/java/subway/domain/section/dto/SectionFindResDto.java b/src/main/java/subway/domain/section/dto/SectionFindResDto.java
new file mode 100644
index 000000000..3e4ccd7a4
--- /dev/null
+++ b/src/main/java/subway/domain/section/dto/SectionFindResDto.java
@@ -0,0 +1,13 @@
+package subway.domain.section.dto;
+
+public class SectionFindResDto {
+ private String lineName;
+
+ public SectionFindResDto(String lineName) {
+ this.lineName = lineName;
+ }
+
+ public String getLineName() {
+ return lineName;
+ }
+}
diff --git a/src/main/java/subway/domain/section/dto/SectionSaveReqDto.java b/src/main/java/subway/domain/section/dto/SectionSaveReqDto.java
new file mode 100644
index 000000000..1757c6200
--- /dev/null
+++ b/src/main/java/subway/domain/section/dto/SectionSaveReqDto.java
@@ -0,0 +1,25 @@
+package subway.domain.section.dto;
+
+public class SectionSaveReqDto {
+ private String lineName;
+ private String upwardStationName;
+ private String downwardStationName;
+
+ public SectionSaveReqDto(String lineName, String upwardStationName, String downwardStationName) {
+ this.lineName = lineName;
+ this.upwardStationName = upwardStationName;
+ this.downwardStationName = downwardStationName;
+ }
+
+ public String getLineName() {
+ return lineName;
+ }
+
+ public String getUpwardStationName() {
+ return upwardStationName;
+ }
+
+ public String getDownwardStationName() {
+ return downwardStationName;
+ }
+}
diff --git a/src/main/java/subway/domain/section/dto/SectionStationAddReqDto.java b/src/main/java/subway/domain/section/dto/SectionStationAddReqDto.java
new file mode 100644
index 000000000..40f57f95a
--- /dev/null
+++ b/src/main/java/subway/domain/section/dto/SectionStationAddReqDto.java
@@ -0,0 +1,25 @@
+package subway.domain.section.dto;
+
+public class SectionStationAddReqDto {
+ private String lineName;
+ private String stationName;
+ private int sequence;
+
+ public SectionStationAddReqDto(String lineName, String stationName, int sequence) {
+ this.lineName = lineName;
+ this.stationName = stationName;
+ this.sequence = sequence;
+ }
+
+ public String getLineName() {
+ return lineName;
+ }
+
+ public String getStationName() {
+ return stationName;
+ }
+
+ public int getSequence() {
+ return sequence;
+ }
+}
diff --git a/src/main/java/subway/domain/section/dto/SectionStationDeleteReqDto.java b/src/main/java/subway/domain/section/dto/SectionStationDeleteReqDto.java
new file mode 100644
index 000000000..0196777b0
--- /dev/null
+++ b/src/main/java/subway/domain/section/dto/SectionStationDeleteReqDto.java
@@ -0,0 +1,19 @@
+package subway.domain.section.dto;
+
+public class SectionStationDeleteReqDto {
+ private String lineName;
+ private String stationName;
+
+ public SectionStationDeleteReqDto(String lineName, String stationName) {
+ this.lineName = lineName;
+ this.stationName = stationName;
+ }
+
+ public String getLineName() {
+ return lineName;
+ }
+
+ public String getStationName() {
+ return stationName;
+ }
+}
diff --git a/src/main/java/subway/domain/station/Station.java b/src/main/java/subway/domain/station/Station.java
new file mode 100644
index 000000000..5a73e2c33
--- /dev/null
+++ b/src/main/java/subway/domain/station/Station.java
@@ -0,0 +1,34 @@
+package subway.domain.station;
+
+import subway.exception.ErrorCode;
+import subway.exception.StationException;
+
+public class Station {
+ private static final int MIN_SIZE = 2;
+ private static final String MUST_CONTAIN_LAST = "역";
+ private static final String PERMIT_CHARACTER = "^[가-힣|0-9]*$";
+
+ private String name;
+
+ public Station(String name) {
+ this.name = name;
+ validateName(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ // 추가 기능 구현
+ private void validateName(String name) {
+ if (name.length() < MIN_SIZE) {
+ throw new StationException(ErrorCode.STATION_NAME_LENGTH_ERROR);
+ }
+ if (!name.endsWith(MUST_CONTAIN_LAST)) {
+ throw new StationException(ErrorCode.STATION_INVALID_LAST_NAME);
+ }
+ if (!name.matches(PERMIT_CHARACTER)) {
+ throw new StationException(ErrorCode.STATION_INVALID_CHARACTER);
+ }
+ }
+}
diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/station/StationRepository.java
similarity index 58%
rename from src/main/java/subway/domain/StationRepository.java
rename to src/main/java/subway/domain/station/StationRepository.java
index 8ed9d103f..5cb972afe 100644
--- a/src/main/java/subway/domain/StationRepository.java
+++ b/src/main/java/subway/domain/station/StationRepository.java
@@ -1,4 +1,7 @@
-package subway.domain;
+package subway.domain.station;
+
+import subway.exception.ErrorCode;
+import subway.exception.StationException;
import java.util.ArrayList;
import java.util.Collections;
@@ -23,4 +26,12 @@ public static boolean deleteStation(String name) {
public static void deleteAll() {
stations.clear();
}
+
+ public static Station findByName(String stationName) {
+ Station findStation = stations.stream()
+ .filter(station -> station.getName().equals(stationName))
+ .findAny()
+ .orElseThrow(() -> new StationException(ErrorCode.STATION_NOT_FOUND));
+ return findStation;
+ }
}
diff --git a/src/main/java/subway/domain/station/StationService.java b/src/main/java/subway/domain/station/StationService.java
new file mode 100644
index 000000000..da24eee69
--- /dev/null
+++ b/src/main/java/subway/domain/station/StationService.java
@@ -0,0 +1,25 @@
+package subway.domain.station;
+
+import subway.domain.station.dto.StationSaveReqDto;
+import subway.exception.ErrorCode;
+import subway.exception.StationException;
+
+public class StationService {
+ public StationService() {
+ }
+
+ public Station saveStation(StationSaveReqDto saveReqDto) {
+ try {
+ StationRepository.findByName(saveReqDto.getStationName());
+ } catch (StationException stationException) {
+ Station station = new Station(saveReqDto.getStationName());
+ StationRepository.addStation(station);
+ return station;
+ }
+ throw new StationException(ErrorCode.STATION_ALREADY_EXIST);
+ }
+
+ public void removeAll() {
+ StationRepository.deleteAll();
+ }
+}
diff --git a/src/main/java/subway/domain/station/StationTime.java b/src/main/java/subway/domain/station/StationTime.java
new file mode 100644
index 000000000..8806df1a6
--- /dev/null
+++ b/src/main/java/subway/domain/station/StationTime.java
@@ -0,0 +1,4 @@
+package subway.domain.station;
+
+public class StationTime {
+}
diff --git a/src/main/java/subway/domain/station/Stations.java b/src/main/java/subway/domain/station/Stations.java
new file mode 100644
index 000000000..50332f5b6
--- /dev/null
+++ b/src/main/java/subway/domain/station/Stations.java
@@ -0,0 +1,25 @@
+package subway.domain.station;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class Stations {
+ private final List stations;
+
+ public Stations(List stations) {
+ this.stations = new ArrayList<>(stations);
+ }
+
+ public List getStations() {
+ return Collections.unmodifiableList(stations);
+ }
+
+ public void addStation(Station station, int sequence) {
+ stations.add(sequence, station);
+ }
+
+ public int size() {
+ return stations.size();
+ }
+}
diff --git a/src/main/java/subway/domain/station/dto/StationSaveReqDto.java b/src/main/java/subway/domain/station/dto/StationSaveReqDto.java
new file mode 100644
index 000000000..8d43e8af4
--- /dev/null
+++ b/src/main/java/subway/domain/station/dto/StationSaveReqDto.java
@@ -0,0 +1,13 @@
+package subway.domain.station.dto;
+
+public class StationSaveReqDto {
+ private final String stationName;
+
+ public StationSaveReqDto(String stationName) {
+ this.stationName = stationName;
+ }
+
+ public String getStationName() {
+ return stationName;
+ }
+}
diff --git a/src/main/java/subway/exception/DistanceTimeException.java b/src/main/java/subway/exception/DistanceTimeException.java
new file mode 100644
index 000000000..3d375750b
--- /dev/null
+++ b/src/main/java/subway/exception/DistanceTimeException.java
@@ -0,0 +1,14 @@
+package subway.exception;
+
+public class DistanceTimeException extends IllegalArgumentException {
+ private final ErrorCode errorCode;
+
+ public DistanceTimeException(ErrorCode errorCode) {
+ super(errorCode.getMessage());
+ this.errorCode = errorCode;
+ }
+
+ public ErrorCode getErrorCode() {
+ return errorCode;
+ }
+}
diff --git a/src/main/java/subway/exception/ErrorCode.java b/src/main/java/subway/exception/ErrorCode.java
new file mode 100644
index 000000000..03c7ab2e5
--- /dev/null
+++ b/src/main/java/subway/exception/ErrorCode.java
@@ -0,0 +1,48 @@
+package subway.exception;
+
+import subway.view.Prefix;
+
+public enum ErrorCode {
+ //Selection
+ INVALID_INPUT_VALUE("S001", "선택할 수 없는 기능입니다."),
+
+ //Station
+ STATION_EMTPY("ST001", "존재하지 않는 역입니다."),
+ STATION_NAME_LENGTH_ERROR("ST002", "역 이름은 2글자 이상이어야 합니다."),
+ STATION_INVALID_LAST_NAME("ST003", "마지막 글자에 역이 들어가야합니다."),
+ STATION_INVALID_CHARACTER("ST004", "한글, 숫자만 입력 가능합니다."),
+ STATION_ALREADY_EXIST("ST005", "이미 등록된 지하철 역입니다."),
+ STATION_NOT_FOUND("ST006", "입력된 이름으로 등록된 지하철 역이 없습니다."),
+ STATION_SAME_NAME("ST007", "출발역과 도착역의 이름이 같을 수 없습니다."),
+
+
+ //Line
+ LINE_NAME_LENGTH_ERROR("L001", "노선 이름은 2글자 이상이어야 합니다."),
+ LINE_INVALID_LAST_NAME("L002", "마지막 글자에 선이 들어가야합니다."),
+ LINE_INVALID_CHARACTER("L003", "한글, 숫자만 입력 가능합니다."),
+ LINE_NOT_FOUND("S004", "입력된 이름으로 등록된 노선이 없습니다."),
+ LINE_ALREADY_EXIST("S005", "이미 등록된 지하철 노선입니다."),
+
+ //Section
+ SECTION_SAME_STATION_NAME("SE001", "상행 좀점역과 하행 종점역의 이름이 같을 수 없습니다."),
+ SECTION_NOT_FOUND("SE002", "입력된 이름으로 등록된 노선이 없습니다."),
+
+ //DistanceTime
+ INPUT_VALUE_MUST_NATURAL("D001", "1이상의 자연수만 입력 가능합니다.");
+
+ private final String code;
+ private final String message;
+
+ ErrorCode(String code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/src/main/java/subway/exception/LineException.java b/src/main/java/subway/exception/LineException.java
new file mode 100644
index 000000000..2105643a0
--- /dev/null
+++ b/src/main/java/subway/exception/LineException.java
@@ -0,0 +1,14 @@
+package subway.exception;
+
+public class LineException extends IllegalArgumentException {
+ private final ErrorCode errorCode;
+
+ public LineException(ErrorCode errorCode) {
+ super(errorCode.getMessage());
+ this.errorCode = errorCode;
+ }
+
+ public ErrorCode getErrorCode() {
+ return errorCode;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/subway/exception/SectionException.java b/src/main/java/subway/exception/SectionException.java
new file mode 100644
index 000000000..4d169c805
--- /dev/null
+++ b/src/main/java/subway/exception/SectionException.java
@@ -0,0 +1,14 @@
+package subway.exception;
+
+public class SectionException extends IllegalArgumentException {
+ private final ErrorCode errorCode;
+
+ public SectionException(ErrorCode errorCode) {
+ super(errorCode.getMessage());
+ this.errorCode = errorCode;
+ }
+
+ public ErrorCode getErrorCode() {
+ return errorCode;
+ }
+}
diff --git a/src/main/java/subway/exception/SelectionException.java b/src/main/java/subway/exception/SelectionException.java
new file mode 100644
index 000000000..751b82072
--- /dev/null
+++ b/src/main/java/subway/exception/SelectionException.java
@@ -0,0 +1,15 @@
+package subway.exception;
+
+public class SelectionException extends IllegalArgumentException {
+ private final ErrorCode errorCode;
+
+ public SelectionException(ErrorCode errorCode) {
+ super(errorCode.getMessage());
+ this.errorCode = errorCode;
+ }
+
+ public ErrorCode getErrorCode() {
+ return errorCode;
+ }
+}
+
diff --git a/src/main/java/subway/exception/StationException.java b/src/main/java/subway/exception/StationException.java
new file mode 100644
index 000000000..d5d928fe7
--- /dev/null
+++ b/src/main/java/subway/exception/StationException.java
@@ -0,0 +1,14 @@
+package subway.exception;
+
+public class StationException extends IllegalArgumentException {
+ private final ErrorCode errorCode;
+
+ public StationException(ErrorCode errorCode) {
+ super(errorCode.getMessage());
+ this.errorCode = errorCode;
+ }
+
+ public ErrorCode getErrorCode() {
+ return errorCode;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/subway/view/InputView.java b/src/main/java/subway/view/InputView.java
new file mode 100644
index 000000000..520577799
--- /dev/null
+++ b/src/main/java/subway/view/InputView.java
@@ -0,0 +1,15 @@
+package subway.view;
+
+import java.util.Scanner;
+
+public class InputView {
+ private final Scanner scanner;
+
+ public InputView(Scanner scanner) {
+ this.scanner = scanner;
+ }
+
+ public String inputNextLine() {
+ return scanner.nextLine();
+ }
+}
diff --git a/src/main/java/subway/view/OutputView.java b/src/main/java/subway/view/OutputView.java
new file mode 100644
index 000000000..0f4cab5fc
--- /dev/null
+++ b/src/main/java/subway/view/OutputView.java
@@ -0,0 +1,42 @@
+package subway.view;
+
+public class OutputView {
+ private static final int START_INDEX = 0;
+
+ private final StringBuilder sb;
+
+ public OutputView(StringBuilder sb) {
+ this.sb = sb;
+ }
+
+ public void printOptions(String[] strings) {
+ sb.append(Prefix.ENTER.getPrefix());
+ for (String string : strings) {
+ sb.append(string).append(Prefix.ENTER.getPrefix());
+ }
+ sb.append(Prefix.ENTER.getPrefix());
+ sb.append(Prefix.CHOOSE_FUNCTION.getPrefix());
+ System.out.println(sb.toString());
+ clearSb();
+ }
+
+ public void printSharp(String text) {
+ sb.append(Prefix.ENTER.getPrefix());
+ sb.append(Prefix.SHARP.getPrefix());
+ sb.append(text);
+
+ System.out.println(sb.toString());
+ clearSb();
+ }
+
+ public void printInfos(String string) {
+ sb.append(Prefix.INFO.getPrefix());
+ sb.append(string);
+ System.out.println(sb.toString());
+ clearSb();
+ }
+
+ private void clearSb() {
+ sb.delete(START_INDEX, sb.length());
+ }
+}
diff --git a/src/main/java/subway/view/Prefix.java b/src/main/java/subway/view/Prefix.java
new file mode 100644
index 000000000..dbe7d9357
--- /dev/null
+++ b/src/main/java/subway/view/Prefix.java
@@ -0,0 +1,25 @@
+package subway.view;
+
+public enum Prefix {
+ ERROR("[ERROR] "),
+ INFO("[INFO] "),
+ SHARP("## "),
+ ONE("1. "),
+ TWO("2. "),
+ QUIT("Q. "),
+ BACK("B. "),
+ ENTER("\n"),
+ CONTOUR("---"),
+ CHOOSE_FUNCTION(SHARP.getPrefix() + "원하는 기능을 선택하세요.");
+
+
+ private String prefix;
+
+ Prefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+}
diff --git a/src/main/java/subway/view/screen/MainView.java b/src/main/java/subway/view/screen/MainView.java
new file mode 100644
index 000000000..7d38c5b8c
--- /dev/null
+++ b/src/main/java/subway/view/screen/MainView.java
@@ -0,0 +1,19 @@
+package subway.view.screen;
+
+import subway.view.OutputView;
+import subway.view.Prefix;
+
+public class MainView {
+ private static final String MAIN = Prefix.SHARP.getPrefix() + "메인 화면";
+ private static final String SEARCH = Prefix.ONE.getPrefix() + "경로 조회";
+ private static final String QUIT = Prefix.QUIT.getPrefix() + "종료";
+ private final OutputView outputView;
+
+ public MainView(OutputView outputView) {
+ this.outputView = outputView;
+ }
+
+ public void showOptions() {
+ outputView.printOptions(new String[]{MAIN, SEARCH, QUIT});
+ }
+}
diff --git a/src/main/java/subway/view/screen/SearchView.java b/src/main/java/subway/view/screen/SearchView.java
new file mode 100644
index 000000000..966fec1a3
--- /dev/null
+++ b/src/main/java/subway/view/screen/SearchView.java
@@ -0,0 +1,71 @@
+package subway.view.screen;
+
+import org.jgrapht.GraphPath;
+import subway.view.OutputView;
+import subway.view.Prefix;
+
+public class SearchView {
+ private static final String MAIN = Prefix.SHARP.getPrefix() + "경로 기준";
+ private static final String DISTANCE = Prefix.ONE.getPrefix() + "최단 거리";
+ private static final String TIME = Prefix.TWO.getPrefix() + "최소 시간";
+ private static final String BACK = Prefix.BACK.getPrefix() + "돌아가기";
+ private static final String PRINT_ADD = "출발역을 입력하세요.";
+ private static final String PRINT_ADD_SECOND = "도착역을 입력하세요.";
+ private static final String PRINT_AFTER_ADD = "조회결과";
+
+ private final OutputView outputView;
+
+ public SearchView(OutputView outputView) {
+ this.outputView = outputView;
+ }
+
+ public void showOptions() {
+ outputView.printOptions(new String[]{MAIN, DISTANCE, TIME, BACK});
+ }
+
+ public void printAdd() {
+ outputView.printSharp(PRINT_ADD);
+ }
+
+ public void printAfterAdd() {
+ outputView.printSharp(PRINT_AFTER_ADD);
+ }
+
+ public void printSecondAdd() {
+ outputView.printSharp(PRINT_ADD_SECOND);
+ }
+
+ public void printDistanceList(GraphPath path, double pathWeight) {
+ outputView.printInfos(Prefix.CONTOUR.getPrefix());
+ outputView.printInfos("총 거리: " + (int)pathWeight + "km");
+ outputView.printInfos(Prefix.CONTOUR.getPrefix());
+ path.getEdgeList().stream()
+ .forEach(edge -> {
+ String tmp = edge.toString();
+ int index = tmp.indexOf(":");
+ String substring = tmp.substring(1, index);
+ outputView.printInfos(substring);
+ });
+ String lastText = path.getEdgeList().get(path.getEdgeList().size() - 1).toString();
+ int index = lastText.indexOf(":");
+ String substring = lastText.substring(index + 2, lastText.length() -1);
+ outputView.printInfos(substring);
+ }
+
+ public void printTimeList(GraphPath path, double pathWeight) {
+ outputView.printInfos(Prefix.CONTOUR.getPrefix());
+ outputView.printInfos("총 시간: " + (int)pathWeight + "분");
+ outputView.printInfos(Prefix.CONTOUR.getPrefix());
+ path.getEdgeList().stream()
+ .forEach(edge -> {
+ String tmp = edge.toString();
+ int index = tmp.indexOf(":");
+ String substring = tmp.substring(1, index);
+ outputView.printInfos(substring);
+ });
+ String lastText = path.getEdgeList().get(path.getEdgeList().size() - 1).toString();
+ int index = lastText.indexOf(":");
+ String substring = lastText.substring(index + 2, lastText.length() -1);
+ outputView.printInfos(substring);
+ }
+}
diff --git a/src/main/java/subway/view/selection/MainSelection.java b/src/main/java/subway/view/selection/MainSelection.java
new file mode 100644
index 000000000..3162f19fc
--- /dev/null
+++ b/src/main/java/subway/view/selection/MainSelection.java
@@ -0,0 +1,35 @@
+package subway.view.selection;
+
+import subway.exception.ErrorCode;
+import subway.exception.SelectionException;
+
+public class MainSelection {
+ private final static String OPTION_ONE = "1";
+ private final static String OPTION_QUIT = "Q";
+ private final static String OPTION_QUIT_LOWERCASE = "q";
+
+ private final String option;
+
+ public MainSelection(String option) {
+ this.option = option;
+ validate(option);
+ }
+
+ private void validate(String option) {
+ if (!option.equals(OPTION_ONE) && !option.equals(OPTION_QUIT) && !option.equals(OPTION_QUIT_LOWERCASE)) {
+ throw new SelectionException(ErrorCode.INVALID_INPUT_VALUE);
+ }
+ }
+
+ public String getOption() {
+ return option;
+ }
+
+ public boolean isOptionOne() {
+ return option.equals(OPTION_ONE);
+ }
+
+ public boolean isQuit() {
+ return option.equals(OPTION_QUIT) | option.equals(OPTION_QUIT_LOWERCASE);
+ }
+}
diff --git a/src/main/java/subway/view/selection/SearchSelection.java b/src/main/java/subway/view/selection/SearchSelection.java
new file mode 100644
index 000000000..22e6844da
--- /dev/null
+++ b/src/main/java/subway/view/selection/SearchSelection.java
@@ -0,0 +1,41 @@
+package subway.view.selection;
+
+import subway.exception.ErrorCode;
+import subway.exception.SelectionException;
+
+public class SearchSelection {
+ private final static String OPTION_ONE = "1";
+ private final static String OPTION_TWO = "2";
+ private final static String OPTION_BACK = "B";
+ private final static String OPTION_BACK_LOWERCASE = "b";
+
+ private final String option;
+
+ public SearchSelection(String option) {
+ this.option = option;
+ validate(option);
+ }
+
+ private void validate(String option) {
+ if (!option.equals(OPTION_ONE) && !option.equals(OPTION_TWO)
+ && !option.equals(OPTION_BACK) && !option.equals(OPTION_BACK_LOWERCASE)) {
+ throw new SelectionException(ErrorCode.INVALID_INPUT_VALUE);
+ }
+ }
+
+ public String getOption() {
+ return option;
+ }
+
+ public boolean isOptionOne() {
+ return option.equals(OPTION_ONE);
+ }
+
+ public boolean isOptionTwo() {
+ return option.equals(OPTION_TWO);
+ }
+
+ public boolean isBack() {
+ return option.equals(OPTION_BACK) | option.equals(OPTION_BACK_LOWERCASE);
+ }
+}
diff --git a/src/test/java/subway/JGraphtTest.java b/src/test/java/subway/JGraphtTest.java
index 4f5f76536..5cfd1ebff 100644
--- a/src/test/java/subway/JGraphtTest.java
+++ b/src/test/java/subway/JGraphtTest.java
@@ -17,12 +17,14 @@ public void getDijkstraShortestPath() {
graph.addVertex("v2");
graph.addVertex("v3");
graph.setEdgeWeight(graph.addEdge("v1", "v2"), 2);
- graph.setEdgeWeight(graph.addEdge("v2", "v3"), 2);
+ graph.setEdgeWeight(graph.addEdge("v2", "v3"), 3);
graph.setEdgeWeight(graph.addEdge("v1", "v3"), 100);
DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(graph);
List shortestPath = dijkstraShortestPath.getPath("v3", "v1").getVertexList();
+ double pathWeight = dijkstraShortestPath.getPathWeight("v3", "v1");
assertThat(shortestPath.size()).isEqualTo(3);
+ assertThat(pathWeight).isEqualTo(5);
}
}
diff --git a/src/test/java/subway/domain/line/LineServiceTest.java b/src/test/java/subway/domain/line/LineServiceTest.java
new file mode 100644
index 000000000..dbe44f5df
--- /dev/null
+++ b/src/test/java/subway/domain/line/LineServiceTest.java
@@ -0,0 +1,36 @@
+package subway.domain.line;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import subway.domain.line.dto.LineSaveReqDto;
+import subway.exception.ErrorCode;
+import subway.exception.LineException;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.*;
+
+class LineServiceTest {
+ LineService lineService;
+
+ @BeforeEach
+ void before() {
+ lineService = new LineService();
+ }
+
+ @Test
+ @DisplayName("이미 등록된 노선일 시 에러가 발생한다. ")
+ void testDuplicateSave() {
+ //given
+ String line = "1호선";
+ String line2 = "1호선";
+
+ //when
+ lineService.saveLine(new LineSaveReqDto(line));
+
+ //then
+ assertThatThrownBy(() -> lineService.saveLine(new LineSaveReqDto(line2)))
+ .isInstanceOf(LineException.class)
+ .hasMessage(ErrorCode.LINE_ALREADY_EXIST.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/subway/domain/line/LineTest.java b/src/test/java/subway/domain/line/LineTest.java
new file mode 100644
index 000000000..530fcb16e
--- /dev/null
+++ b/src/test/java/subway/domain/line/LineTest.java
@@ -0,0 +1,75 @@
+package subway.domain.line;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import subway.exception.ErrorCode;
+import subway.exception.LineException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class LineTest {
+ @Test
+ @DisplayName("숫자, 한글이 포함된 노선을 저장할 수 있다")
+ void testSave() {
+ //given
+ String line = "1호선";
+ String line2 = "2호선";
+
+ //when
+ Line saveLine = new Line(line);
+ Line saveLine2 = new Line(line2);
+
+ //then
+ assertThat(saveLine.getName()).isEqualTo(line);
+ assertThat(saveLine2.getName()).isEqualTo(line2);
+ }
+
+ @Test
+ @DisplayName("2글자 미만인 구간의 이름이 들어올 시 에러가 발생한다.")
+ void testLengthError() {
+ //given
+ String line = "선";
+ String line2 = "샨";
+
+ //then
+ assertThatThrownBy(() -> new Line(line))
+ .isInstanceOf(LineException.class)
+ .hasMessage(ErrorCode.LINE_NAME_LENGTH_ERROR.getMessage());
+ assertThatThrownBy(() -> new Line(line2))
+ .isInstanceOf(LineException.class)
+ .hasMessage(ErrorCode.LINE_NAME_LENGTH_ERROR.getMessage());
+ }
+
+ @Test
+ @DisplayName("한글, 숫자가 아닌 이름이 들어올 시 에러가 발생한다.")
+ void testSaveError() {
+ //given
+ String line = "Q선";
+ String line2 = "기 선";
+
+ //then
+ assertThatThrownBy(() -> new Line(line))
+ .isInstanceOf(LineException.class)
+ .hasMessage(ErrorCode.LINE_INVALID_CHARACTER.getMessage());
+ assertThatThrownBy(() -> new Line(line2))
+ .isInstanceOf(LineException.class)
+ .hasMessage(ErrorCode.LINE_INVALID_CHARACTER.getMessage());
+ }
+
+ @Test
+ @DisplayName("마지막 글자가 선이 아닐 시 에러가 발생한다.")
+ void testLastNameError() {
+ //given
+ String line = "1호션";
+ String line2 = "2호신";
+
+ //then
+ assertThatThrownBy(() -> new Line(line))
+ .isInstanceOf(LineException.class)
+ .hasMessage(ErrorCode.LINE_INVALID_LAST_NAME.getMessage());
+ assertThatThrownBy(() -> new Line(line2))
+ .isInstanceOf(LineException.class)
+ .hasMessage(ErrorCode.LINE_INVALID_LAST_NAME.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/subway/domain/section/SectionServiceTest.java b/src/test/java/subway/domain/section/SectionServiceTest.java
new file mode 100644
index 000000000..f64e72f91
--- /dev/null
+++ b/src/test/java/subway/domain/section/SectionServiceTest.java
@@ -0,0 +1,117 @@
+package subway.domain.section;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import subway.domain.section.dto.SectionSaveReqDto;
+import subway.domain.section.dto.SectionStationAddReqDto;
+import subway.domain.station.StationService;
+import subway.domain.station.dto.StationSaveReqDto;
+import subway.exception.ErrorCode;
+import subway.exception.SectionException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.*;
+
+class SectionServiceTest {
+ SectionService sectionService;
+ StationService stationService;
+
+ @BeforeEach
+ void before() {
+ sectionService = new SectionService(new SectionRepository());
+ stationService = new StationService();
+ String stationName = "행복역";
+ String stationName2 = "사랑역";
+ String stationName3 = "희망역";
+ String stationName4 = "소망역";
+ stationService.saveStation(new StationSaveReqDto(stationName));
+ stationService.saveStation(new StationSaveReqDto(stationName2));
+ stationService.saveStation(new StationSaveReqDto(stationName3));
+ stationService.saveStation(new StationSaveReqDto(stationName4));
+
+ String lineName = "1호선";
+ String upwardName = "행복역";
+ String downwardName = "사랑역";
+ sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName));
+ sectionService.addStation(new SectionStationAddReqDto(lineName, stationName3, 2));
+ }
+
+ @AfterEach
+ void after() {
+ stationService.removeAll();
+ sectionService.removeAll();
+ }
+
+ @Test
+ @DisplayName("노선을 저장한다")
+ void testSaved() {
+ //given
+ String lineName = "2호선";
+ String upwardName = "희망역";
+ String downwardName = "소망역";
+
+ //when
+ Section savedSection = sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName));
+
+ //then
+ assertThat(savedSection.getLineName()).isEqualTo(lineName);
+ }
+
+ @Test
+ @DisplayName("이미 저장된 노선일 시 에러가 발생한다.")
+ void testAlreadySavedError() {
+ //given
+ String lineName = "1호선";
+ String upwardName = "희망역";
+ String downwardName = "소망역";
+
+ //then
+ assertThatThrownBy(() -> sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName)))
+ .isInstanceOf(SectionException.class)
+ .hasMessage(ErrorCode.LINE_ALREADY_EXIST.getMessage());
+ }
+
+ @Test
+ @DisplayName("등룍하려는 상행 종점역이 존재하지 않으면 에러가 발생한다")
+ void testUpwardNotFound() {
+ //given
+ String lineName = "2호선";
+ String upwardName = "역곡역";
+ String downwardName = "소망역";
+
+ //then
+ assertThatThrownBy(() -> sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName)))
+ .isInstanceOf(SectionException.class);
+ }
+
+ @Test
+ @DisplayName("등룍하려는 하행 종점역이 존재하지 않으면 에러가 발생한다")
+ void testDownwardNotFound() {
+ //given
+ String lineName = "2호선";
+ String upwardName = "소망역";
+ String downwardName = "역곡역";
+
+ //then
+ assertThatThrownBy(() -> sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName)))
+ .isInstanceOf(SectionException.class);
+ }
+
+ @Test
+ @DisplayName("등룍하려는 하행 종점역이 앞서 등록한 상행 종점역일 시 에러가 발생한다")
+ void testDownwardSaveError() {
+ //given
+ String lineName = "2호선";
+ String upwardName = "소망역";
+ String downwardName = "소망역";
+
+ //then
+ assertThatThrownBy(() -> sectionService.saveSection(new SectionSaveReqDto(lineName, upwardName, downwardName)))
+ .isInstanceOf(SectionException.class)
+ .hasMessage(ErrorCode.SECTION_SAME_STATION_NAME.getMessage());
+ }
+}
+
diff --git a/src/test/java/subway/domain/station/StationServiceTest.java b/src/test/java/subway/domain/station/StationServiceTest.java
new file mode 100644
index 000000000..70d0ab6a3
--- /dev/null
+++ b/src/test/java/subway/domain/station/StationServiceTest.java
@@ -0,0 +1,50 @@
+package subway.domain.station;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import subway.domain.station.dto.StationSaveReqDto;
+import subway.exception.ErrorCode;
+import subway.exception.StationException;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class StationServiceTest {
+
+ StationService stationService;
+
+ @BeforeEach
+ void before() {
+ stationService = new StationService();
+ String stationName = "행복역";
+ String stationName2 = "사랑역";
+ String stationName3 = "희망역";
+ String stationName4 = "소망역";
+ stationService.saveStation(new StationSaveReqDto(stationName));
+ stationService.saveStation(new StationSaveReqDto(stationName2));
+ stationService.saveStation(new StationSaveReqDto(stationName3));
+ stationService.saveStation(new StationSaveReqDto(stationName4));
+ }
+
+ @AfterEach
+ void after() {
+ stationService.removeAll();
+ }
+
+ @Test
+ @DisplayName("이미 등록된 지하철 역일 시 에러가 발생한다. ")
+ void testDuplicateSave() {
+ //given
+ String name = "인천시청역";
+ String name2 = "인천시청역";
+
+ //when
+ Station savedIncheonStation = stationService.saveStation(new StationSaveReqDto(name));
+
+ //then
+ assertThatThrownBy(() -> stationService.saveStation(new StationSaveReqDto(name2)))
+ .isInstanceOf(StationException.class)
+ .hasMessage(ErrorCode.STATION_ALREADY_EXIST.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/subway/domain/station/StationTest.java b/src/test/java/subway/domain/station/StationTest.java
new file mode 100644
index 000000000..13aea2477
--- /dev/null
+++ b/src/test/java/subway/domain/station/StationTest.java
@@ -0,0 +1,81 @@
+package subway.domain.station;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import subway.exception.ErrorCode;
+import subway.exception.StationException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class StationTest {
+ @Test
+ @DisplayName("숫자, 한글이 포함된 역을 저장할 수 있다.")
+ void testStationSave() {
+ //given
+ String name = "하이2역";
+ String name2 = "바이역";
+
+ //when
+ Station stationName = new Station(name);
+ Station stationName2 = new Station(name2);
+
+ //then
+ assertThat(stationName.getName()).isEqualTo(name);
+ assertThat(stationName2.getName()).isEqualTo(name2);
+ }
+
+ @Test
+ @DisplayName("2글자 이하일 시 에러가 발생한다")
+ void testStationSaveLengthError() {
+ //given
+ String name = "하";
+ String name2 = "바";
+ String name3 = "";
+
+ //when
+
+ //then
+ assertThatThrownBy(() -> new Station(name))
+ .isInstanceOf(StationException.class)
+ .hasMessage(ErrorCode.STATION_NAME_LENGTH_ERROR.getMessage());
+ assertThatThrownBy(() -> new Station(name2))
+ .isInstanceOf(StationException.class)
+ .hasMessage(ErrorCode.STATION_NAME_LENGTH_ERROR.getMessage());
+ assertThatThrownBy(() -> new Station(name3))
+ .isInstanceOf(StationException.class)
+ .hasMessage(ErrorCode.STATION_NAME_LENGTH_ERROR.getMessage());
+ }
+
+ @Test
+ @DisplayName("저장할 이름의 마지막 글자가 '역'이 아니면 에러가 발생한다")
+ void testStationSaveLastNameError() {
+ //given
+ String name = "하이욕";
+ String name2 = "바이염";
+
+ //then
+ assertThatThrownBy(() -> new Station(name))
+ .isInstanceOf(StationException.class)
+ .hasMessage(ErrorCode.STATION_INVALID_LAST_NAME.getMessage());
+ assertThatThrownBy(() -> new Station(name2))
+ .isInstanceOf(StationException.class)
+ .hasMessage(ErrorCode.STATION_INVALID_LAST_NAME.getMessage());
+ }
+
+ @Test
+ @DisplayName("저장할 이름에 한글, 숫자 외의 문자가 들어오면 에러가 발생한다")
+ void testStationSaveInvalidCharacter() {
+ //given
+ String name = "하 역";
+ String name2 = "바e역";
+
+ //then
+ assertThatThrownBy(() -> new Station(name))
+ .isInstanceOf(StationException.class)
+ .hasMessage(ErrorCode.STATION_INVALID_CHARACTER.getMessage());
+ assertThatThrownBy(() -> new Station(name2))
+ .isInstanceOf(StationException.class)
+ .hasMessage(ErrorCode.STATION_INVALID_CHARACTER.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/subway/view/MainSelectionTest.java b/src/test/java/subway/view/MainSelectionTest.java
new file mode 100644
index 000000000..38f76d232
--- /dev/null
+++ b/src/test/java/subway/view/MainSelectionTest.java
@@ -0,0 +1,45 @@
+package subway.view;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import subway.exception.ErrorCode;
+import subway.exception.SelectionException;
+import subway.view.selection.MainSelection;
+
+import static org.assertj.core.api.Assertions.*;
+
+class MainSelectionTest {
+
+ @Test
+ @DisplayName("메인 옵션 선택시 보장된 입력 값만 입력해야한다.")
+ void testInput() {
+ //given
+ String inputOne = "1";
+ String inputQuit = "Q";
+
+ //when
+ MainSelection mainSelectionOne = new MainSelection(inputOne);
+ MainSelection mainSelectionQuit = new MainSelection(inputQuit);
+
+ //then
+ assertThat(mainSelectionOne.getOption()).isEqualTo(inputOne);
+ assertThat(mainSelectionQuit.getOption()).isEqualTo(inputQuit);
+ }
+
+ @Test
+ @DisplayName("메인 옵션 선택시 보장되지 않은 입력 값일 시 에러가 발생한다.")
+ void testInputError() {
+ //given
+ String inputWrong = "2";
+ String inputWrong2 = "0";
+
+ //then
+ assertThatThrownBy(() -> new MainSelection(inputWrong))
+ .isInstanceOf(SelectionException.class)
+ .hasMessage(ErrorCode.INVALID_INPUT_VALUE.getMessage());
+ assertThatThrownBy(() -> new MainSelection(inputWrong2))
+ .isInstanceOf(SelectionException.class)
+ .hasMessage(ErrorCode.INVALID_INPUT_VALUE.getMessage());
+
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/subway/view/SearchSelectionTest.java b/src/test/java/subway/view/SearchSelectionTest.java
new file mode 100644
index 000000000..3ce8b6de0
--- /dev/null
+++ b/src/test/java/subway/view/SearchSelectionTest.java
@@ -0,0 +1,52 @@
+package subway.view;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import subway.exception.ErrorCode;
+import subway.exception.SelectionException;
+import subway.view.selection.SearchSelection;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class SearchSelectionTest {
+
+ @Test
+ @DisplayName("메인 옵션 선택시 보장된 입력 값만 입력해야한다.")
+ void testInput() {
+ //given
+ String inputOne = "1";
+ String input2 = "2";
+ String input3 = "B";
+ String input4 = "b";
+
+ //when
+ SearchSelection searchSelection = new SearchSelection(inputOne);
+ SearchSelection searchSelection2 = new SearchSelection(input2);
+ SearchSelection searchSelection3 = new SearchSelection(input3);
+ SearchSelection searchSelection4 = new SearchSelection(input4);
+
+ //then
+ assertThat(searchSelection.getOption()).isEqualTo(inputOne);
+ assertThat(searchSelection2.getOption()).isEqualTo(input2);
+ assertThat(searchSelection3.getOption()).isEqualTo(input3);
+ assertThat(searchSelection4.getOption()).isEqualTo(input4);
+ }
+
+ @Test
+ @DisplayName("메인 옵션 선택시 보장되지 않은 입력 값일 시 에러가 발생한다.")
+ void testInputError() {
+ //given
+ String inputWrong = "3";
+ String inputWrong2 = "-b";
+
+ //then
+ assertThatThrownBy(() -> new SearchSelection(inputWrong))
+ .isInstanceOf(SelectionException.class)
+ .hasMessage(ErrorCode.INVALID_INPUT_VALUE.getMessage());
+ assertThatThrownBy(() -> new SearchSelection(inputWrong2))
+ .isInstanceOf(SelectionException.class)
+ .hasMessage(ErrorCode.INVALID_INPUT_VALUE.getMessage());
+
+ }
+}
\ No newline at end of file