Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
0fa335b
docs: 0. 설계
jaehyeonjung0613 Feb 10, 2025
5443b27
rename: DDD 구조로 변경
jaehyeonjung0613 Feb 10, 2025
80172e2
feat: 1. Line CRUD
jaehyeonjung0613 Feb 10, 2025
f591c30
docs: 1. Line CRUD
jaehyeonjung0613 Feb 10, 2025
90b4616
feat: 2. Station CRUD
jaehyeonjung0613 Feb 10, 2025
a56aa59
docs: 2. Station CRUD
jaehyeonjung0613 Feb 10, 2025
9fc4be9
refactor: 1. Line CRUD
jaehyeonjung0613 Feb 10, 2025
24830ef
feat: 3. Section CRUD
jaehyeonjung0613 Feb 10, 2025
6c5c7cc
refactor: 1. Line CRUD
jaehyeonjung0613 Feb 10, 2025
85737ee
refactor: 2. Station CRUD
jaehyeonjung0613 Feb 10, 2025
fedc7ac
refactor: 3. Section CRUD
jaehyeonjung0613 Feb 10, 2025
76d9592
feat: 4. 최단 거리 노드, 간선 추가
jaehyeonjung0613 Feb 11, 2025
11269d1
docs: 4. 최단 거리 노드, 간선 추가
jaehyeonjung0613 Feb 11, 2025
53e1727
feat: 5. 최단 거리 경로 구하기
jaehyeonjung0613 Feb 11, 2025
f41ea4a
docs: 5. 최단 거리 경로 구하기
jaehyeonjung0613 Feb 11, 2025
6040632
refactor: 4. 최단 거리 노드, 간선 추가
jaehyeonjung0613 Feb 11, 2025
02bed47
refactor: 1. Line CRUD
jaehyeonjung0613 Feb 11, 2025
14eaf9a
refactor: 2. Station CRUD
jaehyeonjung0613 Feb 11, 2025
c647400
refactor: 3. Section CRUD
jaehyeonjung0613 Feb 11, 2025
226bcb8
refactor: 5. 최단 거리 경로 구하기
jaehyeonjung0613 Feb 11, 2025
a35877a
feat: 6. 그래프 관련 기능 통합
jaehyeonjung0613 Feb 11, 2025
768e163
docs: 6. 그래프 관련 기능 통합
jaehyeonjung0613 Feb 11, 2025
e705bba
feat: 7. 최소 시간 경로 구하기
jaehyeonjung0613 Feb 11, 2025
2f0a8be
docs: 7. 최소 시간 경로 구하기
jaehyeonjung0613 Feb 11, 2025
8c81180
refactor: 6. 그래프 관련 기능 통합
jaehyeonjung0613 Feb 11, 2025
f89f6b6
refactor: 7. 최소 시간 경로 구하기
jaehyeonjung0613 Feb 11, 2025
7515e91
refactor: 지점 용어 삭제
jaehyeonjung0613 Feb 11, 2025
a0983ea
feat: 7. 최소 시간 경로 구하기
jaehyeonjung0613 Feb 12, 2025
ec1fe4a
refactor: 5. 최단 거리 경로 구하기
jaehyeonjung0613 Feb 12, 2025
67a7ac0
feat: 8. Screen Layer Skeleton
jaehyeonjung0613 Feb 13, 2025
c3a6daa
docs: 8. Screen Layer Skeleton
jaehyeonjung0613 Feb 13, 2025
69d918c
feat: 9. 경로 기준(화면) 구현
jaehyeonjung0613 Feb 13, 2025
27a10e4
docs: 9. 경로 기준(화면) 구현
jaehyeonjung0613 Feb 13, 2025
84134a0
feat: 10. 메인 화면 구현
jaehyeonjung0613 Feb 13, 2025
1895a74
docs: 10. 메인 화면 구현
jaehyeonjung0613 Feb 13, 2025
b4c27bf
feat: 11. 파일 검증
jaehyeonjung0613 Feb 13, 2025
297a491
docs: 11. 파일 검증
jaehyeonjung0613 Feb 13, 2025
69f60e0
feat: 12. Xml Parser
jaehyeonjung0613 Feb 13, 2025
86820fc
docs: 12. Xml Parser
jaehyeonjung0613 Feb 13, 2025
358bdf7
resource: 13. 초기 데이터 정의
jaehyeonjung0613 Feb 13, 2025
ec1be41
docs: 13. 초기 데이터 정의
jaehyeonjung0613 Feb 13, 2025
6097a25
feat: 14. 인트로 화면 구현
jaehyeonjung0613 Feb 13, 2025
43db714
docs: 14. 인트로 화면 구현
jaehyeonjung0613 Feb 13, 2025
4b28d4d
feat: 15. 애플리케이션 실행
jaehyeonjung0613 Feb 13, 2025
d0472a8
docs: 15. 애플리케이션 실행
jaehyeonjung0613 Feb 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,873 changes: 3,873 additions & 0 deletions .github/solving_process.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,7 @@ public void getDijkstraShortestPath() {
## 📝 License

This project is [MIT](https://github.com/woowacourse/java-subway-path-precourse/blob/master/LICENSE.md) licensed.

## 🧩 풀이 과정

[solving_process.md](https://github.com/jaehyeonjung0613/java-subway-path-precourse/blob/main/.github/solving_process.md)
8 changes: 4 additions & 4 deletions src/main/java/subway/Application.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package subway;

import java.util.Scanner;
import subway.presentation.IntroViewController;

public class Application {
public static void main(String[] args) {
final Scanner scanner = new Scanner(System.in);
// TODO: 프로그램 구현
IntroViewController introViewController = new IntroViewController();
introViewController.execute();
}
}
}
69 changes: 69 additions & 0 deletions src/main/java/subway/application/section/dto/SectionDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package subway.application.section.dto;

import subway.domain.line.LineDTO;
import subway.domain.station.StationDTO;

public class SectionDTO {
private static final String SECTION_ADDING_LINE_INFO_ESSENTIAL_MESSAGE = "구간 생성시 노선 정보는 필수입니다.";
private static final String SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "구간 생성시 시작역 정보는 필수입니다.";
private static final String SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE = "구간 생성시 종료역 정보는 필수입니다.";

private final LineDTO lineDTO;
private final StationDTO sourceDTO;
private final StationDTO sinkDTO;
private int distance;
private int time;

public SectionDTO(LineDTO lineDTO, StationDTO sourceDTO, StationDTO sinkDTO) {
this(lineDTO, sourceDTO, sinkDTO, 0, 0);
}

public SectionDTO(LineDTO lineDTO, StationDTO sourceDTO, StationDTO sinkDTO, int distance, int time) {
this.validate(lineDTO, sourceDTO, sinkDTO);
this.lineDTO = lineDTO;
this.sourceDTO = sourceDTO;
this.sinkDTO = sinkDTO;
this.distance = distance;
this.time = time;
}

private void validate(LineDTO lineDTO, StationDTO sourceDTO, StationDTO sinkDTO) {
if (lineDTO == null) {
throw new IllegalArgumentException(SECTION_ADDING_LINE_INFO_ESSENTIAL_MESSAGE);
}
if (sourceDTO == null) {
throw new IllegalArgumentException(SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE);
}
if (sinkDTO == null) {
throw new IllegalArgumentException(SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE);
}
}

public LineDTO getLineDTO() {
return lineDTO;
}

public StationDTO getSourceDTO() {
return sourceDTO;
}

public StationDTO getSinkDTO() {
return sinkDTO;
}

public int getDistance() {
return distance;
}

public void setDistance(int distance) {
this.distance = distance;
}

public int getTime() {
return time;
}

public void setTime(int time) {
this.time = time;
}
}
38 changes: 38 additions & 0 deletions src/main/java/subway/application/section/dto/ShortCostRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package subway.application.section.dto;

import subway.domain.station.StationDTO;

public class ShortCostRequest {
private static final String SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "시작역 정보는 필수입니다.";
private static final String SINK_STATION_INFO_ESSENTIAL_MESSAGE = "종료역 정보는 필수입니다.";
private static final String SAME_SOURCE_AND_SINK_STATION_MESSAGE = "출발역과 도착역이 동일합니다.";

private final StationDTO sourceDTO;
private final StationDTO sinkDTO;

public ShortCostRequest(StationDTO sourceDTO, StationDTO sinkDTO) {
this.validate(sourceDTO, sinkDTO);
this.sourceDTO = sourceDTO;
this.sinkDTO = sinkDTO;
}

private void validate(StationDTO sourceDTO, StationDTO sinkDTO) {
if(sourceDTO == null) {
throw new IllegalArgumentException(SOURCE_STATION_INFO_ESSENTIAL_MESSAGE);
}
if(sinkDTO == null) {
throw new IllegalArgumentException(SINK_STATION_INFO_ESSENTIAL_MESSAGE);
}
if(sourceDTO.equals(sinkDTO)) {
throw new IllegalArgumentException(SAME_SOURCE_AND_SINK_STATION_MESSAGE);
}
}

public StationDTO getSourceDTO() {
return sourceDTO;
}

public StationDTO getSinkDTO() {
return sinkDTO;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package subway.application.section.dto;

import java.util.ArrayList;
import java.util.List;

import subway.domain.station.Station;

public class ShortCostResponse {
private int totalDistance;
private int totalTime;
private final List<String> stationNameList;

public ShortCostResponse(List<Station> stationList) {
this.stationNameList = new ArrayList<>();
int length = stationList.size();
for (int index = 0; index < length; index++) {
Station source = stationList.get(index);
if (index + 1 < length) {
Station sink = stationList.get(index + 1);
totalDistance += source.findDistanceTo(sink);
totalTime += source.findTimeTo(sink);
}
stationNameList.add(source.getName());
}
}

public int getTotalDistance() {
return totalDistance;
}

public void setTotalDistance(int totalDistance) {
this.totalDistance = totalDistance;
}

public int getTotalTime() {
return totalTime;
}

public void setTotalTime(int totalTime) {
this.totalTime = totalTime;
}

public List<String> getStationNameList() {
return stationNameList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package subway.application.section.service;

import java.util.List;

import org.jgrapht.GraphPath;
import org.jgrapht.graph.DefaultWeightedEdge;

import subway.application.section.dto.SectionDTO;
import subway.application.section.dto.ShortCostRequest;
import subway.application.section.dto.ShortCostResponse;
import subway.domain.line.Line;
import subway.domain.line.LineService;
import subway.domain.section.Section;
import subway.domain.section.SectionRepository;
import subway.domain.station.Station;
import subway.domain.station.StationDTO;
import subway.domain.station.StationService;

public class SectionService {
private static final String ALREADY_EXISTS_SECTION_MESSAGE = "이미 등록되어있는 구간입니다.";
private static final String NOT_EXISTS_SOURCE_STATION_MESSAGE = "존재하지 않은 시작역입니다.";
private static final String NOT_EXISTS_SINK_STATION_MESSAGE = "존재하지 않은 종료역입니다.";
private static final String NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE = "시작 지점과 종료역이 연결되어 있지 않습니다.";

private final LineService lineService = new LineService();
private final StationService stationService = new StationService();
private final ShortDistanceService shortDistanceService = new ShortDistanceService();
private final ShortTimeService shortTimeService = new ShortTimeService();

public List<Section> findAll() {
return SectionRepository.sections();
}

public void addNode(StationDTO stationDTO) {
Station station = this.stationService.findOneByName(stationDTO.getName());
this.shortDistanceService.addNode(station);
this.shortTimeService.addNode(station);
}

public void addSection(SectionDTO sectionDTO) {
Line line = this.lineService.findOneByName(sectionDTO.getLineDTO().getName());
Station source = this.stationService.findOneByName(sectionDTO.getSourceDTO().getName());
Station sink = this.stationService.findOneByName(sectionDTO.getSinkDTO().getName());
Section section = new Section(line, source, sink, sectionDTO.getDistance(), sectionDTO.getTime());
if (SectionRepository.exists(section)) {
throw new IllegalArgumentException(ALREADY_EXISTS_SECTION_MESSAGE);
}
SectionRepository.addSection(section);
this.shortDistanceService.addEdge(section);
this.shortTimeService.addEdge(section);
line.addSection(section);
source.addSection(section);
}

public ShortCostResponse computeShortDistance(ShortCostRequest shortCostRequest) {
Station source = this.stationService.findByName(shortCostRequest.getSourceDTO().getName())
.orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SOURCE_STATION_MESSAGE));
Station sink = this.stationService.findByName(shortCostRequest.getSinkDTO().getName())
.orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SINK_STATION_MESSAGE));
GraphPath<Station, DefaultWeightedEdge> graphPath = this.shortDistanceService.compute(source, sink);
if (graphPath == null) {
throw new IllegalArgumentException(NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE);
}
return new ShortCostResponse(graphPath.getVertexList());
}

public ShortCostResponse computeShortTime(ShortCostRequest shortCostRequest) {
Station source = this.stationService.findByName(shortCostRequest.getSourceDTO().getName())
.orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SOURCE_STATION_MESSAGE));
Station sink = this.stationService.findByName(shortCostRequest.getSinkDTO().getName())
.orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SINK_STATION_MESSAGE));
GraphPath<Station, DefaultWeightedEdge> graphPath = this.shortDistanceService.compute(source, sink);
if (graphPath == null) {
throw new IllegalArgumentException(NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE);
}
return new ShortCostResponse(graphPath.getVertexList());
}

