-
Notifications
You must be signed in to change notification settings - Fork 8
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
[지하철 노선도] 구현 완료 #1
base: main
Are you sure you want to change the base?
Changes from 7 commits
c0dc38b
3868abe
2af22bc
ec9daf5
1d47e9c
7bc488e
8f0d81f
7de2dd0
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,33 @@ | ||
# 기능정의 | ||
|
||
## 도메인 | ||
|
||
### 지하철(Staion) | ||
|
||
- [x] 지하철역 등록 기능 | ||
- [x] [ERROR] 지하철역은 두글자 이상이여야 한다. | ||
- [x] [ERROR] 지하철역은 한국어만 가능합니다. | ||
- [x] [ERROR] 중복된 역 이름은 등록할 수 없습니다. | ||
- [x] 지하철역 삭제 기능 | ||
- [x] [ERROR] 존재하는 지하철역만 삭제 가능합니다. | ||
- [x] [ERROR] 노선에 등록된 역은 삭제가 안됩니다. | ||
- [x] 지하철역 전체 조회 기능 | ||
|
||
### 노선(Line) | ||
|
||
- [x] 노선 등록 기능 | ||
- [x] 등록시 상행 종점과 하행 종점을 입력받는다. | ||
- [x] [ERROR] 노선의 이름은 두글자 이상이여야 한다. | ||
- [x] 노선 삭제 기능 | ||
- [x] [ERROR] 존재하는 노선만 삭제 가능합니다. | ||
- [x] 노선 목록 조회 기능 | ||
- [x] 노선에 등록된 역 조회 기능 | ||
- [x] 노선의 상행 종점부터 하행 종점까지 순서대로 목록을 조회한다. | ||
|
||
### 구간 | ||
|
||
- [x] 존재하는 노선에 역을 추가한다. | ||
- [x] [ERROR] 등록된 역만 노선에 추가가 가능하다. | ||
- [x] 노선에 역을 삭제한다. | ||
- [x] [ERROR] 노선에 역이 2개 이하면 삭제할 수 없다. | ||
- [x] [ERROR] 노선에 존재하는 역만 삭제할 수 있다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,10 @@ | ||
package subway; | ||
|
||
import java.util.Scanner; | ||
import subway.common.AppConfig; | ||
|
||
public class Application { | ||
public static void main(String[] args) { | ||
final Scanner scanner = new Scanner(System.in); | ||
// TODO: 프로그램 구현 | ||
|
||
AppConfig.getInstance().subwayController().start(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package subway.common; | ||
|
||
import subway.controller.SubwayController; | ||
import subway.domain.LineRepository; | ||
import subway.domain.StationRepository; | ||
import subway.domain.Subway; | ||
import subway.service.SubwayService; | ||
import subway.view.InputView; | ||
import subway.view.OutputView; | ||
|
||
public class AppConfig { | ||
|
||
private static AppConfig instance; | ||
|
||
private AppConfig() { | ||
} | ||
|
||
public static AppConfig getInstance() { | ||
if (instance == null) { | ||
instance = new AppConfig(); | ||
} | ||
return instance; | ||
} | ||
|
||
public SubwayController subwayController() { | ||
return new SubwayController(outputView(), inputView(), subwayService()); | ||
} | ||
|
||
private OutputView outputView() { | ||
return new OutputView(); | ||
} | ||
private InputView inputView() { | ||
return new InputView(); | ||
} | ||
|
||
private SubwayService subwayService() { | ||
return new SubwayService(subway(), lineRepository(), stationRepository()); | ||
} | ||
|
||
private Subway subway() { | ||
return new Subway(); | ||
} | ||
|
||
private LineRepository lineRepository() { | ||
return new LineRepository(); | ||
} | ||
|
||
private StationRepository stationRepository() { | ||
return new StationRepository(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package subway.common; | ||
|
||
public class ExceptionHandler { | ||
|
||
public static void retryOnException(final Runnable runnable) { | ||
try { | ||
runnable.run(); | ||
} catch (final IllegalArgumentException | IllegalStateException e) { | ||
System.out.println(e.getMessage()); | ||
retryOnException(runnable); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package subway.constant; | ||
|
||
import java.util.Arrays; | ||
import subway.constant.message.ErrorMessage; | ||
|
||
public enum LineCommand { | ||
|
||
SAVE("1"), | ||
DELETE("2"), | ||
SELECT("3"), | ||
BACK("B"); | ||
|
||
private final String command; | ||
|
||
LineCommand(final String command) { | ||
this.command = command; | ||
} | ||
|
||
public static LineCommand from(final String input) { | ||
return Arrays.stream(LineCommand.values()) | ||
.filter(e -> e.command.equals(input)) | ||
.findAny() | ||
.orElseThrow(() -> new IllegalArgumentException(ErrorMessage.ERROR_PREFIX.toMessage() + "없는 버튼입니다.")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package subway.constant; | ||
|
||
import java.util.Arrays; | ||
import subway.constant.message.ErrorMessage; | ||
|
||
public enum MainCommand { | ||
STATION_MANAGE("1"), | ||
LINE_MANAGE("2"), | ||
SECTION_MANAGE("3"), | ||
PRINT_SUBWAY("4"), | ||
QUIT("Q"); | ||
|
||
private final String command; | ||
|
||
MainCommand(final String command) { | ||
this.command = command; | ||
} | ||
|
||
public static MainCommand from(final String input) { | ||
return Arrays.stream(MainCommand.values()) | ||
.filter(e -> e.command.equalsIgnoreCase(input)) | ||
.findAny() | ||
.orElseThrow(() -> new IllegalArgumentException(ErrorMessage.ERROR_PREFIX.toMessage() + "없는 버튼입니다.")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package subway.constant; | ||
|
||
import java.util.Arrays; | ||
import subway.constant.message.ErrorMessage; | ||
|
||
public enum SectionCommand { | ||
SAVE("1"), | ||
DELETE("2"), | ||
BACK("B"); | ||
|
||
private final String command; | ||
|
||
SectionCommand(final String command) { | ||
this.command = command; | ||
} | ||
|
||
public static SectionCommand from(final String input) { | ||
return Arrays.stream(SectionCommand.values()) | ||
.filter(e -> e.command.equals(input)) | ||
.findAny() | ||
.orElseThrow(() -> new IllegalArgumentException(ErrorMessage.ERROR_PREFIX.toMessage() + "없는 버튼입니다.")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package subway.constant; | ||
|
||
import java.util.Arrays; | ||
import subway.constant.message.ErrorMessage; | ||
|
||
public enum StationCommand { | ||
SAVE("1"), | ||
DELETE("2"), | ||
SELECT("3"), | ||
BACK("B"); | ||
|
||
private final String command; | ||
|
||
StationCommand(final String command) { | ||
this.command = command; | ||
} | ||
|
||
public static StationCommand from(final String input) { | ||
return Arrays.stream(StationCommand.values()) | ||
.filter(e -> e.command.equals(input)) | ||
.findAny() | ||
.orElseThrow(() -> new IllegalArgumentException(ErrorMessage.ERROR_PREFIX.toMessage() + "없는 버튼입니다.")); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package subway.constant.message; | ||
|
||
public enum ErrorMessage { | ||
ERROR_PREFIX("[ERROR] "); | ||
|
||
private final String message; | ||
|
||
ErrorMessage(final String message) { | ||
this.message = message; | ||
} | ||
|
||
public String toMessage() { | ||
return message; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package subway.constant.message; | ||
|
||
public enum Processmessage { | ||
SUCCESS_PREFIX("[INFO] "), | ||
; | ||
|
||
private final String message; | ||
|
||
Processmessage(final String message) { | ||
this.message = message; | ||
} | ||
|
||
public String toMessage() { | ||
return message; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package subway.controller; | ||
|
||
import java.util.List; | ||
import subway.common.ExceptionHandler; | ||
import subway.constant.LineCommand; | ||
import subway.constant.MainCommand; | ||
import subway.constant.SectionCommand; | ||
import subway.constant.StationCommand; | ||
import subway.domain.Subway; | ||
import subway.service.SubwayService; | ||
import subway.view.InputView; | ||
import subway.view.OutputView; | ||
|
||
public class SubwayController { | ||
|
||
private final OutputView outputView; | ||
private final InputView inputView; | ||
|
||
public SubwayController( | ||
final OutputView outputView, | ||
final InputView inputView, | ||
final SubwayService subwayService | ||
) { | ||
this.outputView = outputView; | ||
this.inputView = inputView; | ||
this.subwayService = subwayService; | ||
} | ||
|
||
private final SubwayService subwayService; | ||
|
||
public void start() { | ||
subwayService.initializeSubway(); | ||
ExceptionHandler.retryOnException(this::startSubway); | ||
} | ||
|
||
private void startSubway() { | ||
while (true) { | ||
outputView.printMainView(); | ||
final String command = inputView.readCommand(); | ||
final MainCommand mainCommand = MainCommand.from(command); | ||
if (mainCommand.equals(MainCommand.STATION_MANAGE)) { | ||
manageStation(); | ||
} | ||
if (mainCommand.equals(MainCommand.LINE_MANAGE)) { | ||
manageLine(); | ||
} | ||
if (mainCommand.equals(MainCommand.SECTION_MANAGE)) { | ||
manageSection(); | ||
} | ||
if (mainCommand.equals(MainCommand.PRINT_SUBWAY)) { | ||
final Subway subway = subwayService.getSubway(); | ||
outputView.printSubway(subway); | ||
} | ||
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. 현재 모든 메서드가 While(true)라고 선언되어있어요. 프로그램을 시작할때 시작 -> 수행 -> 종료와 같은 기본적인 프로세스 동작을 기대하는데 현재 코드로 살펴봤을때 시작 -> 수행은 보이지만 종료에 대해서는 확인할 수 없다고 생각했어요 또한, startSubWay()라는 메서드명을 봤을땐 지하철 노선 동작의 시작이라는 기대를 하고 있는데 전체 동작을 다 수행한다고 생각이 들어 기대값과 메서드명이 일치하지 않는다고 생각이 들었어요. 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. 말씀해주신 방법을 고려해봤는데 enum으로 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. 탈출조건이 명확하게 보이면 좋을 것 같아요 현재 해당 로직은 시작,수행,탈출에 대한 수행을 최상위로 표현하는 유스케이스 느낌이라고 생각하는데 보다 적절한 네이밍으로 사용되면 좋겠고 유스케이스가 주는 의미를 생각해보시면 좋겠어요. |
||
} | ||
} | ||
|
||
private void manageSection() { | ||
while (true) { | ||
outputView.printSectionManageView(); | ||
final String sectionManageCommand = inputView.readCommand(); | ||
final SectionCommand sectionCommand = SectionCommand.from(sectionManageCommand); | ||
if (sectionCommand.equals(SectionCommand.SAVE)) { | ||
final String inputLine = inputView.readLineName(); | ||
final String inputStation = inputView.readStationName(); | ||
final String inputIndex = inputView.readStationInputIndex(); | ||
subwayService.addSubwayStation(inputLine, inputStation, inputIndex); | ||
} | ||
if (sectionCommand.equals(SectionCommand.DELETE)) { | ||
final String inputLine = inputView.readDeleteLineName(); | ||
subwayService.deleteSubwayLine(inputLine); | ||
} | ||
if (sectionCommand.equals(SectionCommand.BACK)) { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
private void manageLine() { | ||
while (true) { | ||
outputView.printLineManageView(); | ||
final String lineManageCommand = inputView.readCommand(); | ||
final LineCommand lineCommand = LineCommand.from(lineManageCommand); | ||
if (lineCommand.equals(LineCommand.SAVE)) { | ||
final String inputName = inputView.readSaveLineName(); | ||
final String inputLineStartStationName = inputView.readLineStartStationName(); | ||
final String inputLineEndStationName = inputView.readLineEndStatationName(); | ||
subwayService.saveLine(inputName, inputLineStartStationName, inputLineEndStationName); | ||
outputView.printSubwayAddSuccess(); | ||
} | ||
if (lineCommand.equals(LineCommand.DELETE)) { | ||
final String inputLineName = inputView.readDeleteLineName(); | ||
subwayService.deleteLine(inputLineName); | ||
outputView.printSubwayDeleteSuccess(); | ||
} | ||
if (lineCommand.equals(LineCommand.SELECT)) { | ||
List<String> lineNames = subwayService.getAllLine(); | ||
outputView.printLines(lineNames); | ||
} | ||
if (lineCommand.equals(LineCommand.BACK)) { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
private void manageStation() { | ||
while (true) { | ||
outputView.printStationManageView(); | ||
final String stationManageCommand = inputView.readCommand(); | ||
final StationCommand stationCommand = StationCommand.from(stationManageCommand); | ||
if (stationCommand.equals(StationCommand.SAVE)) { | ||
final String input = inputView.readSaveStationName(); | ||
subwayService.saveStation(input); | ||
} | ||
if (stationCommand.equals(StationCommand.DELETE)) { | ||
final String input = inputView.readDeleteStationName(); | ||
subwayService.deleteStation(input); | ||
} | ||
if (stationCommand.equals(StationCommand.SELECT)) { | ||
final List<String> stationsName = subwayService.getAllStations(); | ||
outputView.printStations(stationsName); | ||
} | ||
if (stationCommand.equals(StationCommand.BACK)) { | ||
break; | ||
} | ||
} | ||
} | ||
} |
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.
특정 값을 필터링한 이후, findAny()를 통해 값을 찾고있어요.
findAny()를 하게되면 필터링한 값들 중 for과 같은 반복을 통해 내부 필터링된 값을 스캔하여 찾는다고 생각했어요.
그것보다 현재 해당 메서드에서 기대하는건 내가 눌렀던 커맨드 키를 찾는것이니 findFirst가 더 적절하겠어요.
또한, from 이라는 메서드는 특정 값을 통한 인스턴스 생성을 기대하는데, 내부 동작에서는 필터링을 통한 "내가 선택한 커맨드 키"를 찾는과정이 더 강하다고 느껴졌어요.
해당 메서드명도 적절하게 수정하면 좋겠어요.
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.
결국 인스턴스를 반환하는 형식이 되버려 정적펙토리 메서드 네이밍 컨벤션인
from()
을 사용했습니다. 말씀해 주신것처럼 무슨 과정을 처리하는지 고려하는게 좋은거 같네요ps. 혹시 메서드명을 적절하게 선정하는 팁같은게 있으신가요?? 🤔🤔
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.
추가적으로 findAny 내부를 들어가서 살펴보시면 아래와 같은 내용을 찾아보실 수 있어요.
해당 사진을 참고하시면 답을 얻으실 수 있을수도 있겠네요.