From 9debdbd408cb20734f0865af32eaccea4472b61c Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 13:12:45 +0900 Subject: [PATCH 01/28] docs(README.md): add functions to implementation --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index d6299154c..e3e3db5e6 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,20 @@
+## 구현할 기능 + +- [ ] 구간 클래스 +- [ ] 구간 저장소 클래스 +- [ ] 초기 역을 설정하는 기능 +- [ ] 초기 노선을 설정하는 기능 +- [ ] 초기 구간 정보를 설정하는 기능 +- [ ] 출발/도착 역을 입력받는 기능 +- [ ] 입력받은 출발/도착 역 이름이 역 저장소에 있는지 검증하는 기능 +- [ ] 경로를 탐색하려는 A 역과 B 역이 같은지 검증하는 기능 +- [ ] A 역에서 B 역까지의 경로를 최단 거리로 조회하는 기능 +- [ ] A 역에서 B 역까지의 경로를 최소 시간으로 조회하는 기능 +- [ ] 조회한 경로를 총 거리, 총 소요 시간과 함께 출력하는 기능 + ## 🚀 기능 요구사항 > 프리코스 3주차 미션에서 사용한 코드를 참고해도 무관하다. From 976d4c9677710740865bb602f9094fd693de3e87 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 14:14:47 +0900 Subject: [PATCH 02/28] feat(Gap): add Gap class to save distance and time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 시간 및 거리 저장용 클래스 선언 --- README.md | 1 + src/main/java/subway/domain/Gap.java | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/main/java/subway/domain/Gap.java diff --git a/README.md b/README.md index e3e3db5e6..8a8bf6ff0 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ ## 구현할 기능 +- [X] 특정 구간 사이의 차이(시간, 거리)를 저장할 클래스 - [ ] 구간 클래스 - [ ] 구간 저장소 클래스 - [ ] 초기 역을 설정하는 기능 diff --git a/src/main/java/subway/domain/Gap.java b/src/main/java/subway/domain/Gap.java new file mode 100644 index 000000000..27c50ca79 --- /dev/null +++ b/src/main/java/subway/domain/Gap.java @@ -0,0 +1,20 @@ +package subway.domain; + +public class Gap { + + private final int time; + private final int distance; + + public Gap(final int time, final int distance) { + this.time = time; + this.distance = distance; + } + + public int getTime() { + return time; + } + + public int getDistance() { + return distance; + } +} From 982649d187b3f1a9b166dbe929ee0b20cff5819f Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 14:44:33 +0900 Subject: [PATCH 03/28] feat(Section): add Section class to save line-stations and gaps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 노선마다 존재하는 역들과 그 역 사이의 거리를 저장하는 구간 클래스 추가: - 역 목록이 두 개 이상으로 이루어져 있는지 검증 - 구간 목록이 한 개 이상으로 이루어져 있는지 검증 - 역 목록의 크기와 구간 목록의 크기가 1만큼 차이 나는지 검증 - 특정 색인의 역 얻어오기 - 특정 두 색인 사이의 차이 얻어오기 Section 유닛 테스트인 SectionTest 추가 --- README.md | 2 +- src/main/java/subway/domain/Section.java | 79 ++++++++++++++++++++ src/test/java/subway/domain/SectionTest.java | 75 +++++++++++++++++++ 3 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/main/java/subway/domain/Section.java create mode 100644 src/test/java/subway/domain/SectionTest.java diff --git a/README.md b/README.md index 8a8bf6ff0..dd946d4ba 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ## 구현할 기능 - [X] 특정 구간 사이의 차이(시간, 거리)를 저장할 클래스 -- [ ] 구간 클래스 +- [X] 구간 클래스 - [ ] 구간 저장소 클래스 - [ ] 초기 역을 설정하는 기능 - [ ] 초기 노선을 설정하는 기능 diff --git a/src/main/java/subway/domain/Section.java b/src/main/java/subway/domain/Section.java new file mode 100644 index 000000000..e6678602e --- /dev/null +++ b/src/main/java/subway/domain/Section.java @@ -0,0 +1,79 @@ +package subway.domain; + +import java.util.List; + +public class Section { + + private static final int MIN_STATIONS_SIZE = 2; + private static final int MIN_GAPS_SIZE = 1; + + private final Line line; + private final List stations; + private final List gaps; + + public Section(Line line, List stations, List gaps) + throws IllegalArgumentException { + validateStationsSize(stations); + validateGapsSize(gaps); + validateDifferenceBetweenStationsSizeAndGapsSize(stations, gaps); + this.line = line; + this.stations = stations; + this.gaps = gaps; + } + + private void validateStationsSize(List stations) throws IllegalArgumentException { + if (stations.size() < MIN_STATIONS_SIZE) { + throw new IllegalArgumentException(); + } + } + + private void validateGapsSize(List gaps) throws IllegalArgumentException { + if (gaps.size() < MIN_GAPS_SIZE) { + throw new IllegalArgumentException(); + } + } + + private void validateDifferenceBetweenStationsSizeAndGapsSize(List stations, + List gaps) throws IllegalArgumentException { + if (stations.size() != gaps.size() + 1) { + throw new IllegalArgumentException(); + } + } + + private void validateStationIndex(final int index) throws IllegalArgumentException { + if (index < 0 || index >= stations.size()) { + throw new IllegalArgumentException(); + } + } + + public Station getStationByIndex(final int index) throws IllegalArgumentException { + validateStationIndex(index); + return stations.get(index); + } + + private void validateIndexesDifference(final int indexAhead, final int indexBehind) + throws IllegalArgumentException { + if (Integer.min(indexAhead, indexBehind) + 1 != Integer.max(indexAhead, indexBehind)) { + throw new IllegalArgumentException(); + } + } + + private void validateIndexesRange(final int indexAhead, final int indexBehind) + throws IllegalArgumentException { + if (Integer.min(indexAhead, indexBehind) < 0 || + Integer.max(indexAhead, indexBehind) >= stations.size()) { + throw new IllegalArgumentException(); + } + } + + public Gap getGapByTwoIndexes(final int indexAhead, final int indexBehind) + throws IllegalArgumentException { + validateIndexesDifference(indexAhead, indexBehind); + validateIndexesRange(indexAhead, indexBehind); + return gaps.get(Integer.min(indexAhead, indexBehind)); + } + + public Line getLine() { + return line; + } +} diff --git a/src/test/java/subway/domain/SectionTest.java b/src/test/java/subway/domain/SectionTest.java new file mode 100644 index 000000000..356e055ee --- /dev/null +++ b/src/test/java/subway/domain/SectionTest.java @@ -0,0 +1,75 @@ +package subway.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class SectionTest { + + private static final String LINE_NAME = "2호선"; + private static final String[] STATION_NAMES = {"교대역", "강남역", "역삼역"}; + private static final int[][] GAPS = {{2, 3}, {2, 3}}; + private static final Line line = new Line(LINE_NAME); + private static final List stations = new LinkedList<>(); + private static final List gaps = new LinkedList<>(); + private static Section section; + + @BeforeAll + static void setUp() { + for (String stationName : STATION_NAMES) { + stations.add(new Station(stationName)); + } + for (int[] gap : GAPS) { + gaps.add(new Gap(gap[0], gap[1])); + } + section = new Section(line, stations, gaps); + } + + @Test + void getStationByIndex_ValidIndex_Pass() { + for (int i = 0; i < stations.size(); i++) { + assertThat(section.getStationByIndex(i)).isEqualTo(stations.get(i)); + } + } + + @Test + void getStationByIndex_InvalidIndex_ExceptionThrown() { + assertThatIllegalArgumentException().isThrownBy(() -> + section.getStationByIndex(-1) + ); + assertThatIllegalArgumentException().isThrownBy(() -> + section.getStationByIndex(stations.size()) + ); + } + + @Test + void getGapByTwoIndexes_ValidIndexes_Pass() { + assertThat(section.getGapByTwoIndexes(0, 1)).isEqualTo(gaps.get(0)); + } + + @Test + void getGapByTwoIndexes_InvalidIndexesDifference_ExceptionThrown() { + assertThatIllegalArgumentException().isThrownBy(() -> + section.getGapByTwoIndexes(0, 2) + ); + } + + @Test + void getGapByTwoIndexes_InvalidIndexesRange_ExceptionThrown() { + assertThatIllegalArgumentException().isThrownBy(() -> + section.getGapByTwoIndexes(-1, 0) + ); + assertThatIllegalArgumentException().isThrownBy(() -> + section.getGapByTwoIndexes(stations.size(), stations.size() - 1) + ); + } + + @Test + void getLine_SameLine_Pass() { + assertThat(section.getLine()).isEqualTo(line); + } +} \ No newline at end of file From a5d39e01f64fbe01c0bf43052e96ecffe20c57da Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 14:45:30 +0900 Subject: [PATCH 04/28] refactor(Gap): rearrange arguments of constructor --- src/main/java/subway/domain/Gap.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/subway/domain/Gap.java b/src/main/java/subway/domain/Gap.java index 27c50ca79..d8da36dfc 100644 --- a/src/main/java/subway/domain/Gap.java +++ b/src/main/java/subway/domain/Gap.java @@ -2,12 +2,12 @@ public class Gap { - private final int time; private final int distance; + private final int time; - public Gap(final int time, final int distance) { - this.time = time; + public Gap(final int distance, final int time) { this.distance = distance; + this.time = time; } public int getTime() { From d1481a27d03ad411dd4c09571de0ffb6a257edc4 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 15:11:30 +0900 Subject: [PATCH 05/28] feat(SectionRepository): add repository class for Section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 구간을 저장해 둘 저장소 클래스와 하위 메소드 선언: - 저장소에 같은 노선 이름을 지닌 구간이 있는지 검증 - 저장소에 구간 추가 - 저장소에서 특정 노선 이름을 가진 구간 제거 - 저장소 비우기 유닛 테스트 추가 (SectionRepositoryTest) --- README.md | 2 +- .../java/subway/domain/SectionRepository.java | 35 ++++++++ .../subway/domain/SectionRepositoryTest.java | 79 +++++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/main/java/subway/domain/SectionRepository.java create mode 100644 src/test/java/subway/domain/SectionRepositoryTest.java diff --git a/README.md b/README.md index dd946d4ba..a885679ce 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - [X] 특정 구간 사이의 차이(시간, 거리)를 저장할 클래스 - [X] 구간 클래스 -- [ ] 구간 저장소 클래스 +- [X] 구간 저장소 클래스 - [ ] 초기 역을 설정하는 기능 - [ ] 초기 노선을 설정하는 기능 - [ ] 초기 구간 정보를 설정하는 기능 diff --git a/src/main/java/subway/domain/SectionRepository.java b/src/main/java/subway/domain/SectionRepository.java new file mode 100644 index 000000000..1a98db59b --- /dev/null +++ b/src/main/java/subway/domain/SectionRepository.java @@ -0,0 +1,35 @@ +package subway.domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class SectionRepository { + + private static final List
sections = new ArrayList<>(); + + public static List
sections() { + return Collections.unmodifiableList(sections); + } + + private static void validateSectionLineNameDuplicate(String lineName) + throws IllegalArgumentException { + if (sections.stream().anyMatch(section -> section.getLine().getName().equals(lineName))) { + throw new IllegalArgumentException(); + } + } + + public static void addSection(Section section) throws IllegalArgumentException { + validateSectionLineNameDuplicate(section.getLine().getName()); + sections.add(section); + } + + public static boolean deleteSectionByLineName(String lineName) { + return sections.removeIf(section -> Objects.equals(section.getLine().getName(), lineName)); + } + + public static void deleteAll() { + sections.clear(); + } +} diff --git a/src/test/java/subway/domain/SectionRepositoryTest.java b/src/test/java/subway/domain/SectionRepositoryTest.java new file mode 100644 index 000000000..d4e12d19f --- /dev/null +++ b/src/test/java/subway/domain/SectionRepositoryTest.java @@ -0,0 +1,79 @@ +package subway.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNoException; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class SectionRepositoryTest { + + private static final String[] LINE_NAMES = {"2호선", "3호선", "신분당선"}; + private static final String[][] STATION_NAMES_IN_LINES = { + {"교대역", "강남역", "역삼역"}, + {"교대역", "남부터미널역", "양재역", "매봉역"}, + {"강남역", "양재역", "양재시민의숲역"} + }; + private static final int[][][] GAPS_IN_LINES = { + {{2, 3}, {2, 3}}, + {{3, 2}, {6, 5}, {1, 1}}, + {{2, 8}, {10, 3}} + }; + + private static final List
sections = new ArrayList<>(); + + @BeforeAll + static void setUpBeforeAll() { + for (int i = 0; i < LINE_NAMES.length; i++) { + final Line line = new Line(LINE_NAMES[i]); + final List stations = new LinkedList<>(); + final List gaps = new LinkedList<>(); + for (String stationName : STATION_NAMES_IN_LINES[i]) { + stations.add(new Station(stationName)); + } + for (int[] gap : GAPS_IN_LINES[i]) { + gaps.add(new Gap(gap[0], gap[1])); + } + sections.add(new Section(line, stations, gaps)); + } + } + + @BeforeEach + void setUp() { + SectionRepository.deleteAll(); + for (int i = 0; i < sections.size() - 1; i++) { + SectionRepository.addSection(sections.get(i)); + } + + } + + @Test + void addSection_NameDuplicate_ExceptionThrown() { + assertThatIllegalArgumentException().isThrownBy(() -> + SectionRepository.addSection(sections.get(0)) + ); + } + + @Test + void addSection_ValidItem_NoExceptionThrown() { + assertThatNoException().isThrownBy(() -> + SectionRepository.addSection(sections.get(sections.size() - 1)) + ); + } + + @Test + void deleteSectionByLineName_LineNotExist_False() { + assertThat(SectionRepository.deleteSectionByLineName(LINE_NAMES[sections.size() - 1])) + .isFalse(); + } + + @Test + void deleteSectionByLineName_ValidName_True() { + assertThat(SectionRepository.deleteSectionByLineName(LINE_NAMES[0])).isTrue(); + } +} From 55d1747cf0b8f647a2e28e0ef3fbbc0f5f66646a Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 15:37:09 +0900 Subject: [PATCH 06/28] feat(Constants): add class for constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 상수를 Constants 클래스로 분리 같은 값들이 각종 테스트와 초기화 클래스에 반복적으로 사용되는 것을 고려하여 새로운 클래스를 생성했습니다. --- README.md | 1 + src/main/java/subway/util/Constants.java | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/main/java/subway/util/Constants.java diff --git a/README.md b/README.md index a885679ce..fd7ae7aa4 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ - [X] 특정 구간 사이의 차이(시간, 거리)를 저장할 클래스 - [X] 구간 클래스 - [X] 구간 저장소 클래스 +- [X] 초기 역/노선/구간 정보를 저장할 상수 클래스 - [ ] 초기 역을 설정하는 기능 - [ ] 초기 노선을 설정하는 기능 - [ ] 초기 구간 정보를 설정하는 기능 diff --git a/src/main/java/subway/util/Constants.java b/src/main/java/subway/util/Constants.java new file mode 100644 index 000000000..c71a5806a --- /dev/null +++ b/src/main/java/subway/util/Constants.java @@ -0,0 +1,18 @@ +package subway.util; + +public class Constants { + + public static final String[] INITIAL_LINE_NAMES = {"2호선", "3호선", "신분당선"}; + public static final String[][] INITIAL_STATION_NAMES_IN_LINES = { + {"교대역", "강남역", "역삼역"}, + {"교대역", "남부터미널역", "양재역", "매봉역"}, + {"강남역", "양재역", "양재시민의숲역"} + }; + public static final int[][][] INITIAL_GAPS_BETWEEN_STATIONS_OF_SECTIONS = { + {{2, 3}, {2, 3}}, + {{3, 2}, {6, 5}, {1, 1}}, + {{2, 8}, {10, 3}} + }; + + private Constants() {} +} From 14da704c91c655fb6c24cd3da1d85da85d6a6eb7 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 15:37:51 +0900 Subject: [PATCH 07/28] refactor(SectionRepositoryTest): fix implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Constants 내의 상수를 쓰도록 코드 수정 --- .../subway/domain/SectionRepositoryTest.java | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/test/java/subway/domain/SectionRepositoryTest.java b/src/test/java/subway/domain/SectionRepositoryTest.java index d4e12d19f..5913a833e 100644 --- a/src/test/java/subway/domain/SectionRepositoryTest.java +++ b/src/test/java/subway/domain/SectionRepositoryTest.java @@ -10,33 +10,22 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import subway.util.Constants; class SectionRepositoryTest { - private static final String[] LINE_NAMES = {"2호선", "3호선", "신분당선"}; - private static final String[][] STATION_NAMES_IN_LINES = { - {"교대역", "강남역", "역삼역"}, - {"교대역", "남부터미널역", "양재역", "매봉역"}, - {"강남역", "양재역", "양재시민의숲역"} - }; - private static final int[][][] GAPS_IN_LINES = { - {{2, 3}, {2, 3}}, - {{3, 2}, {6, 5}, {1, 1}}, - {{2, 8}, {10, 3}} - }; - private static final List
sections = new ArrayList<>(); @BeforeAll static void setUpBeforeAll() { - for (int i = 0; i < LINE_NAMES.length; i++) { - final Line line = new Line(LINE_NAMES[i]); + for (int i = 0; i < Constants.INITIAL_LINE_NAMES.length; i++) { + final Line line = new Line(Constants.INITIAL_LINE_NAMES[i]); final List stations = new LinkedList<>(); final List gaps = new LinkedList<>(); - for (String stationName : STATION_NAMES_IN_LINES[i]) { + for (String stationName : Constants.INITIAL_STATION_NAMES_IN_LINES[i]) { stations.add(new Station(stationName)); } - for (int[] gap : GAPS_IN_LINES[i]) { + for (int[] gap : Constants.INITIAL_GAPS_BETWEEN_STATIONS_OF_SECTIONS[i]) { gaps.add(new Gap(gap[0], gap[1])); } sections.add(new Section(line, stations, gaps)); @@ -68,12 +57,16 @@ void addSection_ValidItem_NoExceptionThrown() { @Test void deleteSectionByLineName_LineNotExist_False() { - assertThat(SectionRepository.deleteSectionByLineName(LINE_NAMES[sections.size() - 1])) - .isFalse(); + assertThat( + SectionRepository + .deleteSectionByLineName(Constants.INITIAL_LINE_NAMES[sections.size() - 1]) + ).isFalse(); } @Test void deleteSectionByLineName_ValidName_True() { - assertThat(SectionRepository.deleteSectionByLineName(LINE_NAMES[0])).isTrue(); + assertThat( + SectionRepository.deleteSectionByLineName(Constants.INITIAL_LINE_NAMES[0]) + ).isTrue(); } } From 2f73e3f363e63be6da779e901396b5f3f79d3097 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 15:52:20 +0900 Subject: [PATCH 08/28] docs(README.md): add new implementations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 역/노선 저장소 내에 중복된 이름이 있는지 검증하는 기능 추가 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fd7ae7aa4..a3d9a067b 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ - [X] 특정 구간 사이의 차이(시간, 거리)를 저장할 클래스 - [X] 구간 클래스 - [X] 구간 저장소 클래스 +- [ ] 역 저장소 내에 중복된 이름이 있는지 검증하는 기능 +- [ ] 노선 저장소 내에 중복된 이름이 있는지 검증하는 기능 - [X] 초기 역/노선/구간 정보를 저장할 상수 클래스 - [ ] 초기 역을 설정하는 기능 - [ ] 초기 노선을 설정하는 기능 From fca4545e909c4270b4f301b647ffeefc0352b5bf Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 15:54:29 +0900 Subject: [PATCH 09/28] fix(StationRepository): add validation for name duplicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 저장소 내에 같은 이름을 지닌 역이 있는지 검증하는 메소드 추가 addStation 수정 --- src/main/java/subway/domain/StationRepository.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/StationRepository.java index 8ed9d103f..686278763 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/StationRepository.java @@ -6,13 +6,22 @@ import java.util.Objects; public class StationRepository { + private static final List stations = new ArrayList<>(); public static List stations() { return Collections.unmodifiableList(stations); } - public static void addStation(Station station) { + private static void validateStationNameDuplicate(String stationName) + throws IllegalArgumentException { + if (stations.stream().anyMatch(station -> station.getName().equals(stationName))) { + throw new IllegalArgumentException(); + } + } + + public static void addStation(Station station) throws IllegalArgumentException { + validateStationNameDuplicate(station.getName()); stations.add(station); } From a795163683947e40540e26f6ed561ce519a7803f Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 16:13:29 +0900 Subject: [PATCH 10/28] test(StationRepository): add unit tests --- .../subway/domain/StationRepositoryTest.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/test/java/subway/domain/StationRepositoryTest.java diff --git a/src/test/java/subway/domain/StationRepositoryTest.java b/src/test/java/subway/domain/StationRepositoryTest.java new file mode 100644 index 000000000..b9f5019d5 --- /dev/null +++ b/src/test/java/subway/domain/StationRepositoryTest.java @@ -0,0 +1,62 @@ +package subway.domain; + +import static java.util.stream.Collectors.toList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNoException; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import subway.util.Constants; + +class StationRepositoryTest { + + private static final List stationNames = new ArrayList<>(); + private static final List stations = new ArrayList<>(); + + private static final String NON_EXIST_STATION_NAME = "존재하지않는역"; + + @BeforeAll + static void setUpBeforeAll() { + for (String[] stationNameArray : Constants.INITIAL_STATION_NAMES_IN_LINES) { + stationNames.addAll(Arrays.stream(stationNameArray) + .filter(stationName -> !stationNames.contains(stationName)) + .collect(toList())); + } + stationNames.forEach(stationName -> stations.add(new Station(stationName))); + } + + @BeforeEach + void setUp() { + StationRepository.deleteAll(); + stations.forEach(StationRepository::addStation); + } + + @Test + void addStation_NameDuplicated_ExceptionThrown() { + assertThatIllegalArgumentException().isThrownBy(() -> + StationRepository.addStation(stations.get(0)) + ); + } + + @Test + void addStation_ValidItem_NoExceptionThrown() { + assertThatNoException().isThrownBy(() -> + StationRepository.addStation(new Station(NON_EXIST_STATION_NAME)) + ); + } + + @Test + void deleteStation_InvalidItem_False() { + assertThat(StationRepository.deleteStation(NON_EXIST_STATION_NAME)).isFalse(); + } + + @Test + void deleteStation_ValidItem_True() { + assertThat(StationRepository.deleteStation(stations.get(0).getName())).isTrue(); + } +} From 3ed48f45fca3c31b0c3542b026bc5a3cd1904ec3 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 16:15:50 +0900 Subject: [PATCH 11/28] fix(LineRepository): add validation for name duplicate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 저장소 내에 같은 이름을 지닌 노선이 있는지 검증하는 메소드 추가 addLine 수정 --- src/main/java/subway/domain/LineRepository.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/LineRepository.java index 2c4a723c9..c1e9660f5 100644 --- a/src/main/java/subway/domain/LineRepository.java +++ b/src/main/java/subway/domain/LineRepository.java @@ -12,7 +12,14 @@ public static List lines() { return Collections.unmodifiableList(lines); } - public static void addLine(Line line) { + private static void validateLineNameDuplicate(String lineName) throws IllegalArgumentException { + if (lines.stream().anyMatch(line -> line.getName().equals(lineName))) { + throw new IllegalArgumentException(); + } + } + + public static void addLine(Line line) throws IllegalArgumentException { + validateLineNameDuplicate(line.getName()); lines.add(line); } From a457c9c0e22b7d2b4b9c86a0b868efd6e033b38e Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 16:22:00 +0900 Subject: [PATCH 12/28] test(LineRepository): add unit tests --- .../subway/domain/LineRepositoryTest.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/test/java/subway/domain/LineRepositoryTest.java diff --git a/src/test/java/subway/domain/LineRepositoryTest.java b/src/test/java/subway/domain/LineRepositoryTest.java new file mode 100644 index 000000000..ea8ce3727 --- /dev/null +++ b/src/test/java/subway/domain/LineRepositoryTest.java @@ -0,0 +1,57 @@ +package subway.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.assertThatNoException; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import subway.util.Constants; + +class LineRepositoryTest { + + private static final List lines = new ArrayList<>(); + + private static final String NON_EXIST_LINE_NAME = "존재하지않는노선"; + + @BeforeAll + static void setUpBeforeAll() { + Arrays.asList(Constants.INITIAL_LINE_NAMES) + .forEach(lineName -> lines.add(new Line(lineName))); + } + + @BeforeEach + void setUp() { + LineRepository.deleteAll(); + lines.forEach(LineRepository::addLine); + } + + @Test + void addLine_NameDuplicated_ExceptionThrown() { + assertThatIllegalArgumentException().isThrownBy(() -> + LineRepository.addLine(lines.get(0)) + ); + } + + @Test + void addLine_ValidItem_NoExceptionThrown() { + assertThatNoException().isThrownBy(() -> + LineRepository.addLine(new Line(NON_EXIST_LINE_NAME)) + ); + } + + @Test + void deleteLineByName_InvalidItem_False() { + assertThat(LineRepository.deleteLineByName(NON_EXIST_LINE_NAME)).isFalse(); + } + + @Test + void deleteLineByName_ValidItem_True() { + assertThat(LineRepository.deleteLineByName(lines.get(0).getName())).isTrue(); + } + +} From c5efcf75090ad1f0b5c94852ba7451ecf16f40ce Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 16:23:00 +0900 Subject: [PATCH 13/28] fix(README.md): tick commit implementation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a3d9a067b..73b07bdcf 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ - [X] 특정 구간 사이의 차이(시간, 거리)를 저장할 클래스 - [X] 구간 클래스 - [X] 구간 저장소 클래스 -- [ ] 역 저장소 내에 중복된 이름이 있는지 검증하는 기능 -- [ ] 노선 저장소 내에 중복된 이름이 있는지 검증하는 기능 +- [X] 역 저장소 내에 중복된 이름이 있는지 검증하는 기능 +- [X] 노선 저장소 내에 중복된 이름이 있는지 검증하는 기능 - [X] 초기 역/노선/구간 정보를 저장할 상수 클래스 - [ ] 초기 역을 설정하는 기능 - [ ] 초기 노선을 설정하는 기능 From 96e3cae7181e92795aa43a83270f7701c747dafe Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 16:24:54 +0900 Subject: [PATCH 14/28] feat(subway.util): add Initializer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 저장소 초기화를 위한 클래스 추가 --- src/main/java/subway/util/Initializer.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/subway/util/Initializer.java diff --git a/src/main/java/subway/util/Initializer.java b/src/main/java/subway/util/Initializer.java new file mode 100644 index 000000000..284f7d0c5 --- /dev/null +++ b/src/main/java/subway/util/Initializer.java @@ -0,0 +1,8 @@ +package subway.util; + +public class Initializer { + + private Initializer() { + } + +} From 2a230678d2625c008f2f8aa0aa4a3c6e5ab8da52 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 16:26:10 +0900 Subject: [PATCH 15/28] feat(Initializer): add station repository initializer method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 역 저장소를 초기화하는 메소드 추가 --- README.md | 2 +- src/main/java/subway/util/Initializer.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 73b07bdcf..c652164c5 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ - [X] 역 저장소 내에 중복된 이름이 있는지 검증하는 기능 - [X] 노선 저장소 내에 중복된 이름이 있는지 검증하는 기능 - [X] 초기 역/노선/구간 정보를 저장할 상수 클래스 -- [ ] 초기 역을 설정하는 기능 +- [X] 초기 역을 설정하는 기능 - [ ] 초기 노선을 설정하는 기능 - [ ] 초기 구간 정보를 설정하는 기능 - [ ] 출발/도착 역을 입력받는 기능 diff --git a/src/main/java/subway/util/Initializer.java b/src/main/java/subway/util/Initializer.java index 284f7d0c5..909329cb8 100644 --- a/src/main/java/subway/util/Initializer.java +++ b/src/main/java/subway/util/Initializer.java @@ -1,8 +1,22 @@ package subway.util; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import subway.domain.Station; +import subway.domain.StationRepository; + public class Initializer { private Initializer() { } + private static void InitializeStationRepository() { + final Set stationNameSet = new HashSet<>(); + for (String[] stationNames : Constants.INITIAL_STATION_NAMES_IN_LINES) { + stationNameSet.addAll(Arrays.asList(stationNames)); + } + stationNameSet + .forEach(stationName -> StationRepository.addStation(new Station(stationName))); + } } From 3f42377ae1efbb81faeb13a94686f9671eae9dba Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 16:28:50 +0900 Subject: [PATCH 16/28] feat(Initializer): add methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 노선 저장소를 초기화하는 메소드 추가 저장소를 모두 초기화 요청할 때 사용할 public 메소드 추가 --- src/main/java/subway/util/Initializer.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/subway/util/Initializer.java b/src/main/java/subway/util/Initializer.java index 909329cb8..d71774e5d 100644 --- a/src/main/java/subway/util/Initializer.java +++ b/src/main/java/subway/util/Initializer.java @@ -3,6 +3,8 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import subway.domain.Line; +import subway.domain.LineRepository; import subway.domain.Station; import subway.domain.StationRepository; @@ -11,7 +13,7 @@ public class Initializer { private Initializer() { } - private static void InitializeStationRepository() { + private static void initializeStationRepository() { final Set stationNameSet = new HashSet<>(); for (String[] stationNames : Constants.INITIAL_STATION_NAMES_IN_LINES) { stationNameSet.addAll(Arrays.asList(stationNames)); @@ -19,4 +21,14 @@ private static void InitializeStationRepository() { stationNameSet .forEach(stationName -> StationRepository.addStation(new Station(stationName))); } + + private static void initializeLineRepository() { + Arrays.asList(Constants.INITIAL_LINE_NAMES) + .forEach(lineName -> LineRepository.addLine(new Line(lineName))); + } + + public static void initializeRepositories() { + initializeStationRepository(); + initializeLineRepository(); + } } From a948fcb230aedb01731d4ed7a0a74f26c40f632d Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:04:21 +0900 Subject: [PATCH 17/28] feat(StationRepository): add getStationByName method --- src/main/java/subway/domain/StationRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/StationRepository.java index 686278763..648d0468b 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/StationRepository.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; public class StationRepository { @@ -20,6 +21,10 @@ private static void validateStationNameDuplicate(String stationName) } } + public static Optional getStationByName(String name) { + return stations.stream().filter(station -> station.getName().equals(name)).findFirst(); + } + public static void addStation(Station station) throws IllegalArgumentException { validateStationNameDuplicate(station.getName()); stations.add(station); From 94260a27ea272933fd08582e5a07bd75fa0ff72d Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:04:30 +0900 Subject: [PATCH 18/28] feat(LineRepository): add getLineByName method --- src/main/java/subway/domain/LineRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/LineRepository.java index c1e9660f5..ad08aa980 100644 --- a/src/main/java/subway/domain/LineRepository.java +++ b/src/main/java/subway/domain/LineRepository.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; public class LineRepository { private static final List lines = new ArrayList<>(); @@ -18,6 +19,10 @@ private static void validateLineNameDuplicate(String lineName) throws IllegalArg } } + public static Optional getLineByName(String name) { + return lines.stream().filter(line -> line.getName().equals(name)).findFirst(); + } + public static void addLine(Line line) throws IllegalArgumentException { validateLineNameDuplicate(line.getName()); lines.add(line); From 395e88baac91db129f3bcba92369cdce57fb2919 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:06:30 +0900 Subject: [PATCH 19/28] feat(SectionRepository): add addSectionByName and corresponding methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 노선 이름, 역 이름 배열, 구간 간격 리스트를 이용하여 구간을 추가하는 메소드 추가 노선 저장소로부터 노선을 가져오는 메소드 추가 역 저장소로부터 역을 가져오는 메소드 추가 --- .../java/subway/domain/SectionRepository.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/subway/domain/SectionRepository.java b/src/main/java/subway/domain/SectionRepository.java index 1a98db59b..0074e1667 100644 --- a/src/main/java/subway/domain/SectionRepository.java +++ b/src/main/java/subway/domain/SectionRepository.java @@ -1,9 +1,12 @@ package subway.domain; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.Optional; public class SectionRepository { @@ -25,6 +28,32 @@ public static void addSection(Section section) throws IllegalArgumentException { sections.add(section); } + private static Line getLineFromOptional(Optional optionalLine) + throws IllegalArgumentException { + if (optionalLine.isEmpty()) { + throw new IllegalArgumentException(); + } + return optionalLine.get(); + } + + private static Station getStationFromOptional(Optional optionalStation) + throws IllegalArgumentException { + if (optionalStation.isEmpty()) { + throw new IllegalArgumentException(); + } + return optionalStation.get(); + } + + public static void addSectionByNames(String lineName, String[] stationNames, List gaps) + throws IllegalArgumentException { + final Line sectionLine = getLineFromOptional(LineRepository.getLineByName(lineName)); + final List stations = new LinkedList<>(); + Arrays.stream(stationNames).forEach(stationName -> + stations.add(getStationFromOptional(StationRepository.getStationByName(stationName))) + ); + addSection(new Section(sectionLine, stations, gaps)); + } + public static boolean deleteSectionByLineName(String lineName) { return sections.removeIf(section -> Objects.equals(section.getLine().getName(), lineName)); } From cdc60a86c86d4d0a93c4e6d828e49ef5ee4eef8d Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:07:21 +0900 Subject: [PATCH 20/28] feat(Initializer) add section repository initializer method --- README.md | 4 ++-- src/main/java/subway/util/Initializer.java | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c652164c5..1cdacfa1d 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ - [X] 노선 저장소 내에 중복된 이름이 있는지 검증하는 기능 - [X] 초기 역/노선/구간 정보를 저장할 상수 클래스 - [X] 초기 역을 설정하는 기능 -- [ ] 초기 노선을 설정하는 기능 -- [ ] 초기 구간 정보를 설정하는 기능 +- [X] 초기 노선을 설정하는 기능 +- [X] 초기 구간 정보를 설정하는 기능 - [ ] 출발/도착 역을 입력받는 기능 - [ ] 입력받은 출발/도착 역 이름이 역 저장소에 있는지 검증하는 기능 - [ ] 경로를 탐색하려는 A 역과 B 역이 같은지 검증하는 기능 diff --git a/src/main/java/subway/util/Initializer.java b/src/main/java/subway/util/Initializer.java index d71774e5d..5fb548acb 100644 --- a/src/main/java/subway/util/Initializer.java +++ b/src/main/java/subway/util/Initializer.java @@ -2,9 +2,13 @@ import java.util.Arrays; import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; import java.util.Set; +import subway.domain.Gap; import subway.domain.Line; import subway.domain.LineRepository; +import subway.domain.SectionRepository; import subway.domain.Station; import subway.domain.StationRepository; @@ -15,7 +19,7 @@ private Initializer() { private static void initializeStationRepository() { final Set stationNameSet = new HashSet<>(); - for (String[] stationNames : Constants.INITIAL_STATION_NAMES_IN_LINES) { + for (final String[] stationNames : Constants.INITIAL_STATION_NAMES_IN_LINES) { stationNameSet.addAll(Arrays.asList(stationNames)); } stationNameSet @@ -27,8 +31,23 @@ private static void initializeLineRepository() { .forEach(lineName -> LineRepository.addLine(new Line(lineName))); } + + private static void initializeSectionRepository() { + for (int i = 0; i < Constants.INITIAL_LINE_NAMES.length; i++) { + final List gaps = new LinkedList<>(); + Arrays.asList(Constants.INITIAL_GAPS_BETWEEN_STATIONS_OF_SECTIONS[i]) + .forEach(gap -> gaps.add(new Gap(gap[0], gap[1]))); + SectionRepository.addSectionByNames( + Constants.INITIAL_LINE_NAMES[i], + Constants.INITIAL_STATION_NAMES_IN_LINES[i], + gaps + ); + } + } + public static void initializeRepositories() { initializeStationRepository(); initializeLineRepository(); + initializeSectionRepository(); } } From a1fa3e7f74f9a50654d3a3096be488f94fd6fcb6 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:36:22 +0900 Subject: [PATCH 21/28] feat(ErrorMessage) add enum for error messages --- .../java/subway/message/ErrorMessage.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/main/java/subway/message/ErrorMessage.java diff --git a/src/main/java/subway/message/ErrorMessage.java b/src/main/java/subway/message/ErrorMessage.java new file mode 100644 index 000000000..13dcc050f --- /dev/null +++ b/src/main/java/subway/message/ErrorMessage.java @@ -0,0 +1,58 @@ +package subway.message; + +import subway.domain.Section; + +public enum ErrorMessage { + + // 역 관련 에러 메시지 + // STATION_INVALID_NAME_LENGTH(String.format("역 이름은 %d자 이상이어야 합니다.", MIN_STATION_NAME_LENGTH)), + + // 노선 관련 에러 메시지 + // LINE_INVALID_NAME_LENGTH(String.format("노선 이름은 %d자 이상이어야 합니다.", MIN_LINE_NAME_LENGTH)), + LINE_STATION_INDEX_OUT_OF_RANGE("역을 추가하려는 위치가 할당될 수 없는 위치입니다."), + LINE_STATION_DOES_NOT_EXIST("제거하려는 역은 해당 노선에 없는 역입니다."), + + // 구간 관련 에러 메시지 + SECTION_ITEM_DUPLICATED("구간에는 같은 역이 여러 개 존재할 수 없습니다."), + SECTION_STATIONS_TOO_SMALL(String.format("구간에는 최소 %d개의 역이 존재하여야 합니다.", Section.MIN_STATIONS_SIZE)), + SECTION_GAPS_TOO_SMALL(String.format("구간에는 최소 %d개의 간격이 존재하여야 합니다.", Section.MIN_GAPS_SIZE)), + SECTION_STATION_ALREADY_EXIST("추가하려는 역은 이미 해당 구간에 포함된 역입니다."), + SECTION_GAPS_STATIONS_DIFFERENCE("구간의 크기는 역의 크기보다 1 작아야 합니다."), + SECTION_STATION_INDEX_OUT_OF_RANGE("색인의 범위가 구간 내 역 갯수 범위를 초과했습니다."), + SECTION_STATION_INDEXES_DIFFERENCE("두 색인의 차는 1이어야 합니다."), + + // 역 저장소 관련 에러 메시지 + STATION_REPOSITORY_STATION_ALREADY_EXIST("이미 등록된 역 이름입니다."), + STATION_REPOSITORY_STATION_DOES_NOT_EXIST("존재하지 않는 역 이름입니다."), + STATION_REPOSITORY_STATION_HAS_PARENT("구간에서 사용중인 역은 삭제할 수 없습니다."), + STATION_REPOSITORY_EMPTY("역 저장소가 비어 있습니다."), + + // 노선 저장소 관련 에러 메시지 + LINE_REPOSITORY_LINE_ALREADY_EXIST("이미 등록된 노선 이름입니다."), + LINE_REPOSITORY_LINE_DOES_NOT_EXIST("존재하지 않는 노선 이름입니다."), + LINE_REPOSITORY_EMPTY("노선 저장소가 비어 있습니다."), + + // 구간 저장소 관련 에러 메시지 + SECTION_REPOSITORY_LINE_ALREADY_EXIST("추가하려는 노선은 이미 구간 내에 존재합니다."), + + // 메뉴 선택 관련 에러 메시지 + MENU_INVALID_SELECTION("선택할 수 없는 기능입니다."), + + // 입력 관련 에러 메시지 + INPUT_EMPTY_STRING("빈 문장은 입력할 수 없습니다."), + INPUT_INVALID_STRING("올바르지 않은 입력 형식입니다."), + + ; + + private final String message; + + ErrorMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + return message; + } + +} From e804c59d6da6c1836f9b8c6eceee34aff3ccdfe4 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:37:35 +0900 Subject: [PATCH 22/28] refactor(subway.domain): add error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ErrorMessage 열거형을 사용하여 반환하도록 지정 --- .../java/subway/domain/LineRepository.java | 15 ++++---- src/main/java/subway/domain/Section.java | 29 +++++++++++----- .../java/subway/domain/SectionRepository.java | 34 +++++++------------ .../java/subway/domain/StationRepository.java | 18 +++++----- 4 files changed, 52 insertions(+), 44 deletions(-) diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/LineRepository.java index ad08aa980..0b5ffbf89 100644 --- a/src/main/java/subway/domain/LineRepository.java +++ b/src/main/java/subway/domain/LineRepository.java @@ -4,23 +4,26 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Optional; +import subway.message.ErrorMessage; public class LineRepository { + private static final List lines = new ArrayList<>(); public static List lines() { return Collections.unmodifiableList(lines); } - private static void validateLineNameDuplicate(String lineName) throws IllegalArgumentException { - if (lines.stream().anyMatch(line -> line.getName().equals(lineName))) { - throw new IllegalArgumentException(); + public static void validateLineNameDuplicate(String lineName) throws IllegalArgumentException { + if (lineNameExists(lineName)) { + throw new IllegalArgumentException( + ErrorMessage.LINE_REPOSITORY_LINE_ALREADY_EXIST.toString() + ); } } - public static Optional getLineByName(String name) { - return lines.stream().filter(line -> line.getName().equals(name)).findFirst(); + private static boolean lineNameExists(String name) { + return lines.stream().anyMatch(line -> line.getName().equals(name)); } public static void addLine(Line line) throws IllegalArgumentException { diff --git a/src/main/java/subway/domain/Section.java b/src/main/java/subway/domain/Section.java index e6678602e..f4d15281b 100644 --- a/src/main/java/subway/domain/Section.java +++ b/src/main/java/subway/domain/Section.java @@ -1,11 +1,12 @@ package subway.domain; import java.util.List; +import subway.message.ErrorMessage; public class Section { - private static final int MIN_STATIONS_SIZE = 2; - private static final int MIN_GAPS_SIZE = 1; + public static final int MIN_STATIONS_SIZE = 2; + public static final int MIN_GAPS_SIZE = 1; private final Line line; private final List stations; @@ -23,26 +24,34 @@ public Section(Line line, List stations, List gaps) private void validateStationsSize(List stations) throws IllegalArgumentException { if (stations.size() < MIN_STATIONS_SIZE) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + ErrorMessage.SECTION_STATIONS_TOO_SMALL.toString() + ); } } private void validateGapsSize(List gaps) throws IllegalArgumentException { if (gaps.size() < MIN_GAPS_SIZE) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + ErrorMessage.SECTION_GAPS_TOO_SMALL.toString() + ); } } private void validateDifferenceBetweenStationsSizeAndGapsSize(List stations, List gaps) throws IllegalArgumentException { if (stations.size() != gaps.size() + 1) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + ErrorMessage.SECTION_GAPS_STATIONS_DIFFERENCE.toString() + ); } } private void validateStationIndex(final int index) throws IllegalArgumentException { if (index < 0 || index >= stations.size()) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + ErrorMessage.SECTION_STATION_INDEX_OUT_OF_RANGE.toString() + ); } } @@ -54,7 +63,9 @@ public Station getStationByIndex(final int index) throws IllegalArgumentExceptio private void validateIndexesDifference(final int indexAhead, final int indexBehind) throws IllegalArgumentException { if (Integer.min(indexAhead, indexBehind) + 1 != Integer.max(indexAhead, indexBehind)) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + ErrorMessage.SECTION_STATION_INDEXES_DIFFERENCE.toString() + ); } } @@ -62,7 +73,9 @@ private void validateIndexesRange(final int indexAhead, final int indexBehind) throws IllegalArgumentException { if (Integer.min(indexAhead, indexBehind) < 0 || Integer.max(indexAhead, indexBehind) >= stations.size()) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + ErrorMessage.SECTION_STATION_INDEX_OUT_OF_RANGE.toString() + ); } } diff --git a/src/main/java/subway/domain/SectionRepository.java b/src/main/java/subway/domain/SectionRepository.java index 0074e1667..a35048398 100644 --- a/src/main/java/subway/domain/SectionRepository.java +++ b/src/main/java/subway/domain/SectionRepository.java @@ -6,7 +6,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; -import java.util.Optional; +import subway.message.ErrorMessage; public class SectionRepository { @@ -19,7 +19,9 @@ public static List
sections() { private static void validateSectionLineNameDuplicate(String lineName) throws IllegalArgumentException { if (sections.stream().anyMatch(section -> section.getLine().getName().equals(lineName))) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException( + ErrorMessage.SECTION_REPOSITORY_LINE_ALREADY_EXIST.toString() + ); } } @@ -28,29 +30,17 @@ public static void addSection(Section section) throws IllegalArgumentException { sections.add(section); } - private static Line getLineFromOptional(Optional optionalLine) - throws IllegalArgumentException { - if (optionalLine.isEmpty()) { - throw new IllegalArgumentException(); - } - return optionalLine.get(); - } - - private static Station getStationFromOptional(Optional optionalStation) - throws IllegalArgumentException { - if (optionalStation.isEmpty()) { - throw new IllegalArgumentException(); - } - return optionalStation.get(); - } - public static void addSectionByNames(String lineName, String[] stationNames, List gaps) throws IllegalArgumentException { - final Line sectionLine = getLineFromOptional(LineRepository.getLineByName(lineName)); + LineRepository.validateLineNameDuplicate(lineName); + final Line sectionLine = LineRepository.lines().stream() + .filter(line -> line.getName().equals(lineName)).findFirst().get(); final List stations = new LinkedList<>(); - Arrays.stream(stationNames).forEach(stationName -> - stations.add(getStationFromOptional(StationRepository.getStationByName(stationName))) - ); + Arrays.stream(stationNames).forEach(stationName -> { + StationRepository.validateStationNameDuplicate(stationName); + stations.add(StationRepository.stations().stream() + .filter(station -> station.getName().equals(stationName)).findFirst().get()); + }); addSection(new Section(sectionLine, stations, gaps)); } diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/StationRepository.java index 648d0468b..c6c393e3b 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/StationRepository.java @@ -4,7 +4,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Optional; +import subway.message.ErrorMessage; public class StationRepository { @@ -14,15 +14,17 @@ public static List stations() { return Collections.unmodifiableList(stations); } - private static void validateStationNameDuplicate(String stationName) - throws IllegalArgumentException { - if (stations.stream().anyMatch(station -> station.getName().equals(stationName))) { - throw new IllegalArgumentException(); - } + private static boolean stationNameExists(String name) { + return stations.stream().anyMatch(station -> station.getName().equals(name)); } - public static Optional getStationByName(String name) { - return stations.stream().filter(station -> station.getName().equals(name)).findFirst(); + public static void validateStationNameDuplicate(String stationName) + throws IllegalArgumentException { + if (stationNameExists(stationName)) { + throw new IllegalArgumentException( + ErrorMessage.STATION_REPOSITORY_STATION_ALREADY_EXIST.toString() + ); + } } public static void addStation(Station station) throws IllegalArgumentException { From 405d45316b9ba63c88b516aa66b77b9200a72bc4 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:48:05 +0900 Subject: [PATCH 23/28] refactor(StationRepository): add validateStationNameExist method --- src/main/java/subway/domain/StationRepository.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/StationRepository.java index c6c393e3b..39d8f6ea4 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/StationRepository.java @@ -27,6 +27,15 @@ public static void validateStationNameDuplicate(String stationName) } } + public static void validateStationNameExist(String stationName) + throws IllegalArgumentException { + if (!stationNameExists(stationName)) { + throw new IllegalArgumentException( + ErrorMessage.STATION_REPOSITORY_STATION_DOES_NOT_EXIST.toString() + ); + } + } + public static void addStation(Station station) throws IllegalArgumentException { validateStationNameDuplicate(station.getName()); stations.add(station); From 006deb956a43ffe9875eaf9068d7a61f8e067a48 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:54:09 +0900 Subject: [PATCH 24/28] feat(ConsoleOutput): add console output class --- src/main/java/subway/ui/ConsoleOutput.java | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/subway/ui/ConsoleOutput.java diff --git a/src/main/java/subway/ui/ConsoleOutput.java b/src/main/java/subway/ui/ConsoleOutput.java new file mode 100644 index 000000000..0f819134e --- /dev/null +++ b/src/main/java/subway/ui/ConsoleOutput.java @@ -0,0 +1,38 @@ +package subway.ui; + +public class ConsoleOutput { + private static final String GENERAL_MESSAGE_HEADER = "## "; + private static final String ERROR_MESSAGE_HEADER = "[ERROR] "; + private static final String INFO_MESSAGE_HEADER = "[INFO] "; + + private static final String GENERAL_MESSAGE_MAIN = "메인 화면"; + private static final String GENERAL_MESSAGE_PATH = "경로 기준"; + + private static final String GENERAL_MESSAGE_FUNCTION = "원하는 기능을 선택하세요."; + + private ConsoleOutput() { + } + + public static void printGeneralMessage(String message) { + System.out.println(); + System.out.println(GENERAL_MESSAGE_HEADER + message); + } + + public static void printErrorMessage(String errorMessage) { + System.out.println(); + System.out.println(ERROR_MESSAGE_HEADER + errorMessage); + } + + public static void printInfoMessage(String infoMessage) { + System.out.println(INFO_MESSAGE_HEADER + infoMessage); + } + + + public static void printMainMenu() { + printGeneralMessage(GENERAL_MESSAGE_MAIN); + for (MainMenuEnum mainMenuEnum : MainMenuEnum.values()) { + System.out.println(mainMenuEnum.getShortcut() + ". " + mainMenuEnum.getName()); + } + printGeneralMessage(GENERAL_MESSAGE_FUNCTION); + } +} From 8eb7b37b617c6e7221cc43312eee70b732557e08 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:54:21 +0900 Subject: [PATCH 25/28] feat(ConsoleInput): add console input class --- src/main/java/subway/ui/ConsoleInput.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/main/java/subway/ui/ConsoleInput.java diff --git a/src/main/java/subway/ui/ConsoleInput.java b/src/main/java/subway/ui/ConsoleInput.java new file mode 100644 index 000000000..fb2acbe81 --- /dev/null +++ b/src/main/java/subway/ui/ConsoleInput.java @@ -0,0 +1,22 @@ +package subway.ui; + +import java.util.Scanner; +import subway.message.ErrorMessage; + +public class ConsoleInput { + + private ConsoleInput() { + } + + public static String scanLine(final Scanner scanner) throws IllegalArgumentException { + final String lineInput = scanner.nextLine(); + validateLineInputNotEmpty(lineInput); + return lineInput; + } + + private static void validateLineInputNotEmpty(final String lineInput) { + if (lineInput.isEmpty()) { + throw new IllegalArgumentException(ErrorMessage.INPUT_EMPTY_STRING.toString()); + } + } +} From 832c5ca78bdec6e40a3b876e174c737784924424 Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:55:52 +0900 Subject: [PATCH 26/28] feat(MainMenu): add main menu class --- src/main/java/subway/ui/MainMenu.java | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/subway/ui/MainMenu.java diff --git a/src/main/java/subway/ui/MainMenu.java b/src/main/java/subway/ui/MainMenu.java new file mode 100644 index 000000000..31e549c40 --- /dev/null +++ b/src/main/java/subway/ui/MainMenu.java @@ -0,0 +1,38 @@ +package subway.ui; + +import java.util.Optional; +import java.util.Scanner; +import subway.message.ErrorMessage; + +public class MainMenu { + + private final Scanner scanner; + + public MainMenu(Scanner scanner) { + this.scanner = scanner; + } + + public void run() { + while (true) { + ConsoleOutput.printMainMenu(); + String userInput; + try { + userInput = ConsoleInput.scanLine(scanner); + } catch (IllegalArgumentException e) { + ConsoleOutput.printErrorMessage(e.getMessage()); + continue; + } + Optional optional = MainMenuEnum.of(userInput); + if (optional.isEmpty()) { + ConsoleOutput.printErrorMessage(ErrorMessage.INPUT_INVALID_STRING.toString()); + continue; + } + MainMenuEnum mainMenuEnum = optional.get(); + if (mainMenuEnum.equals(MainMenuEnum.EXIT)) { + break; + } + mainMenuEnum.action(scanner); + } + } + +} From d7b250f6c3d1fd48a31d7cf1a4d2e53f804c69bf Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:56:01 +0900 Subject: [PATCH 27/28] feat(MainMenuEnum): add main menu enum --- src/main/java/subway/ui/MainMenuEnum.java | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/main/java/subway/ui/MainMenuEnum.java diff --git a/src/main/java/subway/ui/MainMenuEnum.java b/src/main/java/subway/ui/MainMenuEnum.java new file mode 100644 index 000000000..01352ae83 --- /dev/null +++ b/src/main/java/subway/ui/MainMenuEnum.java @@ -0,0 +1,53 @@ +package subway.ui; + +import static java.util.stream.Collectors.toMap; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Scanner; + +public enum MainMenuEnum { + SEARCH_PATH("경로 조회", "1") { + @Override + public void action(final Scanner scanner) { + } + }, + EXIT("종료", "Q") { + @Override + public void action(final Scanner scanner) { + } + }, + ; + + private static final Map MAP; + + static { + Map mainMenuEnumMap = Arrays.stream(values()) + .collect(toMap(mainMenuEnum -> mainMenuEnum.shortcut, e -> e)); + MAP = Collections.unmodifiableMap(mainMenuEnumMap); + } + + private final String name; + private final String shortcut; + + MainMenuEnum(String name, String shortcut) { + this.name = name; + this.shortcut = shortcut; + } + + public static Optional of(final String shortcut) { + return Optional.ofNullable(MAP.get(shortcut)); + } + + public abstract void action(final Scanner scanner); + + public String getName() { + return name; + } + + public String getShortcut() { + return shortcut; + } +} From 60e2e0bd04eae7e2fe2b627c3a127258b5e25bff Mon Sep 17 00:00:00 2001 From: Hansaem Woo Date: Sat, 19 Dec 2020 17:56:51 +0900 Subject: [PATCH 28/28] feat(ConsoleProgram): add console program class --- src/main/java/subway/ui/ConsoleProgram.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/subway/ui/ConsoleProgram.java diff --git a/src/main/java/subway/ui/ConsoleProgram.java b/src/main/java/subway/ui/ConsoleProgram.java new file mode 100644 index 000000000..95b81c329 --- /dev/null +++ b/src/main/java/subway/ui/ConsoleProgram.java @@ -0,0 +1,20 @@ +package subway.ui; + +import java.util.Scanner; +import subway.util.Initializer; + +public class ConsoleProgram { + + private final Scanner scanner; + + public ConsoleProgram(Scanner scanner) { + this.scanner = scanner; + } + + public void run() { + Initializer.initializeRepositories(); + MainMenu mainMenu = new MainMenu(scanner); + mainMenu.run(); + } + +}