public void deleteAll() {
SectionRepository.deleteAll();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package subway.application.section.service;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.jgrapht.GraphPath;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.AbstractBaseGraph;
import org.jgrapht.graph.DefaultWeightedEdge;

import subway.domain.section.Section;
import subway.domain.station.Station;

abstract class ShortCostService {
private final AbstractBaseGraph<Station, DefaultWeightedEdge> graph;

public ShortCostService(AbstractBaseGraph<Station, DefaultWeightedEdge> graph) {
this.graph = graph;
}

private static final String ALREADY_EXISTS_NODE_MESSAGE = "이미 등록되어있는 노드입니다.";
private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "존재하지 않은 시작노드입니다.";
private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "존재하지 않은 종료노드입니다.";
private static final String ALREADY_EXISTS_EDGE_MESSAGE = "이미 등록되어있는 간선입니다.";

protected Set<Station> findAllNode() {
return Collections.unmodifiableSet(graph.vertexSet());
}

protected Set<DefaultWeightedEdge> findAllEdge() {
return Collections.unmodifiableSet(graph.edgeSet());
}

protected void addNode(Station station) {
if (graph.containsVertex(station)) {
throw new IllegalArgumentException(ALREADY_EXISTS_NODE_MESSAGE);
}
graph.addVertex(station);
}

protected void addEdge(Section section) {
Station source = section.getSource();
Station sink = section.getSink();
this.validateSource(source);
this.validateSink(sink);
if (graph.containsEdge(source, sink)) {
throw new IllegalArgumentException(ALREADY_EXISTS_EDGE_MESSAGE);
}
graph.setEdgeWeight(graph.addEdge(source, sink), this.getWeight(section));
}

protected abstract double getWeight(Section section);

protected GraphPath<Station, DefaultWeightedEdge> compute(Station source, Station sink) {
this.validateSource(source);
this.validateSink(sink);
DijkstraShortestPath<Station, DefaultWeightedEdge> dijkstraShortestPath = new DijkstraShortestPath<>(graph);
return dijkstraShortestPath.getPath(source, sink);
}

protected void validateSource(Station source) {
if (!graph.containsVertex(source)) {
throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE);
}
}

protected void validateSink(Station sink) {
if (!graph.containsVertex(sink)) {
throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE);
}
}

