diff --git a/README.md b/README.md deleted file mode 100644 index e6ed1056f..000000000 --- a/README.md +++ /dev/null @@ -1,470 +0,0 @@ -# 지하철 노선도 미션 -- 지하철 역과 노선을 관리하는 지하철 노선도 기능을 구현한다. - -
- -## 🚀 기능 요구사항 - -### 초기 설정 -- 프로그램 시작 시 역, 노선 등 필요한 정보를 미리 셋팅할 수 있다. - -> 아래의 사전 등록 정보로 반드시 초기 설정을 하기 -> -``` - 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/docs/README.md b/docs/README.md new file mode 100644 index 000000000..cf9d5c551 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,65 @@ +# 지하철 노선도 미션 + +## 🚀 기능 요구사항 + +- [X] 역 정보 초기 설정하는 기능 + +- [X] 메인 화면 조회 + +- [X] 메인 기능 선택 + - [X] 예외사항: 선택할 기능은 1 - 4, Q만 가능 + +- [X] 지하철 역 관리 기능 선택 + - [X] 예외사항: 선택할 기능은 1 - 3, B만 가능 + +- [X] 지하철 역을 등록 + - [X] 예외사항: 역 이름은 2글자 이상이어야 한다. + - [X] 예외사항: 지하철 역 이름은 중복될 수 없다. + +- [X] 지하철 역을 삭제 + - [X] 예외사항: 노선에 등록된 역은 삭제할 수 없다. + - [X] 예외사항: 삭제할 역이 역 목록에 있어야 한다. + +- [X] 지하철 역 목록 조회 + +- [X] 메인 화면으로 되돌아가기 + +- [X] 지하철 노선 관리 기능 선택 + - [X] 예외사항: 선택할 기능은 1 - 3, B만 가능 + +- [X] 지하철 노선 등록 + - [X] 예외사항: 노선 이름은 2글자 이상이어야 한다. + - [X] 예외사항: 노선 이름은 중복될 수 없다. + +- [X] 노선 등록 시 상행 종점역과 하행 종점역을 등록 + - [X] 예외사항: 상행 종점역과 하행 종점역은 2글자 이상이어야 한다. + - [X] 예외사항: 상행 종점역과 하행 종점역이 같지 않다. + - [X] 예외사항: 등록할 역이 역 목록에 있어야한다. + +- [X] 지하철 노선 삭제 + - [X] 예외사항: 삭제할 역은 등록된 노선이어야 한다. + +- [X] 지하철 노선 조회 + +- [X] 메인 화면으로 되돌아가기 + +- [X] 지하철 구간 관리 기능 선택 + - [X] 예외사항: 선택할 기능은 1 - 2, B만 가능 + + +- [X] 지하철 구간 등록 + - [X] 예외사항: 노선 당 중복된 역을 허용하지 않는다. + - [X] 예외사항: 입력할 노선은 등록된 노선이어야 한다. + - [X] 예외사항: 입력할 역이름은 2글자 이상이어야 한다. + - [X] 예외사항: 입력할 역이름은 등록된 역이어야 한다. + - [X] 예외사항: 입력할 순서는 1 - (노선에 배정된 역 개수)만 허용한다. + +- [X] 지하철 구간 삭제 + - [X] 예외사항: 등록된 노선만 삭제할 수 있다. + - [X] 예외사항: 삭제할 역은 2글자 이상이어야한다. + - [X] 예외사항: 삭제할 역은 선택한 노선에 등록된 역 이어야한다. + - [X] 예외사항: 노선에 포함된 역이 2개 이하일 때는 삭제할 수 없다. + +- [X] 메인 화면으로 되돌아가기 + +- [ ] 지하철 노선도 출력 \ No newline at end of file diff --git a/src/main/java/subway/Application.java b/src/main/java/subway/Application.java index 0bcf786cc..9ba8f627b 100644 --- a/src/main/java/subway/Application.java +++ b/src/main/java/subway/Application.java @@ -1,10 +1,22 @@ package subway; +/* + * Application + * + * version 1.0 + * + * 2020.12.15 + * + * Copyright (c) by Davinci.J + */ +import subway.controller.Subway; +import subway.view.InputView; import java.util.Scanner; public class Application { public static void main(String[] args) { final Scanner scanner = new Scanner(System.in); - // TODO: 프로그램 구현 + InputView.insertScanner(scanner); + Subway.run(); } } diff --git a/src/main/java/subway/Constants.java b/src/main/java/subway/Constants.java new file mode 100644 index 000000000..9be70b478 --- /dev/null +++ b/src/main/java/subway/Constants.java @@ -0,0 +1,63 @@ +package subway; + +public class Constants { + public static final String APPLICATION_QUIT = "Q"; + public static final String SUBWAY_LINEMAP_MENU = "4"; + public static final String LINE_MAIN_MENU = "## 노선 관리 화면\n1. 노선 등록\n" + + "2. 노선 삭제\n3. 노선 조회\nB. 돌아가기\n"; + public static final String WRONG_STATE_TRY_AGAIN = "[ERROR] 선택할 수 없는 기능입니다."; + public static final String INPUT_LINE_TO_ENROLL = "## 등록할 노선 이름을 입력하세요."; + public static final String DUPLICATED_TRY_AGAIN = "[ERROR] 중복됩니다."; + public static final String INPUT_START_STATION_TO_ENROLL = "## 등록할 노선의 상행 종점역 " + + "이름을 입력하세요."; + public static final String LINE_MENU = "2"; + public static final String LINE_ENROLLED = "\n[INFO] 지하철 노선이 등록되었습니다.\n"; + public static final String NOTHING_TRY_AGAIN = "[ERROR] 해당 역이 없습니다."; + public static final String NOTHING_OR_START_END_SAME_TRY_AGAIN = "[ERROR] 해당 역이 없거나 " + + "상행 종점, 하행 종점역이 같습니다."; + public static final String INPUT_END_STATION_TO_ENROLL = "## 등록할 노선의 하행 종점역 " + + "이름을 입력하세요."; + public static final String INPUT_LINE_TO_DELETE = "## 삭제할 노선 이름을 입력하세요."; + public static final String NOTHING_TO_DELETE_TRY_AGAIN = "[ERROR] 삭제할 노선이 없습니다."; + public static final String LINE_DELETED = "\n[INFO] 지하철 노선이 삭제되었습니다.\n"; + public static final String SECTION_MAIN_MENU = "## 구간 관리 화면\n1. 구간 등록\n2. 구간 삭제\n" + + "B. 돌아가기\n"; + public static final String INPUT_LINE = "## 노선을 입력하세요."; + public static final String SECTION_ENROLLED = "\n[INFO] 구간이 등록되었습니다.\n"; + public static final String LINE_NOTHING_TRY_AGAIN = "[ERROR] 해당 노선이 없습니다."; + public static final String SECTION_MENU = "3"; + public static final String INPUT_STATION = "## 역이름을 입력하세요."; + public static final String NOTHING_OR_ALREADY_ENROLLED_TRY_AGAIN = "[ERROR] 해당 역이 없거나" + + " 이미 노선에 등록되어 있습니다."; + public static final String INPUT_ORDER = "## 순서를 입력하세요."; + public static final String INDEX_OUT_OF_BOUNDS_TRY_AGAIN = "[ERROR] 인덱스가 초과되었습니다."; + public static final String INPUT_LINE_OF_SECTION_TO_DELETE = "## 삭제할 구간의 노선을 입력하세요."; + public static final String SECTION_DELETED = "\n[INFO] 구간이 삭제되었습니다.\n"; + public static final String INPUT_STATION_OF_SECTION_TO_ENROLL = "## 삭제할 구간의 역을 입력하세요."; + public static final String STATION_NOTHING_OR_LINE_LENGTH_LIMIT_TRY_AGAIN = "[ERROR] " + + "해당 역이 없거나 현재 노선의 길이가 2이하여서 삭제 할 수 없습니다."; + public static final int LINE_MIN_LENGTH = 2; + public static final String STATION_MAIN_MENU = "## 역 관리 화면\n1. 역 등록\n" + + "2. 역 삭제\n3. 역 조회\nB. 돌아가기\n"; + public static final String INPUT_STATION_TO_ENROLL = "## 등록할 역 이름을 입력하세요."; + public static final String STATION_ENROLLED = "\n[INFO] 지하철 역이 등록되었습니다.\n"; + public static final String INPUT_STATION_TO_DELETE = "## 삭제할 역 이름을 입력하세요."; + public static final String STATION_DELETED = "\n[INFO] 지하철 역이 삭제되었습니다.\n"; + public static final String STATION_MENU_NUMBER = "1"; + public static final String MAIN_MENU = "## 메인 화면\n1. 역 관리\n2. 노선 관리\n3. 구간 관리\n" + + "4. 지하철 노선도 출력\nQ. 종료\n"; + public static final String ONE = "1"; + public static final String TOW = "2"; + public static final String THREE = "3"; + public static final String FOUR = "4"; + public static final String INFORMATION = "[INFO] "; + public static final String NAME_LENGTH_LIMIT_ERROR = "[ERROR] 이름은 2글자 이상입니다."; + public static final int NAME_LENGTH_LIMIT = 2; + public static final String LINE_LIST = "\n## 노선 목록"; + public static final String INFORMATION_BAR = "\n[INFO] ---"; + public static final String ERROR_ONLY_POSITIVE_NUMBER = "[ERROR] 양의 정수만 가능합니다."; + public static final int SINGLE_DIGIT_MIN = 0; + public static final int SINGLE_DIGIT_MAX = 9; + public static final String STATION_LIST = "\n## 역 목록"; + public static final String ERROR_NOT_NUMBER = "[ERROR] 숫자가 아닙니다."; +} diff --git a/src/main/java/subway/controller/Subway.java b/src/main/java/subway/controller/Subway.java new file mode 100644 index 000000000..08741d3a7 --- /dev/null +++ b/src/main/java/subway/controller/Subway.java @@ -0,0 +1,70 @@ +package subway.controller; +/* + * Subway + * + * version 1.0 + * + * 2020.12.15 + * + * Copyright (c) by Davinci.J + */ +import subway.Constants; +import subway.domain.LineRepository; +import subway.domain.StationRepository; +import subway.manager.LineManager; +import subway.manager.SectionManager; +import subway.manager.StationManager; +import subway.view.InputView; +import subway.view.OutputView; + +import java.util.Arrays; + +public class Subway { + static { + StationRepository.init(); + LineRepository.init(); + } + + private enum Menu { + STATION("1", StationManager::selectMenu), + LINE("2", LineManager::selectMenu), + SECTION("3", SectionManager::selectMenu), + SUBWAY_LIST("4", OutputView::printLineAndStation), + QUIT("Q", new Subway()::exit); + + private final String name; + private final Runnable runnable; + + Menu(String name, Runnable runnable) { + this.name = name; + this.runnable = runnable; + } + + public static void execute(String input) { + Arrays.stream(values()) + .filter(value -> value.name.equals(input)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(Constants.WRONG_STATE_TRY_AGAIN)) + .runnable.run(); + } + + } + + public static void run() { + try { + String state = InputView.inputMainMenu(); + Menu.execute(state); + if (!state.equals(Constants.APPLICATION_QUIT)) { + run(); + } + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + run(); + } + } + + private void exit() { + System.exit(0); + } + +} \ No newline at end of file diff --git a/src/main/java/subway/domain/Line.java b/src/main/java/subway/domain/Line.java index f4d738d5a..1788183bd 100644 --- a/src/main/java/subway/domain/Line.java +++ b/src/main/java/subway/domain/Line.java @@ -1,15 +1,57 @@ package subway.domain; +import subway.Constants; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + public class Line { - private String name; + private LineName name; + private List stations = new ArrayList<>(); - public Line(String name) { + public Line(LineName name) { this.name = name; } - public String getName() { + public LineName getName() { return name; } - // 추가 기능 구현 + public void addStations(Station station) { + station.setRegister(true); + stations.add(station); + } + + @Override + public boolean equals(Object object) { + if (object instanceof Line) { + Line anotherStation = (Line) object; + return name.equals(anotherStation.name); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() { + return Constants.INFORMATION + name; + } + + public List getStations() { + return stations; + } + + public int size() { + return stations.size(); + } + + public void addStations(int index, Station station) { + stations.add(index, station); + } + } diff --git a/src/main/java/subway/domain/LineName.java b/src/main/java/subway/domain/LineName.java new file mode 100644 index 000000000..92d62387f --- /dev/null +++ b/src/main/java/subway/domain/LineName.java @@ -0,0 +1,43 @@ +package subway.domain; +/* + * LineName + * + * version 1.0 + * + * 2020.12.15 + * + * Copyright (c) by Davinci.J + */ +import subway.Constants; + +import java.util.Objects; + +public class LineName { + private String name; + + public LineName(String name) { + if (name.length() < Constants.NAME_LENGTH_LIMIT) { + throw new IllegalArgumentException(Constants.NAME_LENGTH_LIMIT_ERROR); + } + this.name = name; + } + + @Override + public boolean equals(Object object) { + if (object instanceof LineName) { + LineName anotherName = (LineName) object; + return name.equals(anotherName.name); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/LineRepository.java index 49132ddb6..4caa32786 100644 --- a/src/main/java/subway/domain/LineRepository.java +++ b/src/main/java/subway/domain/LineRepository.java @@ -8,6 +8,25 @@ public class LineRepository { private static final List lines = new ArrayList<>(); + public static void init() { + Line line1 = new Line(new LineName("2호선")); + line1.addStations(new Station(new StationName("교대역"))); + line1.addStations(new Station(new StationName("강남역"))); + line1.addStations(new Station(new StationName("역삼역"))); + Line line2 = new Line(new LineName("3호선")); + line2.addStations(new Station(new StationName("교대역"))); + line2.addStations(new Station(new StationName("남부터미널역"))); + line2.addStations(new Station(new StationName("양재역"))); + line2.addStations(new Station(new StationName("매봉역"))); + Line line3 = new Line(new LineName("신분당선")); + line3.addStations(new Station(new StationName("강남역"))); + line3.addStations(new Station(new StationName("양재역"))); + line3.addStations(new Station(new StationName("양재시민의숲역"))); + lines.add(line1); + lines.add(line2); + lines.add(line3); + } + public static List lines() { return Collections.unmodifiableList(lines); } @@ -16,7 +35,44 @@ public static void addLine(Line line) { lines.add(line); } - public static boolean deleteLineByName(String name) { + public static boolean deleteLineByName(LineName name) { return lines.removeIf(line -> Objects.equals(line.getName(), name)); } + + public static boolean containsStationOfLine(Line line, Station station) { + for (Line n : lines) { + if (n.equals(line) && n.getStations().contains(station)) { + return true; + } + } + return false; + } + + public static int getLineSize(Line line) { + int size = 0; + for (Line n : lines) { + if (n.equals(line)) { + size = n.size(); + break; + } + } + return size; + } + + public static void addSection(Line line, Station station, int orderNumber) { + for (Line n : lines) { + if (n.equals(line)) { + n.addStations(orderNumber, station); + } + } + } + + public static void deleteSection(Line line, Station station) { + for (Line n : lines) { + if (n.equals(line)) { + n.getStations().remove(station); + } + } + } + } diff --git a/src/main/java/subway/domain/PositiveNumber.java b/src/main/java/subway/domain/PositiveNumber.java new file mode 100644 index 000000000..8b7d096ed --- /dev/null +++ b/src/main/java/subway/domain/PositiveNumber.java @@ -0,0 +1,32 @@ +package subway.domain; + +import subway.Constants; + +/* + * PositiveNumber + * + * version 1.0 + * + * 2020.12.15 + * + * Copyright (c) by Davinci.J + */ +public class PositiveNumber implements Comparable { + private int number; + + public PositiveNumber(int number) { + if (number <= 0) { + throw new IllegalArgumentException(Constants.ERROR_ONLY_POSITIVE_NUMBER); + } + this.number = number; + } + + @Override + public int compareTo(PositiveNumber anotherNumber) { + return number - anotherNumber.number; + } + + public int getNumber() { + return number; + } +} diff --git a/src/main/java/subway/domain/Station.java b/src/main/java/subway/domain/Station.java index bdb142590..4e2daaf2d 100644 --- a/src/main/java/subway/domain/Station.java +++ b/src/main/java/subway/domain/Station.java @@ -1,15 +1,46 @@ package subway.domain; +import subway.Constants; + +import java.util.Objects; + public class Station { - private String name; + private StationName name; + private boolean register; - public Station(String name) { + public Station(StationName name) { this.name = name; } - public String getName() { + public StationName getName() { return name; } - // 추가 기능 구현 + @Override + public boolean equals(Object object) { + if (object instanceof Station) { + Station anotherStation = (Station) object; + return name.equals(anotherStation.name); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + public boolean isRegister() { + return register; + } + + public boolean setRegister(boolean register) { + return this.register = register; + } + + @Override + public String toString() { + return Constants.INFORMATION + name.toString(); + } + } diff --git a/src/main/java/subway/domain/StationName.java b/src/main/java/subway/domain/StationName.java new file mode 100644 index 000000000..115dc8002 --- /dev/null +++ b/src/main/java/subway/domain/StationName.java @@ -0,0 +1,43 @@ +package subway.domain; +/* + * StationName + * + * version 1.0 + * + * 2020.12.15 + * + * Copyright (c) by Davinci.J + */ +import subway.Constants; + +import java.util.Objects; + +public class StationName { + private String name; + + public StationName(String name) { + if (name.length() < Constants.NAME_LENGTH_LIMIT) { + throw new IllegalArgumentException(Constants.NAME_LENGTH_LIMIT_ERROR); + } + this.name = name; + } + + @Override + public boolean equals(Object object) { + if (object instanceof StationName) { + StationName anotherName = (StationName) object; + return name.equals(anotherName.name); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/StationRepository.java index b7245c0f3..0c57f53cc 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/StationRepository.java @@ -8,6 +8,16 @@ public class StationRepository { private static final List stations = new ArrayList<>(); + public static void init() { + stations.add(new Station(new StationName("교대역"))); + stations.add(new Station(new StationName("강남역"))); + stations.add(new Station(new StationName("역삼역"))); + stations.add(new Station(new StationName("남부터미널역"))); + stations.add(new Station(new StationName("양재역"))); + stations.add(new Station(new StationName("양재시민의숲역"))); + stations.add(new Station(new StationName("매봉역"))); + } + public static List stations() { return Collections.unmodifiableList(stations); } @@ -17,6 +27,16 @@ public static void addStation(Station station) { } public static boolean deleteStation(String name) { - return stations.removeIf(station -> Objects.equals(station.getName(), name)); + return stations.removeIf(station -> Objects.equals(station.getName().toString(), name)); } + + public static boolean isRegisteredStation(Station anotherStation) { + for (Station station : stations) { + if (station.equals(anotherStation) && station.isRegister()) { + return true; + } + } + return false; + } + } diff --git a/src/main/java/subway/manager/LineManager.java b/src/main/java/subway/manager/LineManager.java new file mode 100644 index 000000000..b61c50977 --- /dev/null +++ b/src/main/java/subway/manager/LineManager.java @@ -0,0 +1,107 @@ +package subway.manager; +/* + * InputLineManager + * + * version 1.0 + * + * 2020.12.15 + * + * Copyright (c) by Davinci.J + */ +import subway.Constants; +import subway.domain.*; +import subway.view.InputView; +import subway.view.OutputView; + +import java.util.Arrays; + +public class LineManager { + private enum Menu { + REGISTER("1", LineManager::register), + DELETE("2", LineManager::delete), + INQUIRY("3", OutputView::printLine), + BACK("B", () -> {}); + + private final String name; + private final Runnable runnable; + + Menu(String name, Runnable runnable) { + this.name = name; + this.runnable = runnable; + } + + public static void execute(String input) { + Arrays.stream(values()) + .filter(value -> value.name.equals(input)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(Constants.WRONG_STATE_TRY_AGAIN)) + .runnable.run(); + } + } + + public static void selectMenu() { + try { + Menu.execute(InputView.inputLineMenu()); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + selectMenu(); + } + } + + public static void register() { + try { + Line line = new Line(new LineName(InputView.inputLineToRegister())); + if (LineRepository.lines().contains(line)) { + throw new IllegalArgumentException(Constants.DUPLICATED_TRY_AGAIN); + } + LineRepository.addLine(line); + registerStartStation(line); + System.out.println(Constants.LINE_ENROLLED); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + register(); + } + } + + private static void registerStartStation(Line line) { + try { + Station station = new Station( + new StationName(InputView.inputStartStationToEnroll())); + if (!StationRepository.stations().contains(station)) { + throw new IllegalArgumentException(Constants.NOTHING_TRY_AGAIN); + } + registerEndStation(line, station); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + registerStartStation(line); + } + } + + private static void registerEndStation(Line line, Station startStation) { + try { + Station endStation = new Station(new StationName(InputView.inputEndStationToEnroll())); + if (!StationRepository.stations().contains(endStation) + || startStation.equals(endStation)) { + throw new IllegalArgumentException(Constants.NOTHING_OR_START_END_SAME_TRY_AGAIN); + } + line.addStations(startStation); + line.addStations(endStation); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + registerEndStation(line, startStation); + } + } + + public static void delete() { + try { + if (!LineRepository.deleteLineByName(new LineName(InputView.inputLineToDelete()))) { + throw new IllegalArgumentException(Constants.NOTHING_TO_DELETE_TRY_AGAIN); + } + System.out.println(Constants.LINE_DELETED); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + delete(); + } + } + +} diff --git a/src/main/java/subway/manager/SectionManager.java b/src/main/java/subway/manager/SectionManager.java new file mode 100644 index 000000000..d33224ded --- /dev/null +++ b/src/main/java/subway/manager/SectionManager.java @@ -0,0 +1,121 @@ +package subway.manager; +/* + * InputSectionManager + * + * version 1.0 + * + * 2020.12.15 + * + * Copyright (c) by Davinci.J + */ +import subway.Constants; +import subway.domain.*; +import subway.view.InputView; + +import java.util.Arrays; + +public class SectionManager { + private enum Menu { + REGISTER("1", SectionManager::register), + DELETE("2", SectionManager::delete), + BACK("B", () -> {}); + + private final String name; + private final Runnable runnable; + + Menu(String name, Runnable runnable) { + this.name = name; + this.runnable = runnable; + } + + public static void execute(String input) { + Arrays.stream(values()) + .filter(value -> value.name.equals(input)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(Constants.WRONG_STATE_TRY_AGAIN)) + .runnable.run(); + } + } + + public static void selectMenu() { + try { + Menu.execute(InputView.inputSectionMenu()); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + selectMenu(); + } + } + + public static void register() { + try { + Line line = new Line(new LineName(InputView.inputSectionToRegister())); + if (!LineRepository.lines().contains(line)) { + throw new IllegalArgumentException(Constants.LINE_NOTHING_TRY_AGAIN); + } + registerStationInSection(line); + System.out.println(Constants.SECTION_ENROLLED); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + register(); + } + } + + private static void registerStationInSection(Line line) { + try { + Station station = new Station( + new StationName(InputView.inputStationInSectionToRegister())); + if (!StationRepository.stations().contains(station) + || LineRepository.containsStationOfLine(line, station)) { + throw new IllegalArgumentException(Constants.NOTHING_OR_ALREADY_ENROLLED_TRY_AGAIN); + } + registerOrderInSection(line, station); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + registerStationInSection(line); + } + } + + private static void registerOrderInSection(Line line, Station station) { + try { + PositiveNumber orderNumber = new PositiveNumber(InputView.inputOrderInSectionToRegister()); + PositiveNumber lineSize = new PositiveNumber(LineRepository.getLineSize(line)); + if (orderNumber.compareTo(lineSize) > 0) { + throw new IllegalArgumentException(Constants.INDEX_OUT_OF_BOUNDS_TRY_AGAIN); + } + station.setRegister(true); + LineRepository.addSection(line, station, orderNumber.getNumber() - 1); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + registerOrderInSection(line, station); + } + } + + public static void delete() { + try { + Line line = new Line(new LineName(InputView.inputSectionToDelete())); + if (!LineRepository.lines().contains(line)) { + throw new IllegalArgumentException(Constants.LINE_NOTHING_TRY_AGAIN); + } + deleteStationInSection(line); + System.out.println(Constants.SECTION_DELETED); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + delete(); + } + } + + private static void deleteStationInSection(Line line) { + try { + Station station = new Station( + new StationName(InputView.inputStationInSectionToDelete())); + if (!LineRepository.containsStationOfLine(line, station) + || LineRepository.getLineSize(line) <= Constants.LINE_MIN_LENGTH) { + throw new IllegalArgumentException(Constants.STATION_NOTHING_OR_LINE_LENGTH_LIMIT_TRY_AGAIN); + } + LineRepository.deleteSection(line, station); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + deleteStationInSection(line); + } + } +} diff --git a/src/main/java/subway/manager/StationManager.java b/src/main/java/subway/manager/StationManager.java new file mode 100644 index 000000000..fdeea9959 --- /dev/null +++ b/src/main/java/subway/manager/StationManager.java @@ -0,0 +1,82 @@ +package subway.manager; +/* + * InputStationManager + * + * version 1.0 + * + * 2020.12.15 + * + * Copyright (c) by Davinci.J + */ +import subway.Constants; +import subway.domain.Station; +import subway.domain.StationName; +import subway.domain.StationRepository; +import subway.view.InputView; +import subway.view.OutputView; + +import java.util.Arrays; + +public class StationManager { + private enum Menu { + REGISTER("1", StationManager::register), + DELETE("2", StationManager::delete), + INQUIRY("3", OutputView::printStation), + BACK("B", () -> {}); + + private final String name; + private final Runnable runnable; + + Menu(String name, Runnable runnable) { + this.name = name; + this.runnable = runnable; + } + + public static void execute(String input) { + Arrays.stream(values()) + .filter(value -> value.name.equals(input)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(Constants.WRONG_STATE_TRY_AGAIN)) + .runnable.run(); + } + } + + public static void selectMenu() { + try { + String state = InputView.inputStationMenu(); + Menu.execute(state); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + selectMenu(); + } + } + + public static void register() { + try { + Station station = new Station(new StationName(InputView.inputStationToRegister())); + if (StationRepository.stations().contains(station)) { + throw new IllegalArgumentException(Constants.DUPLICATED_TRY_AGAIN); + } + StationRepository.addStation(station); + System.out.println(Constants.STATION_ENROLLED); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + register(); + } + } + + public static void delete() { + try { + if (StationRepository.isRegisteredStation( + new Station(new StationName(InputView.inputStationToDelete()))) + || !StationRepository.deleteStation(InputView.inputStationToDelete())) { + throw new IllegalArgumentException(Constants.NOTHING_OR_ALREADY_ENROLLED_TRY_AGAIN); + } + System.out.println(Constants.STATION_DELETED); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + delete(); + } + } + +} diff --git a/src/main/java/subway/view/InputView.java b/src/main/java/subway/view/InputView.java new file mode 100644 index 000000000..af190bf72 --- /dev/null +++ b/src/main/java/subway/view/InputView.java @@ -0,0 +1,96 @@ +package subway.view; + +import subway.Constants; + +import java.util.InputMismatchException; +import java.util.Scanner; + +public class InputView { + public static Scanner scanner; + + public static void insertScanner(Scanner scanner) { + InputView.scanner = scanner; + } + + public static String inputMainMenu() { + System.out.println(Constants.MAIN_MENU); + return scanner.next(); + } + + public static String inputStationMenu() { + System.out.println(Constants.STATION_MAIN_MENU); + return scanner.next(); + } + + public static String inputStationToRegister() { + System.out.println(Constants.INPUT_STATION_TO_ENROLL); + return scanner.next(); + } + + public static String inputStationToDelete() { + System.out.println(Constants.INPUT_STATION_TO_DELETE); + return scanner.next(); + } + + public static String inputLineMenu() { + System.out.println(Constants.LINE_MAIN_MENU); + return scanner.next(); + } + + public static String inputLineToRegister() { + System.out.println(Constants.INPUT_LINE_TO_ENROLL); + return scanner.next(); + } + + public static String inputStartStationToEnroll() { + System.out.println(Constants.INPUT_START_STATION_TO_ENROLL); + return scanner.next(); + } + + public static String inputEndStationToEnroll() { + System.out.println(Constants.INPUT_END_STATION_TO_ENROLL); + return scanner.next(); + } + + public static String inputLineToDelete() { + System.out.println(Constants.INPUT_LINE_TO_DELETE); + return scanner.next(); + } + + public static String inputSectionMenu() { + System.out.println(Constants.SECTION_MAIN_MENU); + return scanner.next(); + } + + public static String inputSectionToRegister() { + System.out.println(Constants.INPUT_LINE); + return scanner.next(); + } + + public static String inputStationInSectionToRegister() { + System.out.println(Constants.INPUT_STATION); + return scanner.next(); + } + + public static int inputOrderInSectionToRegister() { + try { + System.out.println(Constants.INPUT_ORDER); + return scanner.nextInt(); + } catch (InputMismatchException e) { + System.out.println(Constants.ERROR_NOT_NUMBER); + scanner.nextLine(); + return inputOrderInSectionToRegister(); + } + } + + public static String inputSectionToDelete() { + System.out.println(Constants.INPUT_LINE_OF_SECTION_TO_DELETE); + return scanner.next(); + } + + public static String inputStationInSectionToDelete() { + System.out.println(Constants.INPUT_STATION_OF_SECTION_TO_ENROLL); + return scanner.next(); + } + +} diff --git a/src/main/java/subway/view/OutputView.java b/src/main/java/subway/view/OutputView.java new file mode 100644 index 000000000..8255accf8 --- /dev/null +++ b/src/main/java/subway/view/OutputView.java @@ -0,0 +1,33 @@ +package subway.view; + +import subway.Constants; +import subway.domain.*; + +public class OutputView { + + public static void printStation() { + System.out.println(Constants.STATION_LIST); + for (Station station : StationRepository.stations()) { + System.out.println(station); + } + System.out.println(); + } + + public static void printLine() { + System.out.println(Constants.LINE_LIST); + for (Line line : LineRepository.lines()) { + System.out.println(line.toString()); + } + System.out.println(); + } + + public static void printLineAndStation() { + for (Line line : LineRepository.lines()) { + System.out.println(line.toString() + Constants.INFORMATION_BAR); + for (Station station : line.getStations()) { + System.out.println(station.toString()); + } + System.out.println(); + } + } +} diff --git a/src/test/java/subway/domain/LineNameTest.java b/src/test/java/subway/domain/LineNameTest.java new file mode 100644 index 000000000..fa09c67b7 --- /dev/null +++ b/src/test/java/subway/domain/LineNameTest.java @@ -0,0 +1,41 @@ +package subway.domain; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class LineNameTest { + + @Test + public void testCase1_isCorrectLineName() { + //GIVEN + String name = "2호선"; + + //WHEN + boolean actualResult = true; + try { + LineName lineName = new LineName(name); + } catch (Exception e) { + actualResult = false; + } + + //THEN + Assertions.assertTrue(actualResult); + } + + @Test + public void testCase2_isCorrectLineName() { + //GIVEN + String name = "2"; + + //WHEN + boolean actualResult = true; + try { + LineName lineName = new LineName(name); + } catch (Exception e) { + actualResult = false; + } + + //THEN + Assertions.assertFalse(actualResult); + } +} diff --git a/src/test/java/subway/domain/PositiveNumberTest.java b/src/test/java/subway/domain/PositiveNumberTest.java new file mode 100644 index 000000000..fcafffec2 --- /dev/null +++ b/src/test/java/subway/domain/PositiveNumberTest.java @@ -0,0 +1,58 @@ +package subway.domain; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class PositiveNumberTest { + + @Test + public void testCase1_isPositiveNumber() { + //GIVEN + String number = "-1"; + + //WHEN + boolean actualResult = true; + try { + PositiveNumber positiveNumber = new PositiveNumber(number); + } catch (Exception e) { + actualResult = false; + } + + //THEN + Assertions.assertFalse(actualResult); + } + + @Test + public void testCase2_isCorrectLineName() { + //GIVEN + String number = "10"; + + //WHEN + boolean actualResult = true; + try { + PositiveNumber positiveNumber = new PositiveNumber(number); + } catch (Exception e) { + actualResult = false; + } + + //THEN + Assertions.assertTrue(actualResult); + } + + @Test + public void testCase3_isCorrectLineName() { + //GIVEN + String number = "9"; + + //WHEN + boolean actualResult = true; + try { + PositiveNumber positiveNumber = new PositiveNumber(number); + } catch (Exception e) { + actualResult = false; + } + + //THEN + Assertions.assertTrue(actualResult); + } +} diff --git a/src/test/java/subway/domain/StationNameTest.java b/src/test/java/subway/domain/StationNameTest.java new file mode 100644 index 000000000..7b698d869 --- /dev/null +++ b/src/test/java/subway/domain/StationNameTest.java @@ -0,0 +1,41 @@ +package subway.domain; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class StationNameTest { + + @Test + public void testCase1_isCorrectStationName() { + //GIVEN + String name = "방배역"; + + //WHEN + boolean actualResult = true; + try { + StationName stationName = new StationName(name); + } catch (Exception e) { + actualResult = false; + } + + //THEN + Assertions.assertTrue(actualResult); + } + + @Test + public void testCase2_isCorrectLineName() { + //GIVEN + String name = "역"; + + //WHEN + boolean actualResult = true; + try { + StationName stationName = new StationName(name); + } catch (Exception e) { + actualResult = false; + } + + //THEN + Assertions.assertFalse(actualResult); + } +}