diff --git a/README.md b/README.md index 450e7753a..5e6901fdf 100644 --- a/README.md +++ b/README.md @@ -1,469 +1,55 @@ -# 지하철 노선도 미션 -- 지하철 역과 노선을 관리하는 지하철 노선도 기능을 구현한다. +## 기능 구현 목록 + +* 프로그램 시작 시 역, 노선 등 필요한 정보를 미리 셋팅할 수 있다. (초기 설정 like 기본값) + 1. 지하철 역으로 교대역, 강남역, 역삼역, 남부터미널역, 양재역, 양재시민의숲역, 매봉역이 등록되어 있다. + 2. 지하철 노선으로 2호선, 3호선, 신분당선이 등록되어 있다. + 3. 기본 노선에는 역이 아래와 같이 등록되어 있다. (왼쪽 끝이 상행 종점) + * 2호선 : 교대역 - 강남역 - 역삼역 + * 3호선 : 교대역 - 남부터미널역 - 양재역 - 매봉역 + * 신분당선 : 강남역 - 양재역 - 양재시민의숲역 + + +* 역 관련 기능 + 1. 지하철 역을 등록하고 삭제하는 기능 (단, 노선에 등록된 역은 삭제할 수 없다) + 2. 지하철 역의 목록을 조회할 수 있다. + + +* 역 관련 예외 + 1. 중복된 지하철 역 이름은 등록할 수 없음 + 2. 지하철 역 이름은 2글자 이상이어야 한다. + 3. 지하철 역을 삭제할 때 등록되지 않은 역에대한 삭제는 예외를 발생시킨다. + + +* 노선 관련 기능 + 1. 지하철 노선을 등록하고 삭제할 수 있다. + 2. 노선 등록 시 상행 종점역과 하행 종점역을 입력 받는다. + 3. 지하철 노선의 목록을 조회할 수 있다. + + +* 노선 관련 예외 + 1. 중복된 지하철 노선 이름이 등록될 수 없다. + 2. 지하철 노선 이름은 2글자 이상이어야 한다. + 3. 노선을 삭제할 때 등록되지 않은 노선에 대한 삭제는 예외를 발생시킨다. + 4. 더이상 노선이 없다면 삭제 기능이나 조회기능에 진입했을 때 메시지로 알려준다.(모든 노선을 삭제했을 때) + 5. 상행 종점역과 하행 종점역을 입력받을때 입력한 역이 StationRepository에 등록되어 있지 않다면 예외를 발생시킨다. + + +* 구간 추가 기능 (역과 역 사이를 구간, 구간들의 모음 = 노선) + + 순서는 1부터 시작 + 1. 지하철 노선에 구간을 추가하는 기능 ( 노선에 역을 추가하는 것) + 2. 하나의 역은 여러개의 노선에 추가가 가능 + 3. 역과 역 사이에 새로운 역을 추가하는 기능 + 4. 갈래길을 생성할 수 없음(예외사항) + 5. 노선에 이미 있는 역이라면 추가가 불가능(예외사항) + 6. 구간에 추가하는 역이 등록돼있는 역인지(StationRepository에 있는 역인지) 검사하는 기능(예외사항) + +* 구간 삭제 기능 + 1. 노선에 등록된 역을 제거하는 기능 + 2. 종점을 제거할 경우 다음 역이 종점이됨 + 3. 노선에 포함된 역이 2개 이하일때는 역을 제거할 수 없습니다. (예외사항) + 4. 노선에 존재하지 않는 역이라면 제거할 수 없습니다. (예외사항) + + +* 노선에 등록된 역 리스트 조회기능 + 1. 노선의 상행 종점부터 하행 종점까지 연결된 순서대로 역 목록을 조회하는 기능 -
- -## 🚀 기능 요구사항 - -### 초기 설정 -- 프로그램 시작 시 역, 노선 등 필요한 정보를 미리 셋팅할 수 있다. - -> 아래의 사전 등록 정보로 반드시 초기 설정을 하기 -> -``` - 1. 지하철역으로 교대역, 강남역, 역삼역, 남부터미널역, 양재역, 양재시민의숲역, 매봉역이 등록되어 있다. - 2. 지하철 노선으로 2호선, 3호선, 신분당선이 등록되어 있다. - 3. 노선에 역이 아래와 같이 등록되어 있다.(왼쪽 끝이 상행 종점) - - 2호선: 교대역 - 강남역 - 역삼역 - - 3호선: 교대역 - 남부터미널역 - 양재역 - 매봉역 - - 신분당선: 강남역 - 양재역 - 양재시민의숲역 - ``` - - - -### 지하철 역 관련 기능 -- 지하철 역을 등록하고 삭제할 수 있다. (단, 노선에 등록된 역은 삭제할 수 없다) -- 중복된 지하철 역 이름이 등록될 수 없다. -- 지하철 역 이름은 2글자 이상이어야 한다. -- 지하철 역의 목록을 조회할 수 있다. - -### 지하철 노선 관련 기능 -- 지하철 노선을 등록하고 삭제할 수 있다. -- 중복된 지하철 노선 이름이 등록될 수 없다. -- 지하철 노선 이름은 2글자 이상이어야 한다. -- 노선 등록 시 상행 종점역과 하행 종점역을 입력받는다. -- 지하철 노선의 목록을 조회할 수 있다. - -### 지하철 구간 추가 기능 -- 지하철 노선에 구간을 추가하는 기능은 노선에 역을 추가하는 기능이라고도 할 수 있다. - - 역과 역사이를 구간이라 하고 이 구간들의 모음이 노선이다. -- 하나의 역은 여러개의 노선에 추가될 수 있다. -- 역과 역 사이에 새로운 역이 추가 될 수 있다. -- 노선에서 갈래길은 생길 수 없다. - - - -### 지하철 구간 삭제 기능 -- 노선에 등록된 역을 제거할 수 있다. -- 종점을 제거할 경우 다음 역이 종점이 된다. -- 노선에 포함된 역이 두개 이하일 때는 역을 제거할 수 없다. - - - -### 지하철 노선에 등록된 역 조회 기능 -- 노선의 상행 종점부터 하행 종점까지 연결된 순서대로 역 목록을 조회할 수 있다. - -
- -## ✍🏻 입출력 요구사항 -- `프로그래밍 실행 결과 예시`를 참고하여 입출력을 구현한다. -- 기대하는 출력 결과는 `[INFO]`를 붙여서 출력한다. 출력값의 형식은 예시와 동일하게 한다. -- 에러 발생 시 `[ERROR]`를 붙여서 출력한다. (에러의 문구는 자유롭게 작성한다.) - -### 💻 프로그래밍 실행 결과 -#### 역 관리 -``` -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -1 - -## 역 관리 화면 -1. 역 등록 -2. 역 삭제 -3. 역 조회 -B. 돌아가기 - -## 원하는 기능을 선택하세요. -1 - -## 등록할 역 이름을 입력하세요. -잠실역 - -[INFO] 지하철 역이 등록되었습니다. - -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -1 - -## 역 관리 화면 -1. 역 등록 -2. 역 삭제 -3. 역 조회 -B. 돌아가기 - -## 원하는 기능을 선택하세요. -3 - -## 역 목록 -[INFO] 교대역 -[INFO] 강남역 -[INFO] 역삼역 -[INFO] 남부터미널역 -[INFO] 양재역 -[INFO] 양재시민의숲역 -[INFO] 매봉역 -[INFO] 잠실역 - -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -1 - -## 역 관리 화면 -1. 역 등록 -2. 역 삭제 -3. 역 조회 -B. 돌아가기 - -## 원하는 기능을 선택하세요. -2 - -## 삭제할 역 이름을 입력하세요. -잠실역 - -[INFO] 지하철 역이 삭제되었습니다. - -... -``` - -### 노선 관리 - -``` - -... - -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -2 - -## 노선 관리 화면 -1. 노선 등록 -2. 노선 삭제 -3. 노선 조회 -B. 돌아가기 - -## 원하는 기능을 선택하세요. -1 - -## 등록할 노선 이름을 입력하세요. -1호선 - -## 등록할 노선의 상행 종점역 이름을 입력하세요. -강남역 - -## 등록할 노선의 하행 종점역 이름을 입력하세요. -잠실역 - -[INFO] 지하철 노선이 등록되었습니다. - -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -2 - -## 노선 관리 화면 -1. 노선 등록 -2. 노선 삭제 -3. 노선 조회 -B. 돌아가기 - -## 원하는 기능을 선택하세요. -3 - -## 노선 목록 -[INFO] 2호선 -[INFO] 3호선 -[INFO] 신분당선 -[INFO] 1호선 - -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -2 - -## 노선 관리 화면 -1. 노선 등록 -2. 노선 삭제 -3. 노선 조회 -B. 돌아가기 - -## 원하는 기능을 선택하세요. -2 - -## 삭제할 노선 이름을 입력하세요. -1호선 - -[INFO] 지하철 노선이 삭제되었습니다. - -... - -``` - -### 구간 관리 -- 순서는 1부터 시작한다. - -``` -... - -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -3 - -## 구간 관리 화면 -1. 구간 등록 -2. 구간 삭제 -B. 돌아가기 - -## 원하는 기능을 선택하세요. -1 - -## 노선을 입력하세요. -2호선 - -## 역이름을 입력하세요. -잠실역 - -## 순서를 입력하세요. -2 - -[INFO] 구간이 등록되었습니다. - -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -3 - -## 구간 관리 화면 -1. 구간 등록 -2. 구간 삭제 -B. 돌아가기 - -## 원하는 기능을 선택하세요. -2 - -## 삭제할 구간의 노선을 입력하세요. -2호선 - -## 삭제할 구간의 역을 입력하세요. -잠실역 - -[INFO] 구간이 삭제되었습니다. - -... - -``` - -### 지하철 노선도 출력 - -``` -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -4 - -## 지하철 노선도 -[INFO] 2호선 -[INFO] --- -[INFO] 교대역 -[INFO] 강남역 -[INFO] 역삼역 - -[INFO] 3호선 -[INFO] --- -[INFO] 교대역 -[INFO] 남부터미널역 -[INFO] 양재역 -[INFO] 매봉역 - -[INFO] 신분당선 -[INFO] --- -[INFO] 강남역 -[INFO] 양재역 -[INFO] 양재시민의숲역 - -``` - -#### 에러 출력 예시 - -``` -## 메인 화면 -1. 역 관리 -2. 노선 관리 -3. 구간 관리 -4. 지하철 노선도 출력 -Q. 종료 - -## 원하는 기능을 선택하세요. -5 - -[ERROR] 선택할 수 없는 기능입니다. - -## 원하는 기능을 선택하세요. -1 - -## 역 관리 화면 -1. 역 등록 -2. 역 삭제 -3. 역 조회 -B. 돌아가기 - -## 원하는 기능을 선택하세요. -1 - -## 등록할 역 이름을 입력하세요. -강남역 - -[ERROR] 이미 등록된 역 이름입니다. - -## 역 관리 화면 -1. 역 등록 -2. 역 삭제 -3. 역 조회 -B. 돌아가기 - -## 원하는 기능을 선택하세요. - -... - -``` - -
- -## 🎱 프로그래밍 요구사항 -- 자바 코드 컨벤션을 지키면서 프로그래밍한다. - - 기본적으로 [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html)을 원칙으로 한다. - - 단, 들여쓰기는 '2 spaces'가 아닌 '4 spaces'로 한다. -- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다. - - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. - - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다. -- 3항 연산자를 쓰지 않는다. -- 함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다. - - 함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다. -- else 예약어를 쓰지 않는다. - - 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다. - - else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. -- 프로그래밍 요구사항에서 별도로 변경 불가 안내가 없는 경우 파일 수정과 패키지 이동을 자유롭게 할 수 있다. -- 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 `[ERROR]` 로 시작해야 한다. - -### 프로그래밍 요구사항 - Application -- Application 클래스를 활용해 구현해야 한다. -- Application의 패키지 구조는 변경하지 않는다. -```java -public class Application { - public static void main(String[] args) { - ... - } -} -``` - -### 프로그래밍 요구사항 - Station, Line -- Station, Line 클래스를 활용하여 지하철역과 노선을 구현해야 한다. -- 제공하는 각 클래스의 기본 생성자를 추가할 수 없다. -- 필드(인스턴스 변수)인 name의 접근 제어자 private을 변경할 수 없다. -- 가능하면 setter 메소드(ex. setXXX)를 추가하지 않고 구현한다. - -```java -public class Station { - private String name; - - public Station(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - // 추가 기능 구현 -} - -``` - -### 프로그래밍 요구사항 - StationRepository, LineRepository -- Station과 Line의 상태를 저장할 수 있는 StationRepository, LineRepository를 제공한다. -- 필요 시 StationRepository, LineRepository 이 외 추가로 Repository를 만들 수 있다. -- 추가로 생성되는 객체에 대해서 XXXRepository 네이밍으로 저장 클래스를 추가할 수 있다. -- 객체들의 상태를 관리하기 위해서 XXXRepository 클래스를 활용해 저장 로직을 구현해야 한다. -- 필요에 따라 자유롭게 수정이 가능하다. - -```java -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)); - } -} -``` - -
- -## 📈 진행 요구사항 -- 미션은 [java-subway-map-precourse 저장소](https://github.com/woowacourse/java-subway-map-precourse) 를 fork/clone해 시작한다. -- 기능을 구현하기 전에 java-subway-map-precourse/docs/README.md 파일에 구현할 기능 목록을 정리해 추가한다. -- git의 commit 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가한다. - - [AngularJS Commit Message Conventions](https://gist.github.com/stephenparish/9941e89d80e2bc58a153) 참고해 commit log를 남긴다. -- [프리코스 과제 제출 문서](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 절차를 따라 미션을 제출한다. - - [프리코스 과제 FAQ](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse/faq) 문서를 참고하여 진행할 수 있다. -
- -## 📝 License - -This project is [MIT](https://github.com/woowacourse/java-subway-map-precourse/blob/master/LICENSE.md) licensed. diff --git a/src/main/java/subway/Application.java b/src/main/java/subway/Application.java index 0bcf786cc..417d3abde 100644 --- a/src/main/java/subway/Application.java +++ b/src/main/java/subway/Application.java @@ -1,10 +1,13 @@ package subway; +import subway.menu.MainMenu; + import java.util.Scanner; public class Application { public static void main(String[] args) { final Scanner scanner = new Scanner(System.in); // TODO: 프로그램 구현 + new MainMenu(scanner).start(); } } diff --git a/src/main/java/subway/domain/Line.java b/src/main/java/subway/domain/Line.java index f4d738d5a..a3ba219b3 100644 --- a/src/main/java/subway/domain/Line.java +++ b/src/main/java/subway/domain/Line.java @@ -1,5 +1,10 @@ package subway.domain; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + public class Line { private String name; @@ -12,4 +17,51 @@ public String getName() { } // 추가 기능 구현 + + private List stationList = new LinkedList<>(); + + public Line(String name, String upLineLastStop, String downLineLastStop) { + this.name = name; + addStation(upLineLastStop); + addStation(downLineLastStop); + } + + public int size() { + return stationList.size(); + } + + public void addStation(String stationName) { + Station station = StationRepository.findStationByName(stationName); + stationList.add(station); + station.increaseCount(); + } + + public void addStation(String index, String stationName) { + Station station = StationRepository.findStationByName(stationName); + stationList.add(Integer.parseInt(index)-1, station); + station.increaseCount(); + } + + //TODO 삭제 여부를 알아보는 메서드와 삭제를 진행하는 메서드로 나눠야함 + // 구간 삭제 + public boolean removeStation(String stationName) { + return stationList.removeIf(station -> station.getName().equals(stationName)); + } + + public void beforeRemove() { + for (Station station : stationList()) { + station.decreaseCount(); + } + } + + public void deleteLine() { + beforeRemove(); + LineRepository.deleteLineByName(this.name); + } + + public List stationList() { + return Collections.unmodifiableList(stationList); + } + + } diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/LineRepository.java index 49132ddb6..c3f66e140 100644 --- a/src/main/java/subway/domain/LineRepository.java +++ b/src/main/java/subway/domain/LineRepository.java @@ -19,4 +19,13 @@ public static void addLine(Line line) { public static boolean deleteLineByName(String name) { return lines.removeIf(line -> Objects.equals(line.getName(), name)); } + + public static Line findLineByName(String lineName) { + for (Line line : lines) { + if (line.getName().equals(lineName)) { + return line; + } + } + return null; + } } diff --git a/src/main/java/subway/domain/Station.java b/src/main/java/subway/domain/Station.java index bdb142590..afa4fc649 100644 --- a/src/main/java/subway/domain/Station.java +++ b/src/main/java/subway/domain/Station.java @@ -12,4 +12,32 @@ public String getName() { } // 추가 기능 구현 + + private int count = 0; + + public void increaseCount() { + this.count++; + } + + public void decreaseCount() { + this.count--; + } + + public int getCount() { + return this.count; + } + + public boolean isRemovable() { + if (this.count == 0) { + return true; + } + return false; + } + + public boolean delete() { + if (isRemovable()) { + return StationRepository.deleteStation(this.name); + } + return false; + } } diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/StationRepository.java index b7245c0f3..710670b0c 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/StationRepository.java @@ -1,9 +1,6 @@ package subway.domain; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; public class StationRepository { private static final List stations = new ArrayList<>(); @@ -19,4 +16,14 @@ public static void addStation(Station station) { public static boolean deleteStation(String name) { return stations.removeIf(station -> Objects.equals(station.getName(), name)); } + + public static Station findStationByName(String name) { + for (Station station : stations()) { + if (station.getName().equals(name)) { + return station; + } + } + return null; + } + } diff --git a/src/main/java/subway/menu/LineMenu.java b/src/main/java/subway/menu/LineMenu.java new file mode 100644 index 000000000..86c81553b --- /dev/null +++ b/src/main/java/subway/menu/LineMenu.java @@ -0,0 +1,114 @@ +package subway.menu; + +import subway.domain.Line; +import subway.service.LineService; +import subway.util.LineValidator; +import subway.util.StationValidator; + +import java.util.List; +import java.util.Scanner; + +public class LineMenu { + private static final String MENU_TITLE = "## 노선 관리 화면"; + private static final String MENU1 = "1. 노선 등록"; + private static final String MENU2 = "2. 노선 삭제"; + private static final String MENU3 = "3. 노선 조회"; + private static final String BACK = "B. 돌아가기"; + private static final String CHOICE_MESSAGE = "## 원하는 기능을 선택하세요."; + + private Scanner scanner; + + public LineMenu(Scanner scanner) { + this.scanner = scanner; + } + + public void startLineMenu() { + selectLineMenu(); + } + + public void selectLineMenu() { + while (true) { + printLineMenu(); + String input = scanner.nextLine(); + lineMenu(input); + if (input.equals("B")) { + break; + } + System.out.println(); + } + } + + private void lineMenu(String input) { + if (input.equals("1")) { + addLineMenu(); + } + if (input.equals("2")) { + deleteLineMenu(); + } + if (input.equals("3")) { + printLineList(); + } + } + + private void addLineMenu() { + System.out.println("\n## 등록할 노선 이름을 입력하세요."); + String lineName = scanner.nextLine(); + addLineName(lineName); + } + + private void addLineName(String lineName) { + if (LineValidator.checkValidLineName(lineName)) { + addUpLineLastStop(lineName); + } + } + + private void addUpLineLastStop(String lineName) { + System.out.println("\n## 등록할 상행 종점역 이름을 입력하세요."); + String upLineLastStop = scanner.nextLine(); + if (StationValidator.haveStationName(upLineLastStop)) { + addDownLineLastStop(lineName, upLineLastStop); + } + } + + private void addDownLineLastStop(String lineName, String upLineLastStop) { + System.out.println("\n## 등록할 하행 종점역 이름을 입력하세요."); + String downLineLastStop = scanner.nextLine(); + if (LineValidator.checkValidDownLastStop(upLineLastStop, downLineLastStop)) { + LineService.addLine(lineName, upLineLastStop, downLineLastStop); + System.out.println("\n[ INFO ] 지하철 노선이 등록되었습니다."); + } + } + + private void deleteLineMenu(){ + System.out.println("## 삭제할 노선 이름을 입력하세요."); + String lineName = scanner.nextLine(); + if (LineValidator.haveLineName(lineName)) { + LineService.deleteLine(lineName); + System.out.println("[ INFO ] 지하철 노선이 삭제되었습니다."); + } + } + + private void printLineList() { + System.out.println("## 노선 목록"); + List lines = LineService.getLineList(); + if (lines.size() == 0) { + System.out.println("존재하는 노선이 없습니다."); + return; + } + for (Line line : lines) { + System.out.println("[ INFO ] " + line.getName()); + } + } + + //TODO 출력 기능을 다른곳에 모으기 + public void printLineMenu() { + StringBuilder sb = new StringBuilder(); + sb.append(MENU_TITLE).append("\n") + .append(MENU1).append("\n") + .append(MENU2).append("\n") + .append(MENU3).append("\n") + .append(BACK).append("\n\n") + .append(CHOICE_MESSAGE); + System.out.println(sb); + } +} diff --git a/src/main/java/subway/menu/MainMenu.java b/src/main/java/subway/menu/MainMenu.java new file mode 100644 index 000000000..8d6f440d0 --- /dev/null +++ b/src/main/java/subway/menu/MainMenu.java @@ -0,0 +1,67 @@ +package subway.menu; + +import subway.util.DefaultSetting; + +import java.util.Scanner; + +public class MainMenu { + + private static final String MAIN_TITLE = "## 메인 화면"; + private static final String MENU1 = "1. 역 관리"; + private static final String MENU2 = "2. 노선 관리"; + private static final String MENU3 = "3. 구간 관리"; + private static final String MENU4 = "4. 지하철 노선도 출력"; + private static final String QUIT = "Q. 종료"; + private static final String CHOICE_MESSAGE = "## 원하는 기능을 선택하세요."; + + private Scanner scanner; + + public MainMenu(Scanner scanner) { + this.scanner = scanner; + } + + //TODO 메뉴번호 이외의 입력을 받았을 때 예외사항 출력 구현해야함 + public void start() { + new DefaultSetting().defaultSetting(); + selectMainMenu(); + } + + private void selectMainMenu() { + while (true) { + printMainMenu(); + String input = scanner.nextLine(); + System.out.println(); + mainMenu(input); + if (input.equals("Q")) { + break; + } + } + } + + private void mainMenu(String input) { + if (input.equals("1")) { + new StationMenu(scanner).startStationMenu(); + } + if (input.equals("2")) { + new LineMenu(scanner).startLineMenu(); + } + if (input.equals("3")) { + new SectionMenu(scanner).startSectionMenu(); + } + if (input.equals("4")) { + new SubwayMapMenu().printSubwayMap(); + } + } + + private void printMainMenu() { + StringBuilder sb = new StringBuilder(); + sb.append(MAIN_TITLE).append("\n") + .append(MENU1).append("\n") + .append(MENU2).append("\n") + .append(MENU3).append("\n") + .append(MENU4).append("\n") + .append(QUIT).append("\n\n") + .append(CHOICE_MESSAGE); + System.out.println(sb); + } +} diff --git a/src/main/java/subway/menu/SectionMenu.java b/src/main/java/subway/menu/SectionMenu.java new file mode 100644 index 000000000..5149adf0b --- /dev/null +++ b/src/main/java/subway/menu/SectionMenu.java @@ -0,0 +1,101 @@ +package subway.menu; + +import subway.domain.Line; +import subway.domain.LineRepository; +import subway.service.SectionService; +import subway.util.LineValidator; +import subway.util.SectionValidator; +import subway.util.StationValidator; + +import java.util.Objects; +import java.util.Scanner; + +public class SectionMenu { + private static final String MENU_TITLE = "## 구간 관리 화면"; + private static final String MENU1 = "1. 구간 등록"; + private static final String MENU2 = "2. 구간 삭제"; + private static final String BACK = "B. 돌아가기"; + private static final String CHOICE_MESSAGE = "## 원하는 기능을 선택하세요."; + + private Scanner scanner; + + public SectionMenu(Scanner scanner) { + this.scanner = scanner; + } + + public void startSectionMenu() { + selectSectionMenu(); + } + + private void selectSectionMenu() { + while (true) { + printSectionMenu(); + String input = scanner.nextLine(); + if (input.equals("1")) { + addSectionMenu(); + } + if (input.equals("2")) { + deleteSectionMenu(); + } + if (input.equals("B")) { + break; + } + } + } + + private void addSectionMenu() { + addLine(); + } + + private void addLine() { + System.out.println("\n## 노선을 입력하세요."); + String lineName = scanner.nextLine(); + if (LineValidator.haveLineName(lineName)) { + addStation(lineName); + } + } + + private void addStation(String lineName) { + System.out.println("\n## 역 이름을 입력하세요."); + String stationName = scanner.nextLine(); + if (StationValidator.haveStationName(stationName)) { + addIndex(lineName, stationName); + } + } + + private void addIndex(String lineName, String stationName) { + System.out.println("\n## 순서를 입력하세요."); + String index = scanner.nextLine(); + if (SectionValidator.checkValidIndex(index, lineName)) { + SectionService.addSection(lineName, index, stationName); + System.out.println("\n[ INFO ] 구간이 등록되었습니다."); + } + } + + private void deleteSectionMenu() { + System.out.println("\n## 삭제할 구간의 노선을 입력하세요."); + String lineName = scanner.nextLine(); + if (LineValidator.haveLineName(lineName)) { + inputDeleteStation(lineName); + } + } + + private void inputDeleteStation(String lineName) { + System.out.println("\n## 삭제할 구간의 역을 입력하세요."); + String stationName = scanner.nextLine(); + if (SectionValidator.checkRemovableSection(lineName, stationName)) { + SectionService.removeSection(stationName, lineName); + System.out.println("\n[ INFO ] 구간이 삭제되었습니다."); + } + } + + private void printSectionMenu() { + StringBuilder sb = new StringBuilder(); + sb.append(MENU_TITLE).append("\n") + .append(MENU1).append("\n") + .append(MENU2).append("\n") + .append(BACK).append("\n\n") + .append(CHOICE_MESSAGE); + System.out.println(sb); + } +} diff --git a/src/main/java/subway/menu/StationMenu.java b/src/main/java/subway/menu/StationMenu.java new file mode 100644 index 000000000..f11093010 --- /dev/null +++ b/src/main/java/subway/menu/StationMenu.java @@ -0,0 +1,93 @@ +package subway.menu; + +import subway.domain.Station; +import subway.service.StationService; +import subway.util.StationValidator; + +import java.util.List; +import java.util.Scanner; + +public class StationMenu { + private static final String MENU_TITLE = "## 역 관리 화면"; + private static final String MENU1 = "1. 역 등록"; + private static final String MENU2 = "2. 역 삭제"; + private static final String MENU3 = "3. 역 조회"; + private static final String BACK = "B. 돌아가기"; + private static final String CHOICE_MESSAGE = "## 원하는 기능을 선택하세요."; + + private Scanner scanner; + + public StationMenu(Scanner scanner) { + this.scanner = scanner; + } + + public void startStationMenu() { + selectStationMenu(); + } + + private void selectStationMenu() { + while (true) { + printStationMenu(); + String input = this.scanner.nextLine(); + System.out.println(); + if (input.equals("1")) { + addStationMenu(); + } + if (input.equals("2")) { + deleteStationMenu(); + } + if (input.equals("3")) { + printStationList(); + } + if (input.equals("B")) { + break; + } + } + } + + private void addStationMenu() { + System.out.println("## 등록할 역 이름을 입력하세요."); + String stationName = scanner.nextLine(); + System.out.println(); + if (StationValidator.checkValidStationName(stationName)) { + StationService.addStation(stationName); + System.out.println("[ INFO ] 지하철 역이 등록되었습니다.\n"); + } + } + + //TODO 역이 노선이 등록된 역인지 확인하고 이미 노선에 등록된 역이라면 삭제할 수 없도록 구현해야함 + private void deleteStationMenu() { + System.out.println("## 삭제할 역 이름을 입력하세요."); + String stationName = scanner.nextLine(); + System.out.println(); + if (StationValidator.checkRemovableStation(stationName)) { + StationService.deleteStation(stationName); + System.out.println("[ INFO ] 지하철 역이 삭제되었습니다.\n"); + } + } + + private void printStationList() { + System.out.println("## 역 목록"); + List stations = StationService.getStationList(); + if (stations.size() == 0) { + System.out.println("[ INFO ] 존재하는 역이 없습니다."); + return; + } + for (Station station : stations) { + System.out.println("[ INFO ] " + station.getName()); + } + System.out.println(); + } + + //TODO 출력 기능을 다른곳에 모으기 + private void printStationMenu() { + StringBuilder sb = new StringBuilder(); + sb.append(MENU_TITLE).append("\n") + .append(MENU1).append("\n") + .append(MENU2).append("\n") + .append(MENU3).append("\n") + .append(BACK).append("\n\n") + .append(CHOICE_MESSAGE); + System.out.println(sb); + } +} diff --git a/src/main/java/subway/menu/SubwayMapMenu.java b/src/main/java/subway/menu/SubwayMapMenu.java new file mode 100644 index 000000000..a97dd385c --- /dev/null +++ b/src/main/java/subway/menu/SubwayMapMenu.java @@ -0,0 +1,28 @@ +package subway.menu; + +import subway.domain.Line; +import subway.domain.LineRepository; +import subway.domain.Station; + +public class SubwayMapMenu { + + public void printSubwayMap() { + System.out.println("## 지하철 노선도"); + printLines(); + System.out.println(); + } + + private void printLines() { + for (Line line : LineRepository.lines()) { + System.out.println("\n[ INFO ] " + line.getName()); + System.out.println("[ INFO ] ---"); + printStations(line); + } + } + + private void printStations(Line line) { + for (Station station : line.stationList()) { + System.out.println("[ INFO ] " + station.getName()); + } + } +} diff --git a/src/main/java/subway/service/LineService.java b/src/main/java/subway/service/LineService.java new file mode 100644 index 000000000..0c7c3e699 --- /dev/null +++ b/src/main/java/subway/service/LineService.java @@ -0,0 +1,22 @@ +package subway.service; + +import subway.domain.Line; +import subway.domain.LineRepository; + +import java.util.List; + +public class LineService { + + public static void addLine(String lineName, String upLineLastStop, String downLineLastStop){ + LineRepository.addLine(new Line(lineName, upLineLastStop, downLineLastStop)); + } + + public static void deleteLine(String lineName) { + Line line = LineRepository.findLineByName(lineName); + line.deleteLine(); + } + + public static List getLineList() { + return LineRepository.lines(); + } +} diff --git a/src/main/java/subway/service/SectionService.java b/src/main/java/subway/service/SectionService.java new file mode 100644 index 000000000..60e967a3e --- /dev/null +++ b/src/main/java/subway/service/SectionService.java @@ -0,0 +1,17 @@ +package subway.service; + +import subway.domain.Line; +import subway.domain.LineRepository; + +public class SectionService { + + public static void addSection(String lineName, String index, String stationName) { + LineRepository.findLineByName(lineName).addStation(index, stationName); + } + + public static void removeSection(String stationName, String lineName) { + Line line = LineRepository.findLineByName(lineName); + line.removeStation(stationName); + } + +} diff --git a/src/main/java/subway/service/StationService.java b/src/main/java/subway/service/StationService.java new file mode 100644 index 000000000..926b5c98c --- /dev/null +++ b/src/main/java/subway/service/StationService.java @@ -0,0 +1,22 @@ +package subway.service; + +import subway.domain.Station; +import subway.domain.StationRepository; + +import java.util.List; + +public class StationService { + + public static void addStation(String stationName) { + StationRepository.addStation(new Station(stationName)); + } + + public static boolean deleteStation(String stationName) { + Station station = StationRepository.findStationByName(stationName); + return station.delete(); + } + + public static List getStationList() { + return StationRepository.stations(); + } +} diff --git a/src/main/java/subway/util/DefaultSetting.java b/src/main/java/subway/util/DefaultSetting.java new file mode 100644 index 000000000..58f1cf21c --- /dev/null +++ b/src/main/java/subway/util/DefaultSetting.java @@ -0,0 +1,49 @@ +package subway.util; + +import subway.domain.Line; +import subway.domain.LineRepository; +import subway.domain.Station; +import subway.domain.StationRepository; + +public class DefaultSetting { + private static final String KYODAE = "교대역"; + private static final String GANGNAM = "강남역"; + private static final String YEOKSAM = "역삼역"; + private static final String NORTH_TERMINAL = "남부터미널역"; + private static final String YANGJAE = "양재역"; + private static final String YANGJAE_CITIZEN_FOREST = "양재시민의숲역"; + private static final String MAEBONG = "매봉역"; + private static final String LINE2 = "2호선"; + private static final String LINE3 = "3호선"; + private static final String SINBUNDANG_LINE = "신분당선"; + + public void defaultSetting() { + StationRepository.addStation(new Station(KYODAE)); + StationRepository.addStation(new Station(GANGNAM)); + StationRepository.addStation(new Station(YEOKSAM)); + StationRepository.addStation(new Station(NORTH_TERMINAL)); + StationRepository.addStation(new Station(YANGJAE)); + StationRepository.addStation(new Station(YANGJAE_CITIZEN_FOREST)); + StationRepository.addStation(new Station(MAEBONG)); + + LineRepository.addLine(new Line(LINE2)); + LineRepository.addLine(new Line(LINE3)); + LineRepository.addLine(new Line(SINBUNDANG_LINE)); + + Line line2 = LineRepository.findLineByName(LINE2); + line2.addStation(KYODAE); + line2.addStation(GANGNAM); + line2.addStation(YEOKSAM); + + Line line3 = LineRepository.findLineByName(LINE3); + line3.addStation(KYODAE); + line3.addStation(NORTH_TERMINAL); + line3.addStation(YANGJAE); + line3.addStation(MAEBONG); + + Line dxLine = LineRepository.findLineByName(SINBUNDANG_LINE); + dxLine.addStation(GANGNAM); + dxLine.addStation(YANGJAE); + dxLine.addStation(YANGJAE_CITIZEN_FOREST); + } +} diff --git a/src/main/java/subway/util/LineValidator.java b/src/main/java/subway/util/LineValidator.java new file mode 100644 index 000000000..48a374852 --- /dev/null +++ b/src/main/java/subway/util/LineValidator.java @@ -0,0 +1,57 @@ +package subway.util; + +import subway.domain.Line; +import subway.domain.LineRepository; +import subway.domain.Station; + +public class LineValidator { + + private static final int SIZE = 2; + + public static boolean checkValidLineName(String name) { + return !checkDuplicateName(name) && checkValidName(name); + } + + public static boolean checkDuplicateName(String name) { + for (Line line : LineRepository.lines()) { + if (line.getName().equals(name)) { + System.out.println("[ ERROR ] 이미 존재하는 노선입니다.\n"); + return true; + } + } + return false; + } + + public static boolean checkValidName(String name) { + if (name.length() >= SIZE) { + return true; + } + System.out.println("[ ERROR ] 노선 이름은 2글자 이상이어야 합니다.\n"); + return false; + } + + public static boolean haveLineName(String name) { + for (Line line : LineRepository.lines()) { + if (line.getName().equals(name)) { + return true; + } + } + System.out.println("[ ERROR ] 등록 되지않은 노선입니다.\n"); + return false; + } + + public static boolean checkValidDownLastStop(String upName, String downName) { + if (StationValidator.haveStationName(downName) && !isSameStation(upName, downName)) { + return true; + } + return false; + } + + public static boolean isSameStation(String upName, String downName) { + if (upName.equals(downName)) { + System.out.println("[ ERROR ] 상행선종점과 하행선종점은 각각 다른 지하철 역이어야 합니다."); + return true; + } + return false; + } +} diff --git a/src/main/java/subway/util/SectionValidator.java b/src/main/java/subway/util/SectionValidator.java new file mode 100644 index 000000000..a4e63488e --- /dev/null +++ b/src/main/java/subway/util/SectionValidator.java @@ -0,0 +1,57 @@ +package subway.util; + +import subway.domain.Line; +import subway.domain.LineRepository; +import subway.domain.Station; + +import java.util.List; + +public class SectionValidator { + private static final int SIZE = 2; + + public static boolean checkValidStation(String name, List stationList) { + for (Station station : stationList) { + if (station.getName().equals(name)) { + return false; + } + } + return true; + } + + public static boolean checkValidIndex(String index, String lineName) { + int lineSize = LineRepository.findLineByName(lineName).size(); + if (Integer.parseInt(index) > 0 && Integer.parseInt(index) <= lineSize) { + return true; + } + System.out.println("[ ERROR ] 유효하지 않은 순서입니다.(현재 노선의 최대 크기 : " + lineSize + ")"); + return false; + } + + public static boolean checkRemovableSection(String lineName, String stationName) { + if (haveSection(lineName, stationName) && checkValidDelete(lineName)) { + return true; + } + return false; + } + + public static boolean haveSection(String lineName, String stationName) { + Line line = LineRepository.findLineByName(lineName); + for (Station station : line.stationList()) { + if (station.getName().equals(stationName)) { + return true; + } + } + System.out.println("[ ERROR ] 구간에 존재하지 않는 역입니다."); + return false; + } + + public static boolean checkValidDelete(String lineName) { + Line line = LineRepository.findLineByName(lineName); + if (line.stationList().size() <= SIZE) { + System.out.println("[ ERROR ] 상행선 종점과 하행선 종점만 남았을 때는 구간을 삭제할 수 없습니다."); + return false; + } + return true; + } + +} diff --git a/src/main/java/subway/util/StationValidator.java b/src/main/java/subway/util/StationValidator.java new file mode 100644 index 000000000..4ea266037 --- /dev/null +++ b/src/main/java/subway/util/StationValidator.java @@ -0,0 +1,60 @@ +package subway.util; + +import subway.domain.Station; +import subway.domain.StationRepository; + +public class StationValidator { + + private static final int SIZE = 2; + + public static boolean checkValidStationName(String name) { + if (checkValidName(name) && !checkDuplicateName(name)) { + return true; + } + return false; + } + + public static boolean checkDuplicateName(String name) { + for(Station station : StationRepository.stations()) { + if (station.getName().equals(name)) { + System.out.println("[ ERROR ] 이미 존재하는 역입니다.\n"); + return true; + } + } + return false; + } + + public static boolean checkValidName(String name) { + if (name.length() >= SIZE) { + return true; + } + System.out.println("[ ERROR ] 역 이름은 2글자 이상이어야합니다.\n"); + return false; + } + + public static boolean checkRemovableStation(String name) { + if (haveStationName(name) && checkValidRemoveStation(name)) { + return true; + } + return false; + } + + public static boolean checkValidRemoveStation(String name) { + Station station = StationRepository.findStationByName(name); + if (station.isRemovable()) { + return true; + } + System.out.println("[ ERROR ] 노선과 연결되어 있어서 삭제할 수 없는 역입니다.\n"); + return false; + } + + public static boolean haveStationName(String name) { + for(Station station : StationRepository.stations()) { + if (station.getName().equals(name)) { + return true; + } + } + System.out.println("[ ERROR ] 등록 되지않은 지하철 역입니다.\n"); + return false; + } +} diff --git a/src/test/java/subway/domain/LineRepositoryTest.java b/src/test/java/subway/domain/LineRepositoryTest.java new file mode 100644 index 000000000..f3e1d322c --- /dev/null +++ b/src/test/java/subway/domain/LineRepositoryTest.java @@ -0,0 +1,31 @@ +package subway.domain; + +import org.junit.jupiter.api.Test; +import subway.util.DefaultSetting; + +import static org.junit.jupiter.api.Assertions.*; + +public class LineRepositoryTest { + + @Test + public void 초기값설정() { + new DefaultSetting().defaultSetting(); + } + + @Test + public void line_추가된다() { + LineRepository.addLine(new Line("10호선")); + assertEquals(LineRepository.findLineByName("10호선").getName(), "10호선"); + } + + @Test + public void line_삭제된다() { + LineRepository.addLine(new Line("삭제용호선")); + assertTrue(LineRepository.deleteLineByName("삭제용호선")); + } + + @Test + public void line_가져온다() { + assertEquals(LineRepository.findLineByName("2호선").getName(), "2호선"); + } +} diff --git a/src/test/java/subway/domain/LineTest.java b/src/test/java/subway/domain/LineTest.java new file mode 100644 index 000000000..ef671f958 --- /dev/null +++ b/src/test/java/subway/domain/LineTest.java @@ -0,0 +1,47 @@ +package subway.domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import subway.util.DefaultSetting; + +import static org.junit.jupiter.api.Assertions.*; + +public class LineTest { + + @BeforeEach + public void 초기값설정() { + new DefaultSetting().defaultSetting(); + StationRepository.addStation(new Station("서울역")); + StationRepository.addStation(new Station("중앙역")); + } + + @Test + public void 노선_생성된다() { + Line line = new Line("4호선"); + assertEquals(line.getName(), "4호선"); + } + + @Test + public void 상행_하행_생성자() { + Line line = new Line("4호선", "서울역", "중앙역"); + assertEquals(line.size(), 2); + } + + @Test + public void 가장_마지막에_구간_추가() { + Line line = new Line("5호선"); + line.addStation("중앙역"); + assertEquals(line.size(), 1); + } + + @Order(2) + @Test + public void 순서_정해서_구간_추가() { + Line line = LineRepository.findLineByName("2호선"); + line.addStation("1", "중앙역"); + assertEquals(line.stationList().get(0).getName(), "중앙역"); + } + + +} diff --git a/src/test/java/subway/domain/StationRepositoryTest.java b/src/test/java/subway/domain/StationRepositoryTest.java new file mode 100644 index 000000000..11df06b40 --- /dev/null +++ b/src/test/java/subway/domain/StationRepositoryTest.java @@ -0,0 +1,32 @@ +package subway.domain; + +import org.junit.jupiter.api.Test; +import subway.util.DefaultSetting; + +import static org.junit.jupiter.api.Assertions.*; + +public class StationRepositoryTest { + + @Test + public void 초기값_설정() { + new DefaultSetting().defaultSetting(); + } + + @Test + public void station_추가된다() { + StationRepository.addStation(new Station("서울역")); + assertEquals(StationRepository.findStationByName("서울역").getName(), "서울역"); + } + + @Test + public void station_삭제된다() { + StationRepository.addStation(new Station("서울역")); + assertTrue(StationRepository.deleteStation("서울역")); + } + + @Test + public void station_가져온다() { + Station station = StationRepository.findStationByName("양재역"); + assertEquals(station.getName(), "양재역"); + } +} diff --git a/src/test/java/subway/domain/StationTest.java b/src/test/java/subway/domain/StationTest.java new file mode 100644 index 000000000..aacfabe9f --- /dev/null +++ b/src/test/java/subway/domain/StationTest.java @@ -0,0 +1,43 @@ +package subway.domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import subway.util.DefaultSetting; + +import static org.junit.jupiter.api.Assertions.*; + +public class StationTest { + + Station station; + + @BeforeEach + public void 초기값설정() { + new DefaultSetting().defaultSetting(); + StationRepository.addStation(new Station("서울역")); + StationRepository.addStation(new Station("중앙역")); + station = new Station("서울숲역"); + } + + @Test + public void 역_생성된다() { + assertEquals(station.getName(), "서울숲역"); + } + + @Test + public void isRemovable_테스트() { + assertTrue(station.isRemovable()); + } + + @Test + public void increaseCount_테스트() { + station.increaseCount(); + assertEquals(station.getCount(), 1); + } + + @Test + public void decreaseCount_테스트() { + station.decreaseCount(); + assertEquals(station.getCount(), -1); + } + +}