From 97d9861b86abbb2064c6d2682f84a4a8a8f3ddc5 Mon Sep 17 00:00:00 2001 From: Taehwa Lee Date: Sat, 19 Dec 2020 14:12:25 +0900 Subject: [PATCH 1/8] =?UTF-8?q?docs:=20docs/README.md=20=EC=97=90=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=A9=ED=96=A5=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/README.md | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 doc/README.md diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 000000000..7dbb8fbf1 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,146 @@ +### 초기 설정 +- [ ] 프로그램 시작 시 역, 노선, 구간 정보를 초기 설정 해야 한다. + - 거리와 소요 시간은 양의 정수이며 단위는 km와 분을 의미한다. + - 아래의 사전 등록 정보로 반드시 초기 설정을 한다. + +``` + 1. 지하철역으로 교대역, 강남역, 역삼역, 남부터미널역, 양재역, 양재시민의숲역, 매봉역이 등록되어 있다. + 2. 지하철 노선으로 2호선, 3호선, 신분당선이 등록되어 있다. + 3. 노선에 역이 아래와 같이 등록되어 있다.(왼쪽 끝이 상행 종점) + - 2호선: 교대역 - ( 2km / 3분 ) - 강남역 - ( 2km / 3분 ) - 역삼역 + - 3호선: 교대역 - ( 3km / 2분 ) - 남부터미널역 - ( 6km / 5분 ) - 양재역 - ( 1km / 1분 ) - 매봉역 + - 신분당선: 강남역 - ( 2km / 8분 ) - 양재역 - ( 10km / 3분 ) - 양재시민의숲역 + ``` + +### 지하철 역 기능 +- [ ] 지하철 역을 생성할 수 있다. + - 지하철 역 생성 시 이름을 입력받는다. + - 예외 처리 + - [ ] 지하철 역 이름은 2글자 이상이어야 한다. + +### 지하철 역 관리 기능 +- [ ] 지하철 역 저장소에 지하철 역을 등록할 수 있다. + - 예외 처리 + - [ ] 중복된 지하철 역 이름이 등록될 수 없다. + +### 지하철 노선 기능 +- [ ] 지하철 노선을 생성할 수 있다. + - [ ] 노선 생성 시 이름, 상행 종점역, 하행 종점역을 입력받는다. + - 예외 처리 + - [ ] 지하철 노선 이름은 2글자 이상이어야 한다. + - [ ] 상행 종점역과 하행 종점역이 같을 수는 없다. + +### 지하철 노선 관리 기능 +- [ ] 지하철 노선 저장소에 지하철 노선을 등록할 수 있다. + - 예외 처리 + - [ ] 중복된 지하철 노선 이름이 등록될 수 없다. + +### 지하철 구간 기능 +- [ ] 지하철 구간을 생성할 수 있다. + - LineStation은 JGrapht의 Edge 정보(거리, 시간)를 생성자 인자로 받는다. + - 거리, 시간을 수정하면 거리, 시간 관리 그래프에도 반영되어야 한다. + +### 지하철 구간 관리 기능 +- [ ] 지하철 노선 저장소에서 지하철 노선에 구간을 추가할 수 있다. + - [ ] 해당 노선에 이미 존재하는 지하철 역은 추가할 수 없다. + - 순서 + 1. 거리 그래프 관리 객체에 추가할 역을 Vertex로 추가한다. + 2. 거리 그래프 관리 객체에 해당 노선의 하행 끝 역과 추가할 역의 JGrapht Edge를 만든다. + 3. 거리 그래프 관리 객체에 해당 JGrapht Edge에 weight을 설정해서 추가한다. + 4. 시간 그래프 관리 객체에 추가할 역을 Vertex로 추가한다. + 5. 시간 그래프 관리 객체에 해당 노선의 하행 끝 역과 추가할 역의 JGrapht Edge를 만든다. + 7. 시간 그래프 관리 객체에 해당 JGrapht Edge에 weight을 설정해서 추가한다. + 8. LineStation의 속성으로 위의 두 JGrapht Edge를 설정하여 생성한 뒤에 노선의 하행 끝 뒤에 추가한다. + +### 경로 관리 기능 +- [ ] 거리 그래프 객체와 시간 그래프 객체를 가지고 있다. +- [ ] 출발역과 도착역을 입력받아 최단 거리 경로를 조회한다. +- [ ] 출발역과 도착역을 입력받아 최소 시간 경로를 조회한다. + - 경로 조회 시 총 거리, 총 소요 시간도 함께 출력한다. + - 예외 처리 + - [ ] 경로 조회 시 출발역과 도착역이 같으면 에러를 출력한다. + - [ ] 경로 조회 시 출발역과 도착역이 연결되어 있지 않으면 에러를 출력한다. + +
+ +## ✍🏻 입출력 요구사항 +- `프로그래밍 실행 결과 예시`와 동일하게 입출력을 구현한다. +- 기대하는 출력 결과는 `[INFO]`를 붙여서 출력한다. 출력값의 형식은 예시와 동일하게 한다. +- 에러 발생 시 `[ERROR]`를 붙여서 출력한다. 에러의 문구는 자유롭게 작성한다. + +### 💻 프로그래밍 실행 결과 예시 +#### 경로 조회 +``` +## 메인 화면 +1. 경로 조회 +Q. 종료 + +## 원하는 기능을 선택하세요. +1 + +## 경로 기준 +1. 최단 거리 +2. 최소 시간 +B. 돌아가기 + +## 원하는 기능을 선택하세요. +1 + +## 출발역을 입력하세요. +교대역 + +## 도착역을 입력하세요. +양재역 + +## 조회 결과 +[INFO] --- +[INFO] 총 거리: 6km +[INFO] 총 소요 시간: 14분 +[INFO] --- +[INFO] 교대역 +[INFO] 강남역 +[INFO] 양재역 + +## 메인 화면 +1. 경로 조회 +Q. 종료 + +... +``` + +#### 에러 출력 예시 + +``` +## 메인 화면 +1. 경로 조회 +Q. 종료 + +## 원하는 기능을 선택하세요. +1 + +## 경로 기준 +1. 최단 거리 +2. 최소 시간 +B. 돌아가기 + +## 원하는 기능을 선택하세요. +1 + +## 출발역을 입력하세요. +강남역 + +## 도착역을 입력하세요. +강남역 + +[ERROR] 출발역과 도착역이 동일합니다. + +## 경로 기준 +1. 최단 거리 +2. 최소 시간 +B. 돌아가기 + +## 원하는 기능을 선택하세요. + +... + +``` \ No newline at end of file From 2e38b613349fe8c4264e10934f096702a6194925 Mon Sep 17 00:00:00 2001 From: Taehwa Lee Date: Sat, 19 Dec 2020 15:35:38 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat:=20=EC=A7=80=ED=95=98=EC=B2=A0=20?= =?UTF-8?q?=EC=97=AD=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/README.md | 9 ++-- .../subway/domain/station/domain/Station.java | 44 +++++++++++++++++++ .../ShorterThanMinStationNameException.java | 13 ++++++ .../subway/domain/station/StationTest.java | 30 +++++++++++++ 4 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 src/main/java/subway/domain/station/domain/Station.java create mode 100644 src/main/java/subway/domain/station/exception/ShorterThanMinStationNameException.java create mode 100644 src/test/java/subway/domain/station/StationTest.java diff --git a/doc/README.md b/doc/README.md index 7dbb8fbf1..2bb6a192c 100644 --- a/doc/README.md +++ b/doc/README.md @@ -13,10 +13,10 @@ ``` ### 지하철 역 기능 -- [ ] 지하철 역을 생성할 수 있다. +- [x] 지하철 역을 생성할 수 있다. - 지하철 역 생성 시 이름을 입력받는다. - 예외 처리 - - [ ] 지하철 역 이름은 2글자 이상이어야 한다. + - [x] 지하철 역 이름은 2글자 이상이어야 한다. ### 지하철 역 관리 기능 - [ ] 지하철 역 저장소에 지하철 역을 등록할 수 있다. @@ -49,8 +49,8 @@ 3. 거리 그래프 관리 객체에 해당 JGrapht Edge에 weight을 설정해서 추가한다. 4. 시간 그래프 관리 객체에 추가할 역을 Vertex로 추가한다. 5. 시간 그래프 관리 객체에 해당 노선의 하행 끝 역과 추가할 역의 JGrapht Edge를 만든다. - 7. 시간 그래프 관리 객체에 해당 JGrapht Edge에 weight을 설정해서 추가한다. - 8. LineStation의 속성으로 위의 두 JGrapht Edge를 설정하여 생성한 뒤에 노선의 하행 끝 뒤에 추가한다. + 6. 시간 그래프 관리 객체에 해당 JGrapht Edge에 weight을 설정해서 추가한다. + 7. LineStation의 속성으로 위의 두 JGrapht Edge를 설정하여 생성한 뒤에 노선의 하행 끝 뒤에 추가한다. ### 경로 관리 기능 - [ ] 거리 그래프 객체와 시간 그래프 객체를 가지고 있다. @@ -58,6 +58,7 @@ - [ ] 출발역과 도착역을 입력받아 최소 시간 경로를 조회한다. - 경로 조회 시 총 거리, 총 소요 시간도 함께 출력한다. - 예외 처리 + - [ ] 경로 조회 시 출발역이나 도착역이 존재하지 않으면 에러를 출력한다. - [ ] 경로 조회 시 출발역과 도착역이 같으면 에러를 출력한다. - [ ] 경로 조회 시 출발역과 도착역이 연결되어 있지 않으면 에러를 출력한다. diff --git a/src/main/java/subway/domain/station/domain/Station.java b/src/main/java/subway/domain/station/domain/Station.java new file mode 100644 index 000000000..5e67e341c --- /dev/null +++ b/src/main/java/subway/domain/station/domain/Station.java @@ -0,0 +1,44 @@ +package subway.domain.station.domain; + +import java.util.Objects; +import subway.domain.station.exception.ShorterThanMinStationNameException; + +public class Station { + + public static final int MIN_NAME_SIZE = 2; + + private final String name; + + private Station(String name) { + this.name = name; + } + + public static Station from(String name) { + if (name.length() < MIN_NAME_SIZE) { + throw new ShorterThanMinStationNameException(name); + } + + return new Station(name); + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Station station = (Station) o; + return Objects.equals(name, station.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/src/main/java/subway/domain/station/exception/ShorterThanMinStationNameException.java b/src/main/java/subway/domain/station/exception/ShorterThanMinStationNameException.java new file mode 100644 index 000000000..0d17ba6e3 --- /dev/null +++ b/src/main/java/subway/domain/station/exception/ShorterThanMinStationNameException.java @@ -0,0 +1,13 @@ +package subway.domain.station.exception; + +import subway.domain.station.domain.Station; + +public class ShorterThanMinStationNameException extends IllegalArgumentException { + + private static final String MESSAGE = "지하철 역 이름은 " + Station.MIN_NAME_SIZE + + "글자 이상이어야 합니다. (입력 값: '%s')"; + + public ShorterThanMinStationNameException(final String input) { + super(String.format(MESSAGE, input)); + } +} 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..ab1b3fdd6 --- /dev/null +++ b/src/test/java/subway/domain/station/StationTest.java @@ -0,0 +1,30 @@ +package subway.domain.station; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.domain.station.domain.Station; +import subway.domain.station.exception.ShorterThanMinStationNameException; + +@DisplayName("지하철 역 기능에 대한 테스트") +class StationTest { + + @DisplayName("지하철 역 이름은 2글자 이상이어야 한다.") + @Test + void shorterThanMinStationNameException() { + final String name = "a"; + + assertThrows(ShorterThanMinStationNameException.class, () -> Station.from(name)); + } + + @DisplayName("지하철 역을 생성할 수 있다.") + @Test + void create() { + final String name = "test"; + final Station station = Station.from(name); + + assertNotNull(station); + } +} \ No newline at end of file From 140e725ab9ca1e08b8d32d117f973c43628eb326 Mon Sep 17 00:00:00 2001 From: Taehwa Lee Date: Sat, 19 Dec 2020 15:37:21 +0900 Subject: [PATCH 3/8] =?UTF-8?q?docs:=20=EC=A7=80=ED=95=98=EC=B2=A0=20?= =?UTF-8?q?=EC=97=AD=20=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/README.md | 4 +- src/main/java/subway/domain/Station.java | 15 ---- .../java/subway/domain/StationRepository.java | 26 ------- .../station/domain/StationRepository.java | 44 +++++++++++ .../domain/station/dto/StationRequestDto.java | 14 ++++ .../CannotFindStationByNameException.java | 10 +++ .../DuplicateStationNameException.java | 10 +++ .../station/service/StationService.java | 13 ++++ .../domain/station/StationRepositoryTest.java | 78 +++++++++++++++++++ 9 files changed, 171 insertions(+), 43 deletions(-) delete mode 100644 src/main/java/subway/domain/Station.java delete mode 100644 src/main/java/subway/domain/StationRepository.java create mode 100644 src/main/java/subway/domain/station/domain/StationRepository.java create mode 100644 src/main/java/subway/domain/station/dto/StationRequestDto.java create mode 100644 src/main/java/subway/domain/station/exception/CannotFindStationByNameException.java create mode 100644 src/main/java/subway/domain/station/exception/DuplicateStationNameException.java create mode 100644 src/main/java/subway/domain/station/service/StationService.java create mode 100644 src/test/java/subway/domain/station/StationRepositoryTest.java diff --git a/doc/README.md b/doc/README.md index 2bb6a192c..1ac9b2bd6 100644 --- a/doc/README.md +++ b/doc/README.md @@ -19,9 +19,9 @@ - [x] 지하철 역 이름은 2글자 이상이어야 한다. ### 지하철 역 관리 기능 -- [ ] 지하철 역 저장소에 지하철 역을 등록할 수 있다. +- [x] 지하철 역 저장소에 지하철 역을 등록할 수 있다. - 예외 처리 - - [ ] 중복된 지하철 역 이름이 등록될 수 없다. + - [x] 중복된 지하철 역 이름이 등록될 수 없다. ### 지하철 노선 기능 - [ ] 지하철 노선을 생성할 수 있다. 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/StationRepository.java b/src/main/java/subway/domain/StationRepository.java deleted file mode 100644 index 8ed9d103f..000000000 --- a/src/main/java/subway/domain/StationRepository.java +++ /dev/null @@ -1,26 +0,0 @@ -package subway.domain; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -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) { - stations.add(station); - } - - public static boolean deleteStation(String name) { - return stations.removeIf(station -> Objects.equals(station.getName(), name)); - } - - public static void deleteAll() { - stations.clear(); - } -} diff --git a/src/main/java/subway/domain/station/domain/StationRepository.java b/src/main/java/subway/domain/station/domain/StationRepository.java new file mode 100644 index 000000000..8c99c4368 --- /dev/null +++ b/src/main/java/subway/domain/station/domain/StationRepository.java @@ -0,0 +1,44 @@ +package subway.domain.station.domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import subway.domain.station.exception.CannotFindStationByNameException; +import subway.domain.station.exception.DuplicateStationNameException; + +public class StationRepository { + private static final List stations = new ArrayList<>(); + + public static List findAll() { + return Collections.unmodifiableList(stations); + } + + public static Station findByName(String name) { + return stations.stream() + .filter(station -> station.getName().equals(name)) + .findAny() + .orElseThrow(() -> { + throw new CannotFindStationByNameException(name); + }); + } + + public static void save(Station station) { + if (stations.contains(station)) { + throw new DuplicateStationNameException(station.getName()); + } + + stations.add(station); + } + + public static void saveAll(List stations) { + stations.forEach(StationRepository::save); + } + + public static void delete(Station station) { + stations.remove(station); + } + + public static void deleteAll() { + stations.clear(); + } +} diff --git a/src/main/java/subway/domain/station/dto/StationRequestDto.java b/src/main/java/subway/domain/station/dto/StationRequestDto.java new file mode 100644 index 000000000..be191fac2 --- /dev/null +++ b/src/main/java/subway/domain/station/dto/StationRequestDto.java @@ -0,0 +1,14 @@ +package subway.domain.station.dto; + +public class StationRequestDto { + + private final String name; + + public StationRequestDto(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/subway/domain/station/exception/CannotFindStationByNameException.java b/src/main/java/subway/domain/station/exception/CannotFindStationByNameException.java new file mode 100644 index 000000000..e31fe5a0e --- /dev/null +++ b/src/main/java/subway/domain/station/exception/CannotFindStationByNameException.java @@ -0,0 +1,10 @@ +package subway.domain.station.exception; + +public class CannotFindStationByNameException extends RuntimeException { + + private static final String MESSAGE = "등록되지 않은 지하철 역 입니다. (입력 값: '%s')"; + + public CannotFindStationByNameException(final String input) { + super(String.format(MESSAGE, input)); + } +} diff --git a/src/main/java/subway/domain/station/exception/DuplicateStationNameException.java b/src/main/java/subway/domain/station/exception/DuplicateStationNameException.java new file mode 100644 index 000000000..1b8f3bd71 --- /dev/null +++ b/src/main/java/subway/domain/station/exception/DuplicateStationNameException.java @@ -0,0 +1,10 @@ +package subway.domain.station.exception; + +public class DuplicateStationNameException extends IllegalArgumentException { + + private static final String MESSAGE = "이미 존재하는 역 이름입니다. (입력 값: '%s')"; + + public DuplicateStationNameException(final String input) { + super(String.format(MESSAGE, input)); + } +} diff --git a/src/main/java/subway/domain/station/service/StationService.java b/src/main/java/subway/domain/station/service/StationService.java new file mode 100644 index 000000000..3144e64f7 --- /dev/null +++ b/src/main/java/subway/domain/station/service/StationService.java @@ -0,0 +1,13 @@ +package subway.domain.station.service; + +import subway.domain.station.domain.Station; +import subway.domain.station.domain.StationRepository; +import subway.domain.station.dto.StationRequestDto; + +public class StationService { + + public static void save(StationRequestDto requestDto) { + Station newStation = Station.from(requestDto.getName()); + StationRepository.save(newStation); + } +} diff --git a/src/test/java/subway/domain/station/StationRepositoryTest.java b/src/test/java/subway/domain/station/StationRepositoryTest.java new file mode 100644 index 000000000..0c8cea074 --- /dev/null +++ b/src/test/java/subway/domain/station/StationRepositoryTest.java @@ -0,0 +1,78 @@ +package subway.domain.station; + +import static org.junit.jupiter.api.Assertions.*; + +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.domain.Station; +import subway.domain.station.domain.StationRepository; +import subway.domain.station.exception.CannotFindStationByNameException; +import subway.domain.station.exception.DuplicateStationNameException; + +@DisplayName("지하철 역 관리 기능을 테스트 한다.") +class StationRepositoryTest { + + final String STATION_1_NAME = "test station1"; + final Station station1 = Station.from(STATION_1_NAME); + final Station station2 = Station.from("test station2"); + final int SIZE = 2; + + @BeforeEach + void before() { + StationRepository.save(station1); + StationRepository.save(station2); + } + + @AfterEach + void after() { + StationRepository.deleteAll(); + } + + @DisplayName("중복된 지하철 역 이름이 등록될 수 없다.") + @Test + void duplicateStationNameException() { + assertThrows(DuplicateStationNameException.class, () -> { + final Station newStation = Station.from(STATION_1_NAME); + StationRepository.save(newStation); + }); + } + + @DisplayName("지하철 역 저장소에 지하철 역을 등록할 수 있다.") + @Test + void addStation() { + final Station station = Station.from("test"); + + StationRepository.save(station); + + final int EXPECT = SIZE + 1; + assertEquals(StationRepository.findAll().size(), EXPECT); + } + + @DisplayName("지하철 역 저장소에서 지하철 역을 삭제할 수 있다.") + @Test + void deleteStation() { + StationRepository.delete(station1); + + final int EXPECT = SIZE - 1; + assertEquals(StationRepository.findAll().size(), EXPECT); + } + + @DisplayName("등록되지 않은 지하철 역은 조회할 수 없다.") + @Test + void cannotFindStationByNameException() { + final String target = "test"; + + assertThrows(CannotFindStationByNameException.class, + () -> StationRepository.findByName(target)); + } + + @DisplayName("지하철 역 저장소에 존재하는 지하철을 이름으로 조회할 수 있다.") + @Test + void findStationByName() { + final Station foundStation = StationRepository.findByName(STATION_1_NAME); + + assertSame(foundStation, station1); + } +} \ No newline at end of file From f50913a55bb876ec604d24e09360d9ad59007f4f Mon Sep 17 00:00:00 2001 From: Taehwa Lee Date: Sat, 19 Dec 2020 15:58:40 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20=EC=A7=80=ED=95=98=EC=B2=A0=20?= =?UTF-8?q?=EB=85=B8=EC=84=A0=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 지하철 노선을 생성할 수 있다. - 지하철 노선 이름은 2글자 이상이어야 한다. - 상행 종점역과 하행 종점역이 같을 수는 없다. --- doc/README.md | 8 +- src/main/java/subway/domain/Line.java | 15 ---- .../java/subway/domain/line/domain/Line.java | 82 +++++++++++++++++++ .../DuplicateStationNameInLineException.java | 10 +++ .../ShorterThanMinLineNameException.java | 13 +++ ...streamDownstreamStationInputException.java | 11 +++ .../java/subway/domain/line/LineTest.java | 38 +++++++++ 7 files changed, 158 insertions(+), 19 deletions(-) delete mode 100644 src/main/java/subway/domain/Line.java create mode 100644 src/main/java/subway/domain/line/domain/Line.java create mode 100644 src/main/java/subway/domain/line/exception/DuplicateStationNameInLineException.java create mode 100644 src/main/java/subway/domain/line/exception/ShorterThanMinLineNameException.java create mode 100644 src/main/java/subway/domain/line/exception/UpstreamDownstreamStationInputException.java create mode 100644 src/test/java/subway/domain/line/LineTest.java diff --git a/doc/README.md b/doc/README.md index 1ac9b2bd6..16b4e3bb0 100644 --- a/doc/README.md +++ b/doc/README.md @@ -24,11 +24,11 @@ - [x] 중복된 지하철 역 이름이 등록될 수 없다. ### 지하철 노선 기능 -- [ ] 지하철 노선을 생성할 수 있다. - - [ ] 노선 생성 시 이름, 상행 종점역, 하행 종점역을 입력받는다. +- [x] 지하철 노선을 생성할 수 있다. + - [x] 노선 생성 시 이름, 상행 종점역, 하행 종점역을 입력받는다. - 예외 처리 - - [ ] 지하철 노선 이름은 2글자 이상이어야 한다. - - [ ] 상행 종점역과 하행 종점역이 같을 수는 없다. + - [x] 지하철 노선 이름은 2글자 이상이어야 한다. + - [x] 상행 종점역과 하행 종점역이 같을 수는 없다. ### 지하철 노선 관리 기능 - [ ] 지하철 노선 저장소에 지하철 노선을 등록할 수 있다. diff --git a/src/main/java/subway/domain/Line.java b/src/main/java/subway/domain/Line.java deleted file mode 100644 index f4d738d5a..000000000 --- a/src/main/java/subway/domain/Line.java +++ /dev/null @@ -1,15 +0,0 @@ -package subway.domain; - -public class Line { - private String name; - - public Line(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - // 추가 기능 구현 -} diff --git a/src/main/java/subway/domain/line/domain/Line.java b/src/main/java/subway/domain/line/domain/Line.java new file mode 100644 index 000000000..074919e8a --- /dev/null +++ b/src/main/java/subway/domain/line/domain/Line.java @@ -0,0 +1,82 @@ +package subway.domain.line.domain; + +import java.util.List; +import java.util.Objects; +import subway.domain.line.exception.DuplicateStationNameInLineException; +import subway.domain.line.exception.ShorterThanMinLineNameException; +import subway.domain.line.exception.UpstreamDownstreamStationInputException; +import subway.domain.station.domain.Station; + +public class Line { + + public static final int MIN_NAME_SIZE = 2; + + private final String name; + private final LineStations lineStations; + + private Line(String name, LineStations lineStations) { + this.name = name; + this.lineStations = lineStations; + } + + public static Line of(String name, Station upstreamStation, Station downstreamStation, + double distance, double time) { + checkAddLineValidation(name, upstreamStation, downstreamStation); + LineStations lineStations = LineStations.of(upstreamStation, downstreamStation, distance, time); + + return new Line(name, lineStations); + } + + private static void checkAddLineValidation(String name, Station upstreamStation, + Station downstreamStation) { + if (name.length() < MIN_NAME_SIZE) { + throw new ShorterThanMinLineNameException(name); + } + + if (upstreamStation.equals(downstreamStation)) { + throw new UpstreamDownstreamStationInputException(upstreamStation.getName(), + downstreamStation.getName()); + } + } + + public boolean contains(Station target) { + return lineStations.contains(target); + } + + public void addSection(Station station, double distance, double time) { + if (lineStations.contains(station)) { + throw new DuplicateStationNameInLineException(name, station.getName()); + } + + lineStations.add(station, distance, time); + } + + public String getName() { + return name; + } + + public List getLineStations() { + return lineStations.getLineStations(); + } + + public Station getLastDownstreamStation() { + return lineStations.getLastDownstreamStation(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Line line = (Line) o; + return Objects.equals(name, line.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/src/main/java/subway/domain/line/exception/DuplicateStationNameInLineException.java b/src/main/java/subway/domain/line/exception/DuplicateStationNameInLineException.java new file mode 100644 index 000000000..9f984f414 --- /dev/null +++ b/src/main/java/subway/domain/line/exception/DuplicateStationNameInLineException.java @@ -0,0 +1,10 @@ +package subway.domain.line.exception; + +public class DuplicateStationNameInLineException extends IllegalArgumentException { + + private static final String MESSAGE = "%s 노선에 이미 존재하는 역입니다. (입력 값: '%s')"; + + public DuplicateStationNameInLineException(final String lineName, final String stationName) { + super(String.format(MESSAGE, lineName, stationName)); + } +} diff --git a/src/main/java/subway/domain/line/exception/ShorterThanMinLineNameException.java b/src/main/java/subway/domain/line/exception/ShorterThanMinLineNameException.java new file mode 100644 index 000000000..a55e1b3de --- /dev/null +++ b/src/main/java/subway/domain/line/exception/ShorterThanMinLineNameException.java @@ -0,0 +1,13 @@ +package subway.domain.line.exception; + +import subway.domain.line.domain.Line; + +public class ShorterThanMinLineNameException extends IllegalArgumentException { + + private static final String MESSAGE = "지하철 노선 이름은 " + Line.MIN_NAME_SIZE + + "글자 이상이어야 합니다. (입력 값: '%s')"; + + public ShorterThanMinLineNameException(final String input) { + super(String.format(MESSAGE, input)); + } +} diff --git a/src/main/java/subway/domain/line/exception/UpstreamDownstreamStationInputException.java b/src/main/java/subway/domain/line/exception/UpstreamDownstreamStationInputException.java new file mode 100644 index 000000000..93a7067fa --- /dev/null +++ b/src/main/java/subway/domain/line/exception/UpstreamDownstreamStationInputException.java @@ -0,0 +1,11 @@ +package subway.domain.line.exception; + +public class UpstreamDownstreamStationInputException extends IllegalArgumentException { + + private static final String MESSAGE = "상행 종점역과 하행 종점역이 같을 수는 없습니다. (입력 값: '%s', '%s')"; + + public UpstreamDownstreamStationInputException(final String upstreamStation, + final String downstreamStation) { + super(String.format(MESSAGE, upstreamStation, downstreamStation)); + } +} 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..a8c594be6 --- /dev/null +++ b/src/test/java/subway/domain/line/LineTest.java @@ -0,0 +1,38 @@ +package subway.domain.line; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.domain.line.domain.Line; +import subway.domain.line.exception.ShorterThanMinLineNameException; +import subway.domain.station.domain.Station; + +@DisplayName("지하철 노선 기능에 대한 테스트") +class LineTest { + + final String LINE_NAME = "test line1"; + final Station upstreamStation = Station.from("test1"); + final Station downstreamStation = Station.from("test2"); + + @DisplayName("지하철 노선 이름은 2글자 이상이어야 한다.") + @Test + void shorterThanMinLineNameException() { + final String shortName = "a"; + final double distance = 1; + final double time = 1; + + assertThrows(ShorterThanMinLineNameException.class, + () -> Line.of(shortName, upstreamStation, downstreamStation, distance, time)); + } + + @DisplayName("지하철 노선을 생성할 수 있다.") + @Test + void create() { + final double distance = 1; + final double time = 1; + final Line line = Line.of(LINE_NAME, upstreamStation, downstreamStation, distance, time); + + assertNotNull(line); + } +} \ No newline at end of file From 1c21854bfd84913cb21a20aef1349f393b7e16d1 Mon Sep 17 00:00:00 2001 From: Taehwa Lee Date: Sat, 19 Dec 2020 16:03:06 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20=EC=A7=80=ED=95=98=EC=B2=A0=20?= =?UTF-8?q?=EB=85=B8=EC=84=A0=20=EA=B8=B0=EB=8A=A5=20=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 지하철 노선 저장소에 지하철 노선을 등록할 수 있다. - 중복된 지하철 노선 이름이 등록될 수 없다. --- doc/README.md | 4 +- .../java/subway/domain/LineRepository.java | 26 ------ .../domain/line/domain/LineRepository.java | 45 ++++++++++ .../domain/line/domain/LineStation.java | 66 +++++++++++++++ .../domain/line/domain/LineStations.java | 72 ++++++++++++++++ .../domain/line/dto/LineRequestDto.java | 39 +++++++++ .../CannotFindLineByNameException.java | 10 +++ .../exception/DuplicateLineNameException.java | 10 +++ .../domain/line/service/LineService.java | 24 ++++++ .../domain/line/LineRepositoryTest.java | 82 +++++++++++++++++++ 10 files changed, 350 insertions(+), 28 deletions(-) delete mode 100644 src/main/java/subway/domain/LineRepository.java create mode 100644 src/main/java/subway/domain/line/domain/LineRepository.java create mode 100644 src/main/java/subway/domain/line/domain/LineStation.java create mode 100644 src/main/java/subway/domain/line/domain/LineStations.java create mode 100644 src/main/java/subway/domain/line/dto/LineRequestDto.java create mode 100644 src/main/java/subway/domain/line/exception/CannotFindLineByNameException.java create mode 100644 src/main/java/subway/domain/line/exception/DuplicateLineNameException.java create mode 100644 src/main/java/subway/domain/line/service/LineService.java create mode 100644 src/test/java/subway/domain/line/LineRepositoryTest.java diff --git a/doc/README.md b/doc/README.md index 16b4e3bb0..728d0ba1e 100644 --- a/doc/README.md +++ b/doc/README.md @@ -31,9 +31,9 @@ - [x] 상행 종점역과 하행 종점역이 같을 수는 없다. ### 지하철 노선 관리 기능 -- [ ] 지하철 노선 저장소에 지하철 노선을 등록할 수 있다. +- [x] 지하철 노선 저장소에 지하철 노선을 등록할 수 있다. - 예외 처리 - - [ ] 중복된 지하철 노선 이름이 등록될 수 없다. + - [x] 중복된 지하철 노선 이름이 등록될 수 없다. ### 지하철 구간 기능 - [ ] 지하철 구간을 생성할 수 있다. diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/LineRepository.java deleted file mode 100644 index 2c4a723c9..000000000 --- a/src/main/java/subway/domain/LineRepository.java +++ /dev/null @@ -1,26 +0,0 @@ -package subway.domain; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -public class LineRepository { - private static final List lines = new ArrayList<>(); - - public static List lines() { - return Collections.unmodifiableList(lines); - } - - public static void addLine(Line line) { - lines.add(line); - } - - public static boolean deleteLineByName(String name) { - return lines.removeIf(line -> Objects.equals(line.getName(), name)); - } - - public static void deleteAll() { - lines.clear(); - } -} diff --git a/src/main/java/subway/domain/line/domain/LineRepository.java b/src/main/java/subway/domain/line/domain/LineRepository.java new file mode 100644 index 000000000..5c63dca49 --- /dev/null +++ b/src/main/java/subway/domain/line/domain/LineRepository.java @@ -0,0 +1,45 @@ +package subway.domain.line.domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import subway.domain.line.exception.CannotFindLineByNameException; +import subway.domain.line.exception.DuplicateLineNameException; + +public class LineRepository { + + private static final List lines = new ArrayList<>(); + + public static List findAll() { + return Collections.unmodifiableList(lines); + } + + public static Line findByName(String name) { + return lines.stream() + .filter(line -> line.getName().equals(name)) + .findAny() + .orElseThrow(() -> { + throw new CannotFindLineByNameException(name); + }); + } + + public static void save(Line line) { + if (lines.contains(line)) { + throw new DuplicateLineNameException(line.getName()); + } + + lines.add(line); + } + + public static void saveAll(List lines) { + lines.forEach(LineRepository::save); + } + + public static void delete(Line line) { + lines.remove(line); + } + + public static void deleteAll() { + lines.clear(); + } +} diff --git a/src/main/java/subway/domain/line/domain/LineStation.java b/src/main/java/subway/domain/line/domain/LineStation.java new file mode 100644 index 000000000..e29e28f24 --- /dev/null +++ b/src/main/java/subway/domain/line/domain/LineStation.java @@ -0,0 +1,66 @@ +package subway.domain.line.domain; + +import org.jgrapht.graph.DefaultWeightedEdge; +import subway.domain.Path.PathRepository; +import subway.domain.station.domain.Station; + +public class LineStation { + + private final Station station; + private Station prevStation; + private DefaultWeightedEdge distanceWeightEdge; + private DefaultWeightedEdge timeWeightEdge; + + public LineStation(Station station, Station prevStation, + DefaultWeightedEdge distanceWeightEdge, DefaultWeightedEdge timeWeightEdge) { + this.station = station; + this.prevStation = prevStation; + this.distanceWeightEdge = distanceWeightEdge; + this.timeWeightEdge = timeWeightEdge; + } + + public static LineStation from(Station station) { + return new LineStation(station, null, null, null); + } + + public static LineStation of(Station station, Station prevStation, + DefaultWeightedEdge distanceWeightEdge, DefaultWeightedEdge timeWeightEdge) { + return new LineStation(station, prevStation, distanceWeightEdge, timeWeightEdge); + } + + public boolean isFirst() { + return prevStation == null; + } + + public String getName() { + return station.getName(); + } + + public Station getStation() { + return station; + } + + public Station getPrevStation() { + return prevStation; + } + + public void setPrevStation(Station station) { + prevStation = station; + } + + public void getDistance(double distance) { + PathRepository.getDistanceWeightGraph().getEdgeWeight(distanceWeightEdge); + } + + public void setDistance(double distance) { + PathRepository.getDistanceWeightGraph().setEdgeWeight(distanceWeightEdge, distance); + } + + public void getTime(double time) { + PathRepository.getTimeWeightGraph().getEdgeWeight(timeWeightEdge); + } + + public void setTime(double time) { + PathRepository.getTimeWeightGraph().setEdgeWeight(timeWeightEdge, time); + } +} diff --git a/src/main/java/subway/domain/line/domain/LineStations.java b/src/main/java/subway/domain/line/domain/LineStations.java new file mode 100644 index 000000000..4b3e74938 --- /dev/null +++ b/src/main/java/subway/domain/line/domain/LineStations.java @@ -0,0 +1,72 @@ +package subway.domain.line.domain; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.jgrapht.graph.DefaultWeightedEdge; +import subway.domain.Path.PathRepository; +import subway.domain.station.domain.Station; + +public class LineStations { + + private final List lineStations; + + private LineStations(List lineStations) { + this.lineStations = lineStations; + } + + public static LineStations from() { + return new LineStations(new ArrayList<>()); + } + + public static LineStations of(List lineStations) { + return new LineStations(lineStations); + } + + public static LineStations of(Station upstreamStation, Station downstreamStation, + double distance, double time) { + LineStations lineStations = from(); + lineStations.addFirstStation(upstreamStation); + lineStations.add(downstreamStation, distance, time); + + return lineStations; + } + + public boolean contains(Station targetStation) { + for (LineStation lineStation : lineStations) { + if (lineStation.getStation().equals(targetStation)) { + return true; + } + } + + return false; + } + + public int size() { + return lineStations.size(); + } + + public void addFirstStation(Station station) { + PathRepository.addVertex(station); + lineStations.add(LineStation.from(station)); + } + + public void add(Station station, double distance, double time) { + Station lastDownstreamStation = getLastDownstreamStation(); + DefaultWeightedEdge distanceWeightEdge = PathRepository + .addDistanceWeightEdge(lastDownstreamStation, station, time); + DefaultWeightedEdge timeWeightEdge = PathRepository + .addTimeWeightEdge(lastDownstreamStation, station, distance); + LineStation newLineStation = LineStation + .of(station, lastDownstreamStation, distanceWeightEdge, timeWeightEdge); + lineStations.add(newLineStation); + } + + public List getLineStations() { + return lineStations; + } + + public Station getLastDownstreamStation() { + return lineStations.get(lineStations.size() - 1).getStation(); + } +} diff --git a/src/main/java/subway/domain/line/dto/LineRequestDto.java b/src/main/java/subway/domain/line/dto/LineRequestDto.java new file mode 100644 index 000000000..d5d775703 --- /dev/null +++ b/src/main/java/subway/domain/line/dto/LineRequestDto.java @@ -0,0 +1,39 @@ +package subway.domain.line.dto; + +public class LineRequestDto { + + private final String name; + private final String upstreamStationName; + private final String downstreamStationName; + private final double distance; + private final double time; + + public LineRequestDto(String name, String upstreamStationName, + String downstreamStationName, double distance, double time) { + this.name = name; + this.upstreamStationName = upstreamStationName; + this.downstreamStationName = downstreamStationName; + this.distance = distance; + this.time = time; + } + + public String getName() { + return name; + } + + public String getUpstreamStationName() { + return upstreamStationName; + } + + public String getDownstreamStationName() { + return downstreamStationName; + } + + public double getDistance() { + return distance; + } + + public double getTime() { + return time; + } +} diff --git a/src/main/java/subway/domain/line/exception/CannotFindLineByNameException.java b/src/main/java/subway/domain/line/exception/CannotFindLineByNameException.java new file mode 100644 index 000000000..9e7c0a2fa --- /dev/null +++ b/src/main/java/subway/domain/line/exception/CannotFindLineByNameException.java @@ -0,0 +1,10 @@ +package subway.domain.line.exception; + +public class CannotFindLineByNameException extends RuntimeException { + + private static final String MESSAGE = "등록되지 않은 지하철 노선 입니다. (입력 값: '%s')"; + + public CannotFindLineByNameException(final String input) { + super(String.format(MESSAGE, input)); + } +} diff --git a/src/main/java/subway/domain/line/exception/DuplicateLineNameException.java b/src/main/java/subway/domain/line/exception/DuplicateLineNameException.java new file mode 100644 index 000000000..351fc1a6e --- /dev/null +++ b/src/main/java/subway/domain/line/exception/DuplicateLineNameException.java @@ -0,0 +1,10 @@ +package subway.domain.line.exception; + +public class DuplicateLineNameException extends IllegalArgumentException { + + private static final String MESSAGE = "이미 존재하는 노선 이름입니다. (입력 값: '%s')"; + + public DuplicateLineNameException(final String input) { + super(String.format(MESSAGE, input)); + } +} diff --git a/src/main/java/subway/domain/line/service/LineService.java b/src/main/java/subway/domain/line/service/LineService.java new file mode 100644 index 000000000..3c6ab2a7d --- /dev/null +++ b/src/main/java/subway/domain/line/service/LineService.java @@ -0,0 +1,24 @@ +package subway.domain.line.service; + +import subway.domain.line.domain.Line; +import subway.domain.line.domain.LineRepository; +import subway.domain.line.dto.LineRequestDto; +import subway.domain.station.domain.Station; +import subway.domain.station.domain.StationRepository; + +public class LineService { + + public static void save(LineRequestDto requestDto) { + Station upstreamStation = StationRepository.findByName(requestDto.getUpstreamStationName()); + Station downstreamStation = StationRepository.findByName(requestDto.getDownstreamStationName()); + Line newLine = Line + .of(requestDto.getName(), upstreamStation, downstreamStation, + requestDto.getDistance(), requestDto.getTime()); + LineRepository.save(newLine); + } + + public static boolean contains(Station targetStation) { + return LineRepository.findAll().stream() + .anyMatch(line -> line.contains(targetStation)); + } +} diff --git a/src/test/java/subway/domain/line/LineRepositoryTest.java b/src/test/java/subway/domain/line/LineRepositoryTest.java new file mode 100644 index 000000000..2129ba625 --- /dev/null +++ b/src/test/java/subway/domain/line/LineRepositoryTest.java @@ -0,0 +1,82 @@ +package subway.domain.line; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.List; +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.line.domain.Line; +import subway.domain.line.domain.LineRepository; +import subway.domain.line.exception.CannotFindLineByNameException; +import subway.domain.line.exception.DuplicateLineNameException; +import subway.domain.station.domain.Station; + +@DisplayName("지하철 노선 관리 기능을 테스트 한다.") +class LineRepositoryTest { + + final String LINE_NAME = "test line"; + final int LINE_SIZE = 1; + final double DISTANCE = 1; + final double TIME = 1; + final Station upstreamStation = Station.from("test station1"); + final Station downstreamStation = Station.from("test station2"); + final Line line = Line.of(LINE_NAME, upstreamStation, downstreamStation, DISTANCE, TIME); + + @BeforeEach + void before() { + LineRepository.save(line); + } + + @AfterEach + void after() { + LineRepository.deleteAll(); + } + + @DisplayName("중복된 지하철 노선 이름은 등록될 수 없다.") + @Test + void duplicateLineNameException() { + assertThrows(DuplicateLineNameException.class, () -> LineRepository.save(line)); + } + + @DisplayName("지하철 노선 저장소에 지하철 노선을 등록할 수 있다.") + @Test + void addLine() { + final String NAME = "test"; + final double distance = 1; + final double time = 1; + final Line line = Line.of(NAME, upstreamStation, downstreamStation, distance, time); + + LineRepository.save(line); + + final int EXPECT = LINE_SIZE + 1; + assertEquals(LineRepository.findAll().size(), EXPECT); + } + + @DisplayName("지하철 노선 저장소에서 지하철 노선의 목록을 조회할 수 있다.") + @Test + void findAllLine() { + final List lines = LineRepository.findAll(); + + assertEquals(lines.size(), LINE_SIZE); + } + + @DisplayName("등록되지 않은 지하철 노선은 조회할 수 없다.") + @Test + void cannotFindLineByNameException() { + final String TARGET = "test"; + + assertThrows(CannotFindLineByNameException.class, () -> LineRepository.findByName(TARGET)); + } + + @DisplayName("지하철 노선 저장소에 존재하는 지하철 노선을 이름으로 조회할 수 있다.") + @Test + void findLineByName() { + final Line foundLine = LineRepository.findByName(LINE_NAME); + + assertSame(foundLine, line); + } +} \ No newline at end of file From 0b0b67a1f6d91e6e5cf6873af9adacaa510500e3 Mon Sep 17 00:00:00 2001 From: Taehwa Lee Date: Sat, 19 Dec 2020 16:14:46 +0900 Subject: [PATCH 6/8] =?UTF-8?q?feat:=20=EC=A7=80=ED=95=98=EC=B2=A0=20?= =?UTF-8?q?=EA=B5=AC=EA=B0=84=20=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 지하철 노선 저장소에서 지하철 노선에 구간을 추가할 수 있다. - 해당 노선에 이미 존재하는 지하철 역은 추가할 수 없다. --- doc/README.md | 6 +-- .../subway/domain/Path/PathRepository.java | 31 ++++++++++++ .../java/subway/domain/Path/WeightGraph.java | 30 ++++++++++++ .../domain/line/domain/LineStation.java | 8 +-- .../line/dto/LineStationResponseDto.java | 40 +++++++++++++++ .../line/dto/SectionInsertRequestDto.java | 33 +++++++++++++ .../line/service/LineStationService.java | 16 ++++++ .../domain/line/LineStationServiceTest.java | 49 +++++++++++++++++++ 8 files changed, 206 insertions(+), 7 deletions(-) create mode 100644 src/main/java/subway/domain/Path/PathRepository.java create mode 100644 src/main/java/subway/domain/Path/WeightGraph.java create mode 100644 src/main/java/subway/domain/line/dto/LineStationResponseDto.java create mode 100644 src/main/java/subway/domain/line/dto/SectionInsertRequestDto.java create mode 100644 src/main/java/subway/domain/line/service/LineStationService.java create mode 100644 src/test/java/subway/domain/line/LineStationServiceTest.java diff --git a/doc/README.md b/doc/README.md index 728d0ba1e..a94e7078b 100644 --- a/doc/README.md +++ b/doc/README.md @@ -36,13 +36,13 @@ - [x] 중복된 지하철 노선 이름이 등록될 수 없다. ### 지하철 구간 기능 -- [ ] 지하철 구간을 생성할 수 있다. +- [x] 지하철 구간을 생성할 수 있다. - LineStation은 JGrapht의 Edge 정보(거리, 시간)를 생성자 인자로 받는다. - 거리, 시간을 수정하면 거리, 시간 관리 그래프에도 반영되어야 한다. ### 지하철 구간 관리 기능 -- [ ] 지하철 노선 저장소에서 지하철 노선에 구간을 추가할 수 있다. - - [ ] 해당 노선에 이미 존재하는 지하철 역은 추가할 수 없다. +- [x] 지하철 노선 저장소에서 지하철 노선에 구간을 추가할 수 있다. + - [x] 해당 노선에 이미 존재하는 지하철 역은 추가할 수 없다. - 순서 1. 거리 그래프 관리 객체에 추가할 역을 Vertex로 추가한다. 2. 거리 그래프 관리 객체에 해당 노선의 하행 끝 역과 추가할 역의 JGrapht Edge를 만든다. diff --git a/src/main/java/subway/domain/Path/PathRepository.java b/src/main/java/subway/domain/Path/PathRepository.java new file mode 100644 index 000000000..edfcc8e12 --- /dev/null +++ b/src/main/java/subway/domain/Path/PathRepository.java @@ -0,0 +1,31 @@ +package subway.domain.Path; + +import org.jgrapht.graph.DefaultWeightedEdge; +import subway.domain.station.domain.Station; + +public class PathRepository { + + private static final WeightGraph distanceWeightGraph = new WeightGraph(); + private static final WeightGraph timeWeightGraph = new WeightGraph(); + + public static WeightGraph getDistanceWeightGraph() { + return distanceWeightGraph; + } + + public static WeightGraph getTimeWeightGraph() { + return timeWeightGraph; + } + + public static DefaultWeightedEdge addDistanceWeightEdge(Station sourceStation, Station targetStation, double weight) { + return distanceWeightGraph.addEdge(sourceStation, targetStation, weight); + } + + public static DefaultWeightedEdge addTimeWeightEdge(Station sourceStation, Station targetStation, double weight) { + return timeWeightGraph.addEdge(sourceStation, targetStation, weight); + } + + public static void addVertex(Station station) { + distanceWeightGraph.addVertex(station); + timeWeightGraph.addVertex(station); + } +} diff --git a/src/main/java/subway/domain/Path/WeightGraph.java b/src/main/java/subway/domain/Path/WeightGraph.java new file mode 100644 index 000000000..42c07715f --- /dev/null +++ b/src/main/java/subway/domain/Path/WeightGraph.java @@ -0,0 +1,30 @@ +package subway.domain.Path; + +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.WeightedMultigraph; +import subway.domain.station.domain.Station; + +public class WeightGraph { + + private final WeightedMultigraph graph = new WeightedMultigraph(DefaultWeightedEdge.class); + + public DefaultWeightedEdge addEdge(Station sourceStation, Station targetStation, double weight) { + graph.addVertex(targetStation); + DefaultWeightedEdge edge = graph.addEdge(sourceStation, targetStation); + graph.setEdgeWeight(edge, weight); + + return edge; + } + + public void addVertex(Station station) { + graph.addVertex(station); + } + + public double getEdgeWeight(DefaultWeightedEdge edge) { + return graph.getEdgeWeight(edge); + } + + public void setEdgeWeight(DefaultWeightedEdge edge, double weight) { + graph.setEdgeWeight(edge, weight); + } +} diff --git a/src/main/java/subway/domain/line/domain/LineStation.java b/src/main/java/subway/domain/line/domain/LineStation.java index e29e28f24..03defee14 100644 --- a/src/main/java/subway/domain/line/domain/LineStation.java +++ b/src/main/java/subway/domain/line/domain/LineStation.java @@ -48,16 +48,16 @@ public void setPrevStation(Station station) { prevStation = station; } - public void getDistance(double distance) { - PathRepository.getDistanceWeightGraph().getEdgeWeight(distanceWeightEdge); + public double getDistance(double distance) { + return PathRepository.getDistanceWeightGraph().getEdgeWeight(distanceWeightEdge); } public void setDistance(double distance) { PathRepository.getDistanceWeightGraph().setEdgeWeight(distanceWeightEdge, distance); } - public void getTime(double time) { - PathRepository.getTimeWeightGraph().getEdgeWeight(timeWeightEdge); + public double getTime(double time) { + return PathRepository.getTimeWeightGraph().getEdgeWeight(timeWeightEdge); } public void setTime(double time) { diff --git a/src/main/java/subway/domain/line/dto/LineStationResponseDto.java b/src/main/java/subway/domain/line/dto/LineStationResponseDto.java new file mode 100644 index 000000000..fc3814cbe --- /dev/null +++ b/src/main/java/subway/domain/line/dto/LineStationResponseDto.java @@ -0,0 +1,40 @@ +package subway.domain.line.dto; + +import java.util.List; +import java.util.stream.Collectors; +import subway.domain.line.domain.LineStation; + +public class LineStationResponseDto { + + private final String stationName; + private final String prevStationName; + + public LineStationResponseDto(String stationName, String prevStationName) { + this.stationName = stationName; + this.prevStationName = prevStationName; + } + + public static LineStationResponseDto of(LineStation entity) { + String stationName = null; + if (!entity.isFirst()) { + stationName = entity.getPrevStation().getName(); + } + + return new LineStationResponseDto( + entity.getStation().getName(), stationName); + } + + public static List of(List entities) { + return entities.stream() + .map(LineStationResponseDto::of) + .collect(Collectors.toList()); + } + + public String getStationName() { + return stationName; + } + + public String getPrevStationName() { + return prevStationName; + } +} diff --git a/src/main/java/subway/domain/line/dto/SectionInsertRequestDto.java b/src/main/java/subway/domain/line/dto/SectionInsertRequestDto.java new file mode 100644 index 000000000..b699f6ea5 --- /dev/null +++ b/src/main/java/subway/domain/line/dto/SectionInsertRequestDto.java @@ -0,0 +1,33 @@ +package subway.domain.line.dto; + +public class SectionInsertRequestDto { + + private final String lineName; + private final String stationName; + private final double distance; + private final double time; + + public SectionInsertRequestDto(String lineName, String stationName, double distance, + double time) { + this.lineName = lineName; + this.stationName = stationName; + this.distance = distance; + this.time = time; + } + + public String getLineName() { + return lineName; + } + + public String getStationName() { + return stationName; + } + + public double getDistance() { + return distance; + } + + public double getTime() { + return time; + } +} diff --git a/src/main/java/subway/domain/line/service/LineStationService.java b/src/main/java/subway/domain/line/service/LineStationService.java new file mode 100644 index 000000000..15d422394 --- /dev/null +++ b/src/main/java/subway/domain/line/service/LineStationService.java @@ -0,0 +1,16 @@ +package subway.domain.line.service; + +import subway.domain.line.domain.Line; +import subway.domain.line.domain.LineRepository; +import subway.domain.line.dto.SectionInsertRequestDto; +import subway.domain.station.domain.Station; +import subway.domain.station.domain.StationRepository; + +public class LineStationService { + + public static void addSection(SectionInsertRequestDto requestDto) { + Line line = LineRepository.findByName(requestDto.getLineName()); + Station station = StationRepository.findByName(requestDto.getStationName()); + line.addSection(station, requestDto.getDistance(), requestDto.getTime()); + } +} diff --git a/src/test/java/subway/domain/line/LineStationServiceTest.java b/src/test/java/subway/domain/line/LineStationServiceTest.java new file mode 100644 index 000000000..9fc9fdd3c --- /dev/null +++ b/src/test/java/subway/domain/line/LineStationServiceTest.java @@ -0,0 +1,49 @@ +package subway.domain.line; + +import static org.junit.jupiter.api.Assertions.*; + +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.line.domain.Line; +import subway.domain.line.domain.LineRepository; +import subway.domain.line.dto.SectionInsertRequestDto; +import subway.domain.line.service.LineStationService; +import subway.domain.station.domain.Station; +import subway.domain.station.domain.StationRepository; + +public class LineStationServiceTest { + + final String LINE_NAME = "test line"; + final double DISTANCE = 1; + final double TIME = 1; + final Station upstreamStation = Station.from("test station1"); + final Station downstreamStation = Station.from("test station2"); + final Line line = Line.of(LINE_NAME, upstreamStation, downstreamStation, DISTANCE, TIME); + final int STATIONS_SIZE = 2; + + @BeforeEach + void before() { + LineRepository.save(line); + } + + @AfterEach + void after() { + LineRepository.deleteAll(); + } + + @DisplayName("지하철 노선에 구간을 추가한다.") + @Test + void addSection() { + final double distance = 1; + final double time = 1; + final String insertedStationName = "inserted station"; + final Station station = Station.from("inserted station"); + StationRepository.save(station); + LineStationService.addSection(new SectionInsertRequestDto(LINE_NAME, insertedStationName, distance, time)); + + assertEquals(line.getLineStations().size(), STATIONS_SIZE + 1); + assertSame(line.getLastDownstreamStation(), station); + } +} From 14b917efc8e0d629c86d6889810c90e8c5999add Mon Sep 17 00:00:00 2001 From: Taehwa Lee Date: Sat, 19 Dec 2020 17:09:12 +0900 Subject: [PATCH 7/8] =?UTF-8?q?feat:=20=EC=A7=80=ED=95=98=EC=B2=A0=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EC=9D=84=20=EA=B5=AC=ED=98=84=ED=95=9C=EB=8B=A4.=20-=20?= =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EA=B7=B8=EB=9E=98=ED=94=84=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EC=99=80=20=EC=8B=9C=EA=B0=84=20=EA=B7=B8=EB=9E=98?= =?UTF-8?q?=ED=94=84=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EA=B0=80=EC=A7=80?= =?UTF-8?q?=EA=B3=A0=20=EC=9E=88=EB=8B=A4.=20-=20=EC=B6=9C=EB=B0=9C?= =?UTF-8?q?=EC=97=AD=EA=B3=BC=20=EB=8F=84=EC=B0=A9=EC=97=AD=EC=9D=84=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EB=B0=9B=EC=95=84=20=EC=B5=9C=EB=8B=A8=20?= =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EA=B2=BD=EB=A1=9C=EB=A5=BC=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=ED=95=9C=EB=8B=A4.=20-=20=EC=B6=9C=EB=B0=9C=EC=97=AD?= =?UTF-8?q?=EA=B3=BC=20=EB=8F=84=EC=B0=A9=EC=97=AD=EC=9D=84=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EB=B0=9B=EC=95=84=20=EC=B5=9C=EC=86=8C=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EA=B2=BD=EB=A1=9C=EB=A5=BC=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=9C=EB=8B=A4.=20-=20=EA=B2=BD=EB=A1=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=8B=9C=20=EC=B4=9D=20=EA=B1=B0=EB=A6=AC,=20?= =?UTF-8?q?=EC=B4=9D=20=EC=86=8C=EC=9A=94=20=EC=8B=9C=EA=B0=84=EB=8F=84=20?= =?UTF-8?q?=ED=95=A8=EA=BB=98=20=EC=B6=9C=EB=A0=A5=ED=95=9C=EB=8B=A4.=20-?= =?UTF-8?q?=20=EA=B2=BD=EB=A1=9C=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20?= =?UTF-8?q?=EC=B6=9C=EB=B0=9C=EC=97=AD=EC=9D=B4=EB=82=98=20=EB=8F=84?= =?UTF-8?q?=EC=B0=A9=EC=97=AD=EC=9D=B4=20=EC=A1=B4=EC=9E=AC=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9C=BC=EB=A9=B4=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EB=A5=BC=20=EC=B6=9C=EB=A0=A5=ED=95=9C=EB=8B=A4.=20-=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EC=B6=9C?= =?UTF-8?q?=EB=B0=9C=EC=97=AD=EA=B3=BC=20=EB=8F=84=EC=B0=A9=EC=97=AD?= =?UTF-8?q?=EC=9D=B4=20=EA=B0=99=EC=9C=BC=EB=A9=B4=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EB=A5=BC=20=EC=B6=9C=EB=A0=A5=ED=95=9C=EB=8B=A4.=20-=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EC=B6=9C?= =?UTF-8?q?=EB=B0=9C=EC=97=AD=EA=B3=BC=20=EB=8F=84=EC=B0=A9=EC=97=AD?= =?UTF-8?q?=EC=9D=B4=20=EC=97=B0=EA=B2=B0=EB=90=98=EC=96=B4=20=EC=9E=88?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9C=BC=EB=A9=B4=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EB=A5=BC=20=EC=B6=9C=EB=A0=A5=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/README.md | 17 ++-- src/main/java/subway/DummyData.java | 36 +++++++++ .../Path/{ => domain}/PathRepository.java | 2 +- .../domain/Path/{ => domain}/WeightGraph.java | 7 +- .../domain/Path/dto/PathResponseDto.java | 23 ++++++ .../Path/exception/NotConnectedException.java | 10 +++ .../SameStartAndEndStationException.java | 10 +++ .../domain/Path/service/PathService.java | 43 +++++++++++ .../domain/line/domain/LineStation.java | 2 +- .../domain/line/domain/LineStations.java | 3 +- .../station/dto/StationResponseDto.java | 28 +++++++ .../subway/domain/Path/PathServiceTest.java | 77 +++++++++++++++++++ 12 files changed, 247 insertions(+), 11 deletions(-) create mode 100644 src/main/java/subway/DummyData.java rename src/main/java/subway/domain/Path/{ => domain}/PathRepository.java (96%) rename src/main/java/subway/domain/Path/{ => domain}/WeightGraph.java (81%) create mode 100644 src/main/java/subway/domain/Path/dto/PathResponseDto.java create mode 100644 src/main/java/subway/domain/Path/exception/NotConnectedException.java create mode 100644 src/main/java/subway/domain/Path/exception/SameStartAndEndStationException.java create mode 100644 src/main/java/subway/domain/Path/service/PathService.java create mode 100644 src/main/java/subway/domain/station/dto/StationResponseDto.java create mode 100644 src/test/java/subway/domain/Path/PathServiceTest.java diff --git a/doc/README.md b/doc/README.md index a94e7078b..5fa6c6b79 100644 --- a/doc/README.md +++ b/doc/README.md @@ -53,14 +53,19 @@ 7. LineStation의 속성으로 위의 두 JGrapht Edge를 설정하여 생성한 뒤에 노선의 하행 끝 뒤에 추가한다. ### 경로 관리 기능 -- [ ] 거리 그래프 객체와 시간 그래프 객체를 가지고 있다. -- [ ] 출발역과 도착역을 입력받아 최단 거리 경로를 조회한다. -- [ ] 출발역과 도착역을 입력받아 최소 시간 경로를 조회한다. +- [x] 거리 그래프 객체와 시간 그래프 객체를 가지고 있다. +- [x] 출발역과 도착역을 입력받아 최단 거리 경로를 조회한다. +- [x] 출발역과 도착역을 입력받아 최소 시간 경로를 조회한다. - 경로 조회 시 총 거리, 총 소요 시간도 함께 출력한다. - 예외 처리 - - [ ] 경로 조회 시 출발역이나 도착역이 존재하지 않으면 에러를 출력한다. - - [ ] 경로 조회 시 출발역과 도착역이 같으면 에러를 출력한다. - - [ ] 경로 조회 시 출발역과 도착역이 연결되어 있지 않으면 에러를 출력한다. + - [x] 경로 조회 시 출발역이나 도착역이 존재하지 않으면 에러를 출력한다. + - [x] 경로 조회 시 출발역과 도착역이 같으면 에러를 출력한다. + - [x] 경로 조회 시 출발역과 도착역이 연결되어 있지 않으면 에러를 출력한다. + + +### 생각해보기 +#### 구간 정보가 바뀌면 그래프가 자동으로 업데이트 되도록 하자! +구간 정보에 거리와 시간에 대한 JGrapht의 Edge 정보들을 저장하고 구간 정보가 바뀌어야 할 때 구간 관리 기능을 통해 해당 Edge를 업데이트 해준다.
diff --git a/src/main/java/subway/DummyData.java b/src/main/java/subway/DummyData.java new file mode 100644 index 000000000..a87dd1adb --- /dev/null +++ b/src/main/java/subway/DummyData.java @@ -0,0 +1,36 @@ +package subway; + +import java.util.Arrays; +import subway.domain.line.domain.Line; +import subway.domain.line.domain.LineRepository; +import subway.domain.station.domain.Station; +import subway.domain.station.domain.StationRepository; + +public class DummyData { + + public static void load() { + Station station1 = Station.from("교대역"); + Station station2 = Station.from("강남역"); + Station station3 = Station.from("역삼역"); + Station station4 = Station.from("남부터미널역"); + Station station5 = Station.from("양재역"); + Station station6 = Station.from("양재시민의숲역"); + Station station7 = Station.from("매봉역"); + + StationRepository.saveAll( + Arrays.asList(station1, station2, station3, station4, station5, station6, station7) + ); + + Line line1 = Line.of("2호선", station1, station2, 2, 3); + line1.addSection(station3, 2, 3); + + Line line2 = Line.of("3호선", station1, station4, 3, 2); + line2.addSection(station5, 6, 5); + line2.addSection(station7, 1, 1); + + Line line3 = Line.of("신분당선", station2, station5, 2, 8); + line3.addSection(station6, 10, 3); + + LineRepository.saveAll(Arrays.asList(line1, line2, line3)); + } +} diff --git a/src/main/java/subway/domain/Path/PathRepository.java b/src/main/java/subway/domain/Path/domain/PathRepository.java similarity index 96% rename from src/main/java/subway/domain/Path/PathRepository.java rename to src/main/java/subway/domain/Path/domain/PathRepository.java index edfcc8e12..e66049b2c 100644 --- a/src/main/java/subway/domain/Path/PathRepository.java +++ b/src/main/java/subway/domain/Path/domain/PathRepository.java @@ -1,4 +1,4 @@ -package subway.domain.Path; +package subway.domain.Path.domain; import org.jgrapht.graph.DefaultWeightedEdge; import subway.domain.station.domain.Station; diff --git a/src/main/java/subway/domain/Path/WeightGraph.java b/src/main/java/subway/domain/Path/domain/WeightGraph.java similarity index 81% rename from src/main/java/subway/domain/Path/WeightGraph.java rename to src/main/java/subway/domain/Path/domain/WeightGraph.java index 42c07715f..19222e322 100644 --- a/src/main/java/subway/domain/Path/WeightGraph.java +++ b/src/main/java/subway/domain/Path/domain/WeightGraph.java @@ -1,5 +1,6 @@ -package subway.domain.Path; +package subway.domain.Path.domain; +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.WeightedMultigraph; import subway.domain.station.domain.Station; @@ -27,4 +28,8 @@ public double getEdgeWeight(DefaultWeightedEdge edge) { public void setEdgeWeight(DefaultWeightedEdge edge, double weight) { graph.setEdgeWeight(edge, weight); } + + public DijkstraShortestPath getDijkstraShortestPath() { + return new DijkstraShortestPath(graph); + } } diff --git a/src/main/java/subway/domain/Path/dto/PathResponseDto.java b/src/main/java/subway/domain/Path/dto/PathResponseDto.java new file mode 100644 index 000000000..7949e53e0 --- /dev/null +++ b/src/main/java/subway/domain/Path/dto/PathResponseDto.java @@ -0,0 +1,23 @@ +package subway.domain.Path.dto; + +import java.util.List; +import subway.domain.station.dto.StationResponseDto; + +public class PathResponseDto { + + final List stations; + final double totalWeight; + + public PathResponseDto(List stations, double totalWeight) { + this.stations = stations; + this.totalWeight = totalWeight; + } + + public List getStations() { + return stations; + } + + public double getTotalWeight() { + return totalWeight; + } +} diff --git a/src/main/java/subway/domain/Path/exception/NotConnectedException.java b/src/main/java/subway/domain/Path/exception/NotConnectedException.java new file mode 100644 index 000000000..36e6af9ef --- /dev/null +++ b/src/main/java/subway/domain/Path/exception/NotConnectedException.java @@ -0,0 +1,10 @@ +package subway.domain.Path.exception; + +public class NotConnectedException extends IllegalArgumentException { + + private static final String MESSAGE = "출발역과 도착역이 연결되어 있지 않습니다. (입력 값: '%s, %s')"; + + public NotConnectedException(final String start, final String end) { + super(String.format(MESSAGE, start, end)); + } +} diff --git a/src/main/java/subway/domain/Path/exception/SameStartAndEndStationException.java b/src/main/java/subway/domain/Path/exception/SameStartAndEndStationException.java new file mode 100644 index 000000000..c9784bfd4 --- /dev/null +++ b/src/main/java/subway/domain/Path/exception/SameStartAndEndStationException.java @@ -0,0 +1,10 @@ +package subway.domain.Path.exception; + +public class SameStartAndEndStationException extends IllegalArgumentException { + + private static final String MESSAGE = "출발역과 도착역은 달라야 합니다. (입력 값: '%s, %s')"; + + public SameStartAndEndStationException(final String start, final String end) { + super(String.format(MESSAGE, start, end)); + } +} diff --git a/src/main/java/subway/domain/Path/service/PathService.java b/src/main/java/subway/domain/Path/service/PathService.java new file mode 100644 index 000000000..3df3131c7 --- /dev/null +++ b/src/main/java/subway/domain/Path/service/PathService.java @@ -0,0 +1,43 @@ +package subway.domain.Path.service; + +import org.jgrapht.GraphPath; +import subway.domain.Path.domain.PathRepository; +import subway.domain.Path.domain.WeightGraph; +import subway.domain.Path.dto.PathResponseDto; +import subway.domain.Path.exception.NotConnectedException; +import subway.domain.Path.exception.SameStartAndEndStationException; +import subway.domain.station.domain.Station; +import subway.domain.station.domain.StationRepository; + +public class PathService { + + public static PathResponseDto getShortestDistanceGraphPath(String sourceStationName, + String targetStationName) { + return getShortestRoute(PathRepository.getTimeWeightGraph(), sourceStationName, + targetStationName); + } + + public static PathResponseDto getShortestTimeGraphPath(String sourceStationName, + String targetStationName) { + return getShortestRoute(PathRepository.getDistanceWeightGraph(), sourceStationName, + targetStationName); + } + + private static PathResponseDto getShortestRoute(WeightGraph weightGraph, + String sourceStationName, String targetStationName) { + if (sourceStationName.equals(targetStationName)) { + throw new SameStartAndEndStationException(sourceStationName, targetStationName); + } + + Station sourceStation = StationRepository.findByName(sourceStationName); + Station targetStation = StationRepository.findByName(targetStationName); + + try { + GraphPath graphPath = weightGraph.getDijkstraShortestPath() + .getPath(sourceStation, targetStation); + return new PathResponseDto(graphPath.getEdgeList(), graphPath.getWeight()); + } catch (IllegalArgumentException e) { + throw new NotConnectedException(sourceStationName, targetStationName); + } + } +} diff --git a/src/main/java/subway/domain/line/domain/LineStation.java b/src/main/java/subway/domain/line/domain/LineStation.java index 03defee14..35f602c79 100644 --- a/src/main/java/subway/domain/line/domain/LineStation.java +++ b/src/main/java/subway/domain/line/domain/LineStation.java @@ -1,7 +1,7 @@ package subway.domain.line.domain; import org.jgrapht.graph.DefaultWeightedEdge; -import subway.domain.Path.PathRepository; +import subway.domain.Path.domain.PathRepository; import subway.domain.station.domain.Station; public class LineStation { diff --git a/src/main/java/subway/domain/line/domain/LineStations.java b/src/main/java/subway/domain/line/domain/LineStations.java index 4b3e74938..2d2373293 100644 --- a/src/main/java/subway/domain/line/domain/LineStations.java +++ b/src/main/java/subway/domain/line/domain/LineStations.java @@ -1,10 +1,9 @@ package subway.domain.line.domain; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import org.jgrapht.graph.DefaultWeightedEdge; -import subway.domain.Path.PathRepository; +import subway.domain.Path.domain.PathRepository; import subway.domain.station.domain.Station; public class LineStations { diff --git a/src/main/java/subway/domain/station/dto/StationResponseDto.java b/src/main/java/subway/domain/station/dto/StationResponseDto.java new file mode 100644 index 000000000..45dec2ced --- /dev/null +++ b/src/main/java/subway/domain/station/dto/StationResponseDto.java @@ -0,0 +1,28 @@ +package subway.domain.station.dto; + +import java.util.List; +import java.util.stream.Collectors; +import subway.domain.station.domain.Station; + +public class StationResponseDto { + + private final String name; + + public StationResponseDto(String name) { + this.name = name; + } + + public static StationResponseDto of(Station entity) { + return new StationResponseDto(entity.getName()); + } + + public static List of(List entities) { + return entities.stream() + .map(StationResponseDto::of) + .collect(Collectors.toList()); + } + + public String getName() { + return name; + } +} diff --git a/src/test/java/subway/domain/Path/PathServiceTest.java b/src/test/java/subway/domain/Path/PathServiceTest.java new file mode 100644 index 000000000..aa4daf6e1 --- /dev/null +++ b/src/test/java/subway/domain/Path/PathServiceTest.java @@ -0,0 +1,77 @@ +package subway.domain.Path; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import subway.DummyData; +import subway.domain.Path.dto.PathResponseDto; +import subway.domain.Path.exception.NotConnectedException; +import subway.domain.Path.exception.SameStartAndEndStationException; +import subway.domain.Path.service.PathService; +import subway.domain.station.domain.StationRepository; +import subway.domain.station.dto.StationRequestDto; +import subway.domain.station.exception.CannotFindStationByNameException; +import subway.domain.station.service.StationService; + +class PathServiceTest { + + @BeforeAll + static void beforeAll() { + DummyData.load(); + } + + @DisplayName("출발역과 도착역을 입력받아 최단 거리 경로를 조회한다.") + @Test + void getShortestDistanceRoute() { + final String sourceStationName = "교대역"; + final String targetStationName = "양재역"; + + PathResponseDto responseDto = PathService.getShortestDistanceGraphPath(sourceStationName, targetStationName); + + assertEquals(responseDto.getTotalWeight(), 4); + } + + @DisplayName("출발역과 도착역을 입력받아 최소 시간 경로를 조회한다.") + @Test + void getShortestTimeRoute() { + final String sourceStationName = "교대역"; + final String targetStationName = "양재역"; + + PathResponseDto responseDto = PathService.getShortestTimeGraphPath(sourceStationName, targetStationName); + + assertEquals(responseDto.getTotalWeight(), 7); + } + + @DisplayName("경로 조회 시 출발역이나 도착역이 존재하지 않으면 에러를 출력한다.") + @Test + void cannotFindStationByNameException() { + final String sourceStationName = "평양역"; + final String targetStationName = "서귀포역"; + + assertThrows(CannotFindStationByNameException.class, + () -> PathService.getShortestDistanceGraphPath(sourceStationName, targetStationName)); + } + + @DisplayName("경로 조회 시 출발역과 도착역이 같으면 에러를 출력한다.") + @Test + void sameStartAndEndStationException() { + final String sourceStationName = "교대역"; + final String targetStationName = "교대역"; + + assertThrows(SameStartAndEndStationException.class, + () -> PathService.getShortestDistanceGraphPath(sourceStationName, targetStationName)); + } + + @DisplayName("경로 조회 시 출발역과 도착역이 연결되어 있지 않으면 에러를 출력한다.") + @Test + void notConnectedException() { + final String sourceStationName = "교대역"; + final String targetStationName = "새로운역"; + StationService.save(new StationRequestDto(targetStationName)); + + assertThrows(NotConnectedException.class, + () -> PathService.getShortestDistanceGraphPath(sourceStationName, targetStationName)); + } +} \ No newline at end of file From 4ceb0087c82dcc17d069b7fc0170a50970da1e32 Mon Sep 17 00:00:00 2001 From: Taehwa Lee Date: Sat, 19 Dec 2020 17:41:45 +0900 Subject: [PATCH 8/8] =?UTF-8?q?feat:=20=EB=A9=94=EC=9D=B8=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=9D=84=20=EC=9E=91=EC=84=B1=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=ED=94=84=EB=A1=A0=ED=8A=B8=20=EB=B6=80=EB=B6=84=EC=9D=84=20?= =?UTF-8?q?=EC=9A=94=EA=B5=AC=EC=82=AC=ED=95=AD=EC=97=90=20=EB=A7=9E?= =?UTF-8?q?=EA=B2=8C=20=EC=B6=9C=EB=A0=A5=ED=95=9C=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/subway/ActionType.java | 18 ++++++ src/main/java/subway/Application.java | 20 +++++- src/main/java/subway/CategoryType.java | 31 +++++++++ src/main/java/subway/HandlerMapping.java | 25 ++++++++ src/main/java/subway/utils/ErrorUtils.java | 30 +++++++++ .../java/subway/utils/SupplierNoReturn.java | 7 +++ src/main/java/subway/view/InputView.java | 63 +++++++++++++++++++ src/main/java/subway/view/OutputView.java | 31 +++++++++ .../exception/InvalidCommandException.java | 10 +++ .../java/subway/view/screen/MainScreen.java | 47 ++++++++++++++ .../subway/view/screen/ManagementScreen.java | 54 ++++++++++++++++ src/main/java/subway/view/screen/Screen.java | 22 +++++++ .../subway/view/screen/ScreenManager.java | 43 +++++++++++++ .../view/screen/action/BaseActionScreen.java | 28 +++++++++ .../ShortestDistancePathActionScreen.java | 42 +++++++++++++ .../path/ShortestTimePathActionScreen.java | 42 +++++++++++++ .../subway/domain/Path/PathServiceTest.java | 1 - .../domain/station/StationRepositoryTest.java | 9 --- 18 files changed, 512 insertions(+), 11 deletions(-) create mode 100644 src/main/java/subway/ActionType.java create mode 100644 src/main/java/subway/CategoryType.java create mode 100644 src/main/java/subway/HandlerMapping.java create mode 100644 src/main/java/subway/utils/ErrorUtils.java create mode 100644 src/main/java/subway/utils/SupplierNoReturn.java create mode 100644 src/main/java/subway/view/InputView.java create mode 100644 src/main/java/subway/view/OutputView.java create mode 100644 src/main/java/subway/view/exception/InvalidCommandException.java create mode 100644 src/main/java/subway/view/screen/MainScreen.java create mode 100644 src/main/java/subway/view/screen/ManagementScreen.java create mode 100644 src/main/java/subway/view/screen/Screen.java create mode 100644 src/main/java/subway/view/screen/ScreenManager.java create mode 100644 src/main/java/subway/view/screen/action/BaseActionScreen.java create mode 100644 src/main/java/subway/view/screen/action/path/ShortestDistancePathActionScreen.java create mode 100644 src/main/java/subway/view/screen/action/path/ShortestTimePathActionScreen.java diff --git a/src/main/java/subway/ActionType.java b/src/main/java/subway/ActionType.java new file mode 100644 index 000000000..7b2834654 --- /dev/null +++ b/src/main/java/subway/ActionType.java @@ -0,0 +1,18 @@ +package subway; + +public enum ActionType { + + SHORTEST_DISTANCE_PATH("최단 거리"), + SHORTEST_TIME_PATH("최소 시간"), + BACK("돌아가기"); + + private final String name; + + ActionType(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/subway/Application.java b/src/main/java/subway/Application.java index 0bcf786cc..fceb99b6f 100644 --- a/src/main/java/subway/Application.java +++ b/src/main/java/subway/Application.java @@ -1,10 +1,28 @@ package subway; import java.util.Scanner; +import subway.utils.ErrorUtils; +import subway.view.InputView; +import subway.view.screen.MainScreen; +import subway.view.screen.ScreenManager; public class Application { + public static void main(String[] args) { final Scanner scanner = new Scanner(System.in); - // TODO: 프로그램 구현 + InputView inputView = InputView.of(scanner); + DummyData.load(); + start(inputView); + } + + public static void start(InputView inputView) { + ScreenManager.push(new MainScreen()); + + while (!ScreenManager.isEmpty()) { + ErrorUtils.screenGoBackWhenException(() -> { + ScreenManager.visualize(); + ScreenManager.logic(inputView); + }); + } } } diff --git a/src/main/java/subway/CategoryType.java b/src/main/java/subway/CategoryType.java new file mode 100644 index 000000000..72977fd23 --- /dev/null +++ b/src/main/java/subway/CategoryType.java @@ -0,0 +1,31 @@ +package subway; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public enum CategoryType { + + STATION( + "경로 조회", + Arrays.asList(ActionType.SHORTEST_DISTANCE_PATH, ActionType.SHORTEST_TIME_PATH)), + EXIT( + "종료", + Collections.emptyList()); + + private final String name; + private final List actionOrder; + + CategoryType(String name, List actionOrder) { + this.name = name; + this.actionOrder = actionOrder; + } + + public String getName() { + return name; + } + + public List getActionOrder() { + return actionOrder; + } +} diff --git a/src/main/java/subway/HandlerMapping.java b/src/main/java/subway/HandlerMapping.java new file mode 100644 index 000000000..020fe47b7 --- /dev/null +++ b/src/main/java/subway/HandlerMapping.java @@ -0,0 +1,25 @@ +package subway; + +import subway.view.screen.ScreenManager; +import subway.view.screen.action.path.ShortestDistancePathActionScreen; +import subway.view.screen.action.path.ShortestTimePathActionScreen; + +public class HandlerMapping { + + public static void mapping(CategoryType categoryType, ActionType actionType) { + if (categoryType == CategoryType.STATION) { + pathMapping(categoryType, actionType); + } + } + + private static void pathMapping(CategoryType categoryType, ActionType actionType) { + if (actionType == ActionType.SHORTEST_DISTANCE_PATH) { + ScreenManager.push(new ShortestDistancePathActionScreen(categoryType)); + return; + } + + if (actionType == ActionType.SHORTEST_TIME_PATH) { + ScreenManager.push(new ShortestTimePathActionScreen(categoryType)); + } + } +} diff --git a/src/main/java/subway/utils/ErrorUtils.java b/src/main/java/subway/utils/ErrorUtils.java new file mode 100644 index 000000000..51b4cb017 --- /dev/null +++ b/src/main/java/subway/utils/ErrorUtils.java @@ -0,0 +1,30 @@ +package subway.utils; + +import java.util.function.Supplier; +import subway.view.OutputView; +import subway.view.screen.Screen; +import subway.view.screen.ScreenManager; + +public class ErrorUtils { + + public static Object repeatingUntilNoException(final Supplier supplier) { + while (true) { + try { + return supplier.get(); + } catch (RuntimeException e) { + OutputView.println(); + OutputView.println(Screen.ERROR_PREFIX + e.getMessage()); + } + } + } + + public static void screenGoBackWhenException(final SupplierNoReturn supplierNoReturn) { + try { + supplierNoReturn.execute(); + } catch (RuntimeException e) { + OutputView.println(); + OutputView.println(Screen.ERROR_PREFIX + e.getMessage()); + ScreenManager.goBack(); + } + } +} diff --git a/src/main/java/subway/utils/SupplierNoReturn.java b/src/main/java/subway/utils/SupplierNoReturn.java new file mode 100644 index 000000000..0fc85ce16 --- /dev/null +++ b/src/main/java/subway/utils/SupplierNoReturn.java @@ -0,0 +1,7 @@ +package subway.utils; + +@FunctionalInterface +public interface SupplierNoReturn { + + void execute(); +} diff --git a/src/main/java/subway/view/InputView.java b/src/main/java/subway/view/InputView.java new file mode 100644 index 000000000..9593a67f6 --- /dev/null +++ b/src/main/java/subway/view/InputView.java @@ -0,0 +1,63 @@ +package subway.view; + +import java.util.Scanner; +import subway.CategoryType; +import subway.view.exception.InvalidCommandException; +import subway.view.screen.MainScreen; + +public final class InputView { + + public static final String ONLY_DIGIT_REGULAR = "^[0-9]*$"; + public static final int MIN_LIST_NUMBER = 1; + public static final String EXIT_COMMAND = "q"; + public static final String BACK_COMMAND = "b"; + public static final int EXIT = -1; + public static final int BACK = -1; + + private final Scanner scanner; + + private InputView(final Scanner scanner) { + this.scanner = scanner; + } + + public static InputView of(final Scanner scanner) { + return new InputView(scanner); + } + + public int readCategoryCommandNumber() { + String command = readCommand().toLowerCase(); + + if (command.equals(InputView.EXIT_COMMAND)) { + return EXIT; + } + + return converToNumber(command, MainScreen.MAIN_CATEGORIES.size()); + } + + public int readActionOrderCommandNumber(CategoryType selectedCategoryType) { + String command = readCommand().toLowerCase(); + + if (command.equals(InputView.BACK_COMMAND)) { + return BACK; + } + + return converToNumber(command, selectedCategoryType.getActionOrder().size()); + } + + private int converToNumber(String command, int listSize) { + if (!command.matches(InputView.ONLY_DIGIT_REGULAR) || command.isEmpty()) { + throw new InvalidCommandException(command); + } + + int commandNumber = Integer.parseInt(command); + if (commandNumber < MIN_LIST_NUMBER || commandNumber > listSize) { + throw new InvalidCommandException(command); + } + + return commandNumber; + } + + public String readCommand() { + 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..067e315fc --- /dev/null +++ b/src/main/java/subway/view/OutputView.java @@ -0,0 +1,31 @@ +package subway.view; + +import subway.view.screen.Screen; + +public final class OutputView { + + private OutputView() { + } + + public static void println(final String value) { + System.out.println(value); + } + + public static void println() { + System.out.println(); + } + + public static void printResult(final String value) { + println(Screen.INFO_PREFIX + value); + } + + public static void printlnResult(final String value) { + println(); + println(Screen.INFO_PREFIX + value); + } + + public static void printTitle(final String value) { + println(); + println(Screen.DOUBLE_SHARP + value); + } +} diff --git a/src/main/java/subway/view/exception/InvalidCommandException.java b/src/main/java/subway/view/exception/InvalidCommandException.java new file mode 100644 index 000000000..38aab5868 --- /dev/null +++ b/src/main/java/subway/view/exception/InvalidCommandException.java @@ -0,0 +1,10 @@ +package subway.view.exception; + +public class InvalidCommandException extends RuntimeException { + + private static final String MESSAGE = "선택할 수 없는 기능입니다. (입력 값: '%s')"; + + public InvalidCommandException(final String input) { + super(String.format(MESSAGE, input)); + } +} diff --git a/src/main/java/subway/view/screen/MainScreen.java b/src/main/java/subway/view/screen/MainScreen.java new file mode 100644 index 000000000..bd7a2ef38 --- /dev/null +++ b/src/main/java/subway/view/screen/MainScreen.java @@ -0,0 +1,47 @@ +package subway.view.screen; + +import java.util.Arrays; +import java.util.List; +import subway.CategoryType; +import subway.utils.ErrorUtils; +import subway.view.InputView; +import subway.view.OutputView; + +public class MainScreen implements Screen { + + public static final String MAIN_SCREEN_MESSAGE = "메인 화면"; + + public static final List MAIN_CATEGORIES = Arrays.asList( + CategoryType.STATION + ); + + @Override + public void visualize() { + OutputView.printTitle(MAIN_SCREEN_MESSAGE); + + for (int i = 1; i <= MAIN_CATEGORIES.size(); i++) { + System.out.println(i + COMMA + MAIN_CATEGORIES.get(i - 1).getName()); + } + + OutputView.println(InputView.EXIT_COMMAND.toUpperCase() + COMMA + CategoryType.EXIT.getName()); + } + + @Override + public void logic(InputView inputView) { + int categoryCommandNumber = getCategoryCommandNumber(inputView); + if (categoryCommandNumber == InputView.EXIT) { + ScreenManager.exit(); + return; + } + + CategoryType selectedCategoryType = MAIN_CATEGORIES.get(categoryCommandNumber - 1); + ScreenManager.push(new ManagementScreen(selectedCategoryType)); + } + + private int getCategoryCommandNumber(InputView inputView) { + return (int) ErrorUtils.repeatingUntilNoException(() -> { + OutputView.printTitle(Screen.SELECT_CATEGORY_MESSAGE); + return inputView.readCategoryCommandNumber(); + }); + } +} diff --git a/src/main/java/subway/view/screen/ManagementScreen.java b/src/main/java/subway/view/screen/ManagementScreen.java new file mode 100644 index 000000000..ace72d9d7 --- /dev/null +++ b/src/main/java/subway/view/screen/ManagementScreen.java @@ -0,0 +1,54 @@ +package subway.view.screen; + +import java.util.List; +import subway.ActionType; +import subway.CategoryType; +import subway.HandlerMapping; +import subway.utils.ErrorUtils; +import subway.view.InputView; +import subway.view.OutputView; + +public class ManagementScreen implements Screen { + + public static final String MANAGEMENT_SCREEN_MESSAGE = "경로 기준"; + + public CategoryType selectedCategoryType; + + public ManagementScreen(CategoryType selectedCategoryType) { + this.selectedCategoryType = selectedCategoryType; + } + + @Override + public void visualize() { + OutputView.printTitle(MANAGEMENT_SCREEN_MESSAGE); + + List actionOrder = selectedCategoryType.getActionOrder(); + for (int i = 1; i <= actionOrder.size(); i++) { + OutputView.println( + i + COMMA + actionOrder.get(i - 1).getName()); + } + + OutputView.println(InputView.BACK_COMMAND.toUpperCase() + COMMA + ActionType.BACK.getName()); + } + + @Override + public void logic(InputView inputView) { + int actionOrderCommandNumber = getActionOrderCommandNumber(inputView); + if (actionOrderCommandNumber == InputView.BACK) { + ScreenManager.goBack(); + return; + } + + ActionType actionType = selectedCategoryType.getActionOrder() + .get(actionOrderCommandNumber - 1); + + HandlerMapping.mapping(selectedCategoryType, actionType); + } + + private int getActionOrderCommandNumber(InputView inputView) { + return (int) ErrorUtils.repeatingUntilNoException(() -> { + OutputView.printTitle(Screen.SELECT_CATEGORY_MESSAGE); + return inputView.readActionOrderCommandNumber(selectedCategoryType); + }); + } +} diff --git a/src/main/java/subway/view/screen/Screen.java b/src/main/java/subway/view/screen/Screen.java new file mode 100644 index 000000000..44c1f5ca4 --- /dev/null +++ b/src/main/java/subway/view/screen/Screen.java @@ -0,0 +1,22 @@ +package subway.view.screen; + +import subway.view.InputView; + +public interface Screen { + + String ERROR_PREFIX = "[ERROR] "; + String INFO_PREFIX = "[INFO] "; + String SELECT_CATEGORY_MESSAGE = "원하는 기능을 선택하세요."; + String DOUBLE_SHARP = "## "; + String SPACE = " "; + String COMMA = ". "; + String COLUMN_LINE = "---"; + String MANAGEMENT_MESSAGE = "관리"; + String LIST_MESSAGE = "목록"; + String PRINT_MESSAGE = "출력"; + String RESULT_MESSAGE = "조회 결과"; + String DOT_DOT = ": "; + + void visualize(); + void logic(InputView inputView); +} diff --git a/src/main/java/subway/view/screen/ScreenManager.java b/src/main/java/subway/view/screen/ScreenManager.java new file mode 100644 index 000000000..78e0986ff --- /dev/null +++ b/src/main/java/subway/view/screen/ScreenManager.java @@ -0,0 +1,43 @@ +package subway.view.screen; + +import java.util.Stack; +import subway.view.InputView; + +public class ScreenManager { + + public static final Stack stack = new Stack<>(); + + public static void push(Screen screen) { + stack.push(screen); + } + + public static void goBack() { + stack.pop(); + } + + public static Screen peek() { + return stack.peek(); + } + + public static boolean isEmpty() { + return stack.isEmpty(); + } + + public static void visualize() { + peek().visualize(); + } + + public static void logic(InputView inputView) { + peek().logic(inputView); + } + + public static void exit() { + stack.clear(); + } + + public static void goToFirstScreen() { + while (stack.size() > 1) { + goBack(); + } + } +} diff --git a/src/main/java/subway/view/screen/action/BaseActionScreen.java b/src/main/java/subway/view/screen/action/BaseActionScreen.java new file mode 100644 index 000000000..533721e42 --- /dev/null +++ b/src/main/java/subway/view/screen/action/BaseActionScreen.java @@ -0,0 +1,28 @@ +package subway.view.screen.action; + +import subway.CategoryType; +import subway.view.InputView; +import subway.view.screen.Screen; +import subway.view.screen.ScreenManager; + +public abstract class BaseActionScreen implements Screen { + + public static final String TOTAL_DISTANCE_MESSAGE = "총 거리"; + public static final String TOTAL_TIME_MESSAGE = "총 소요 시간"; + public static final String MINUTE_MESSAGE = "분"; + public static final String KILLOMETER_MESSAGE = "km"; + + public CategoryType selectedCategoryType; + + public BaseActionScreen(CategoryType selectedCategoryType) { + this.selectedCategoryType = selectedCategoryType; + } + + @Override + public void logic(InputView inputView) { + action(inputView); + ScreenManager.goToFirstScreen(); + } + + protected abstract void action(InputView inputView); +} diff --git a/src/main/java/subway/view/screen/action/path/ShortestDistancePathActionScreen.java b/src/main/java/subway/view/screen/action/path/ShortestDistancePathActionScreen.java new file mode 100644 index 000000000..9af7ac86c --- /dev/null +++ b/src/main/java/subway/view/screen/action/path/ShortestDistancePathActionScreen.java @@ -0,0 +1,42 @@ +package subway.view.screen.action.path; + +import subway.CategoryType; +import subway.domain.Path.dto.PathResponseDto; +import subway.domain.Path.service.PathService; +import subway.domain.line.service.LineService; +import subway.view.InputView; +import subway.view.OutputView; +import subway.view.screen.action.BaseActionScreen; + +public class ShortestDistancePathActionScreen extends BaseActionScreen { + + public static final String START_STATION_NAME_INPUT_MESSAGE = "출발역을 입력하세요."; + public static final String END_STATION_NAME_INPUT_MESSAGE = "도착역을 입력하세요."; + + public ShortestDistancePathActionScreen(CategoryType selectedCategoryType) { + super(selectedCategoryType); + } + + @Override + public void visualize() { + } + + @Override + protected void action(InputView inputView) { + OutputView.printTitle(START_STATION_NAME_INPUT_MESSAGE); + String sourceStationName = inputView.readCommand(); + + OutputView.printTitle(END_STATION_NAME_INPUT_MESSAGE); + String targetStationName = inputView.readCommand(); + + PathResponseDto responseDto = PathService + .getShortestDistanceGraphPath(sourceStationName, targetStationName); + + OutputView.printTitle(RESULT_MESSAGE); + OutputView.printResult(COLUMN_LINE); + OutputView.printResult(TOTAL_DISTANCE_MESSAGE + DOT_DOT + responseDto.getTotalWeight() + KILLOMETER_MESSAGE); + OutputView.printResult(COLUMN_LINE); + responseDto.getStations().forEach( + lineResponseDto -> OutputView.printResult(lineResponseDto.getName())); + } +} diff --git a/src/main/java/subway/view/screen/action/path/ShortestTimePathActionScreen.java b/src/main/java/subway/view/screen/action/path/ShortestTimePathActionScreen.java new file mode 100644 index 000000000..769d8b0c6 --- /dev/null +++ b/src/main/java/subway/view/screen/action/path/ShortestTimePathActionScreen.java @@ -0,0 +1,42 @@ +package subway.view.screen.action.path; + +import subway.CategoryType; +import subway.domain.Path.dto.PathResponseDto; +import subway.domain.Path.service.PathService; +import subway.domain.line.service.LineService; +import subway.view.InputView; +import subway.view.OutputView; +import subway.view.screen.action.BaseActionScreen; + +public class ShortestTimePathActionScreen extends BaseActionScreen { + + public static final String START_STATION_NAME_INPUT_MESSAGE = "출발역을 입력하세요."; + public static final String END_STATION_NAME_INPUT_MESSAGE = "도착역을 입력하세요."; + + public ShortestTimePathActionScreen(CategoryType selectedCategoryType) { + super(selectedCategoryType); + } + + @Override + public void visualize() { + } + + @Override + protected void action(InputView inputView) { + OutputView.printTitle(START_STATION_NAME_INPUT_MESSAGE); + String sourceStationName = inputView.readCommand(); + + OutputView.printTitle(END_STATION_NAME_INPUT_MESSAGE); + String targetStationName = inputView.readCommand(); + + PathResponseDto responseDto = PathService + .getShortestDistanceGraphPath(sourceStationName, targetStationName); + + OutputView.printTitle(RESULT_MESSAGE); + OutputView.printResult(COLUMN_LINE); + OutputView.printResult(TOTAL_TIME_MESSAGE + DOT_DOT + responseDto.getTotalWeight() + MINUTE_MESSAGE); + OutputView.printResult(COLUMN_LINE); + responseDto.getStations().forEach( + lineResponseDto -> OutputView.printResult(lineResponseDto.getName())); + } +} diff --git a/src/test/java/subway/domain/Path/PathServiceTest.java b/src/test/java/subway/domain/Path/PathServiceTest.java index aa4daf6e1..85b5b8d4d 100644 --- a/src/test/java/subway/domain/Path/PathServiceTest.java +++ b/src/test/java/subway/domain/Path/PathServiceTest.java @@ -10,7 +10,6 @@ import subway.domain.Path.exception.NotConnectedException; import subway.domain.Path.exception.SameStartAndEndStationException; import subway.domain.Path.service.PathService; -import subway.domain.station.domain.StationRepository; import subway.domain.station.dto.StationRequestDto; import subway.domain.station.exception.CannotFindStationByNameException; import subway.domain.station.service.StationService; diff --git a/src/test/java/subway/domain/station/StationRepositoryTest.java b/src/test/java/subway/domain/station/StationRepositoryTest.java index 0c8cea074..537818f10 100644 --- a/src/test/java/subway/domain/station/StationRepositoryTest.java +++ b/src/test/java/subway/domain/station/StationRepositoryTest.java @@ -50,15 +50,6 @@ void addStation() { assertEquals(StationRepository.findAll().size(), EXPECT); } - @DisplayName("지하철 역 저장소에서 지하철 역을 삭제할 수 있다.") - @Test - void deleteStation() { - StationRepository.delete(station1); - - final int EXPECT = SIZE - 1; - assertEquals(StationRepository.findAll().size(), EXPECT); - } - @DisplayName("등록되지 않은 지하철 역은 조회할 수 없다.") @Test void cannotFindStationByNameException() {