-
Notifications
You must be signed in to change notification settings - Fork 282
Final #115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Final #115
Changes from all commits
65bb889
ac926ef
2756ebd
78adbef
8841edc
4ef33b2
21f1db3
bf65abe
03cf1f1
47d466d
1931b3b
dbbdd7c
cbc0fba
ec9805a
b06a553
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # 지하철 노선도 경로 조회 | ||
|
|
||
| ## 기능 요구사항 | ||
|
|
||
| - 경로 조회 기능을 제공한다. | ||
| - 경로 조회 기준은 최단 거리 / 최소 시간 의 두 가지 기준을 사용한다. | ||
| - 경로 조회 기준을 선택한다. | ||
| - 잘못된 메뉴 입력시 예외 발생 | ||
| - 1, 2를 제외한 모든 입력에서 예외 발생 | ||
| - 출발열과 도착역을 입력하면 경로 조회 기준에 따라 조회 결과를 출력한다. | ||
| - [EXCEPTION] 출발 역과 도착 역이 같으면 예외 발생 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,76 @@ | ||
| package subway; | ||
|
|
||
| import java.util.Scanner; | ||
| import subway.controller.exception.RetryHandler; | ||
| import subway.domain.PathResult; | ||
| import subway.domain.Station; | ||
| import subway.domain.SubwayService; | ||
| import subway.domain.repository.RepositoryConfig; | ||
| import subway.domain.repository.StationRepository; | ||
| import subway.view.View; | ||
|
|
||
| public class Application { | ||
| private static final View view = new View(); | ||
| private static final RetryHandler handler = new RetryHandler(); | ||
| private static SubwayService subwayService; | ||
|
|
||
| public static void main(String[] args) { | ||
| final Scanner scanner = new Scanner(System.in); | ||
| // TODO: 프로그램 구현 | ||
| RepositoryConfig.initRepository(); | ||
| subwayService = new SubwayService(); | ||
|
|
||
| handler.runOrRetry(() -> run(scanner)); | ||
| } | ||
|
|
||
| public static void run(Scanner scanner){ | ||
| while(true) { | ||
| view.printMenuView(); | ||
| String input = scanner.nextLine(); | ||
| if (input.equals("Q")) { | ||
| return; | ||
| } | ||
| if (input.equals("1")) { | ||
| handler.runOrRetry(() -> findPath(scanner)); | ||
| continue; | ||
| } | ||
| throw new IllegalArgumentException("잘못된 메뉴 입력입니다."); | ||
| } | ||
| } | ||
|
|
||
| private static void findPath(Scanner scanner) { | ||
| view.printPathMenu(); | ||
| String input = scanner.nextLine(); | ||
| if (input.equals("B")) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여러 이점은 각
@june-777 님의 시간 단축을 위해 작성하셨을 수도 있을 것 같은데,
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 맞습니다,,, 리팩토링을 하고싶었지만 시간이 부족해 하지 못했던 부분이네요 ㅠ |
||
| return; | ||
| } | ||
| if (input.equals("1") || input.equals("2")) { | ||
| _findPath(scanner, input); | ||
| return; | ||
| } | ||
|
|
||
| //todo | ||
| throw new IllegalArgumentException("잘못된 메뉴 입력입니다."); | ||
| } | ||
|
|
||
| private static void _findPath(Scanner scanner, String input) { | ||
| view.guideStartStation(); | ||
| Station start = getStation(scanner); | ||
| view.guideEndStation(); | ||
| Station end = getStation(scanner); | ||
| PathResult result = null; | ||
| if(input.equals("1")){ | ||
| result = subwayService.findShortestPath(start, end); | ||
| } | ||
| if (input.equals("2")) { | ||
| result = subwayService.findFastestPath(start, end); | ||
| } | ||
| view.printPathResult(result); | ||
| } | ||
|
|
||
| private static Station getStation(Scanner scanner) { | ||
| String stationName = scanner.nextLine(); | ||
| return StationRepository.getStationByName(stationName); | ||
| } | ||
|
|
||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package subway.controller; | ||
|
|
||
| import subway.view.View; | ||
|
|
||
| public class SubwayController { | ||
| private final View view; | ||
|
|
||
| public SubwayController(View view) { | ||
| this.view = view; | ||
| } | ||
| //todo Button 사용 가능할지 고민해 보기 | ||
|
|
||
| /* | ||
| 경로 기준은 경로 탐색 전략을 결정해 준다. | ||
| 이후 시작, 끝 점을 사용해 경로를 탐색한다. | ||
|
|
||
|
|
||
| 1. 전략 선택 (최단 거리 / 최단 시간) | ||
| 2. 시작 / 끝 역 선택 | ||
| 3. 경로 구함 | ||
| 4. 결과 출력 | ||
| - 총 거리 | ||
| - 총 시간 | ||
| - 경로 내 모든 역 (이건 라이브러리의 반환 결과 사용하면 됨) | ||
|
|
||
| -> 총 거리, 총 시간은 라이브러리 반환 결과의 경로를 이용해 구하는 것이 맞는 것 같음 | ||
| -> A-B-C-D 경로일 경우 | ||
| 각 `Line`을 순회하면서 `A-B` 경로가 존재하는지 확인 후 거리와 시간을 가져온다. | ||
|
|
||
| 그럼 경로 정보는 `Line`이 가지고 있어야 하겠네 | ||
|
|
||
| StationRepository 는 그냥 입력받은 역들이 존재하는 역인지 판단하는 역할 이상은 못할 것 같음 | ||
|
|
||
| */ | ||
|
|
||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package subway.controller.exception; | ||
|
|
||
| import java.util.function.Supplier; | ||
| import subway.view.View; | ||
|
|
||
| public class RetryHandler { | ||
| private final View view = new View(); | ||
|
|
||
| public <T> T getOrRetry(Supplier<T> supplier){ | ||
| while(true){ | ||
| try { | ||
| return supplier.get(); | ||
| } catch (IllegalArgumentException e){ | ||
| view.printException(e.getMessage()); | ||
| } finally { | ||
| view.printLine(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public void runOrRetry(Runnable runnable){ | ||
| while(true){ | ||
| try { | ||
| runnable.run(); | ||
| return; | ||
| } catch (IllegalArgumentException e){ | ||
| view.printException(e.getMessage()); | ||
| } finally { | ||
| view.printLine(); | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| package subway.domain; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class PathResult { | ||
| private final List<Station> stations; | ||
| private final int time; | ||
| private final int distance; | ||
|
|
||
| public PathResult(List<Station> stations, int time, int distance) { | ||
| this.stations = stations; | ||
| this.time = time; | ||
| this.distance = distance; | ||
| } | ||
|
|
||
| public List<Station> getStations() { | ||
| return stations; | ||
| } | ||
|
|
||
| public int getTime() { | ||
| return time; | ||
| } | ||
|
|
||
| public int getDistance() { | ||
| return distance; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package subway.domain; | ||
|
|
||
| import org.jgrapht.GraphPath; | ||
| import org.jgrapht.graph.DefaultWeightedEdge; | ||
| import subway.domain.pathFinder.DistancePathFinder; | ||
| import subway.domain.pathFinder.StationPathFinder; | ||
| import subway.domain.pathFinder.TimePathFinder; | ||
| import subway.domain.repository.PathRepository; | ||
|
|
||
| public class SubwayService { | ||
| private static final StationPathFinder timePathFinder = new TimePathFinder(); | ||
| private static final StationPathFinder distanceFinder = new DistancePathFinder(); | ||
|
|
||
| public PathResult findShortestPath(Station start, Station end) { | ||
| GraphPath<Station, DefaultWeightedEdge> path = findPath(distanceFinder, start, end); | ||
| int time = PathRepository.getTotalTime(path.getVertexList()); | ||
| return new PathResult(path.getVertexList(), time, (int)path.getWeight()); | ||
| } | ||
|
|
||
| public PathResult findFastestPath(Station start, Station end) { | ||
| GraphPath<Station, DefaultWeightedEdge> path = findPath(timePathFinder, start, end); | ||
| int distance = PathRepository.getTotalDistance(path.getVertexList()); | ||
| return new PathResult(path.getVertexList(), (int) path.getWeight(), distance); | ||
| } | ||
| private GraphPath<Station, DefaultWeightedEdge> findPath(StationPathFinder pathFinder, Station start, Station end) { | ||
| if(start.equals(end)){ | ||
| throw new IllegalArgumentException("출발역과 도착역이 동일합니다."); | ||
| } | ||
| return pathFinder.findPath(start, end); | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| package subway.domain; | ||
|
|
||
| import java.util.Set; | ||
|
|
||
| public class UnitPath { | ||
| private final Station start; | ||
| private final Station end; | ||
|
|
||
| //todo 아래 두 값 래핑 | ||
| private final int time; | ||
| private final int distance; | ||
|
|
||
| public UnitPath(Station start, Station end, int time, int distance) { | ||
| this.start = start; | ||
| this.end = end; | ||
| this.time = time; | ||
| this.distance = distance; | ||
| } | ||
|
|
||
| public boolean isPathOf(Station start, Station end) { | ||
| if (this.start.equals(start) && this.end.equals(end)) { | ||
| return true; | ||
| } | ||
| if (this.start.equals(end) && this.end.equals(start)) { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| public Station getEnd() { | ||
| return end; | ||
| } | ||
|
|
||
| public Station getStart() { | ||
| return start; | ||
| } | ||
|
|
||
| public int getDistance() { | ||
| return distance; | ||
| } | ||
|
|
||
| public int getTime() { | ||
| return time; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package subway.domain.pathFinder; | ||
|
|
||
| import subway.domain.repository.LineRepository; | ||
| import subway.domain.UnitPath; | ||
|
|
||
| public class DistancePathFinder extends StationPathFinder{ | ||
| public DistancePathFinder() { | ||
| super(); | ||
| } | ||
|
|
||
| @Override | ||
| protected int getCost(UnitPath path) { | ||
| return path.getDistance(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
리터럴 및 입력을 비교할 때,
"Q".equals(input)과 같은 방식으로 코드를 작성하면 어떨까 합니다.Scanner에 의해 입력 받는 값이null이 될 수는 없기 때문에 해당 코드에서NPE가 발생하진 않겠으나,Scanner가 아닌 다른null이 될 가능성이 있는String타입의 변수를 리터럴과 비교 연산할 때,NPE를 막아줄 수 있겠습니다.이러한 규칙을 코딩 표준으로 만들어서 항상
literal.equals(variable)구조로 작성한다면, 일관적인 스타일로 코드를 작성하면서NPE을 방지할 수 있을 것 같습니다.