protected void deleteAllNode() {
Set<Station> nodes = new HashSet<>(this.findAllNode());
graph.removeAllVertices(nodes);
}

protected void deleteAllEdge() {
graph.removeAllEdges(graph.edgeSet());
}

protected void deleteAll() {
this.deleteAllEdge();
this.deleteAllNode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package subway.application.section.service;

import org.jgrapht.graph.AbstractBaseGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.DirectedWeightedMultigraph;

import subway.domain.section.Section;
import subway.domain.station.Station;

class ShortDistanceService extends ShortCostService {
private static final AbstractBaseGraph<Station, DefaultWeightedEdge> graph = new DirectedWeightedMultigraph<>(
DefaultWeightedEdge.class);

public ShortDistanceService() {
super(graph);
}

@Override
protected double getWeight(Section section) {
return section.getDistance();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package subway.application.section.service;

import org.jgrapht.graph.AbstractBaseGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.DirectedWeightedMultigraph;

import subway.domain.section.Section;
import subway.domain.station.Station;

class ShortTimeService extends ShortCostService {
private static final AbstractBaseGraph<Station, DefaultWeightedEdge> graph = new DirectedWeightedMultigraph<>(
DefaultWeightedEdge.class);

public ShortTimeService() {
super(graph);
}

@Override
protected double getWeight(Section section) {
return section.getTime();
}
}
Loading