From 0fa335be43d7b03ab77ee5cc65bf944606c5fbf7 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 10:04:46 +0900 Subject: [PATCH 01/45] =?UTF-8?q?docs:=200.=20=EC=84=A4=EA=B3=84=20-=20[so?= =?UTF-8?q?lving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=20-=20[README.md]=20=ED=92=80=EC=9D=B4=20=EA=B3=BC=EC=A0=95=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 63 ++++++++++++++++++++++++++++++++++++++ README.md | 4 +++ 2 files changed, 67 insertions(+) create mode 100644 .github/solving_process.md diff --git a/.github/solving_process.md b/.github/solving_process.md new file mode 100644 index 000000000..84b0986ad --- /dev/null +++ b/.github/solving_process.md @@ -0,0 +1,63 @@ +# ๐Ÿง ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ฒฝ๋กœ ์กฐํšŒ ๋ฏธ์…˜ + +[์šฐ์•„ํ•œํ…Œํฌ์ฝ”์Šค](https://github.com/woowacourse) precourse ๋ฌธ์ œ +์ค‘ [์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ฒฝ๋กœ ์กฐํšŒ ๋ฏธ์…˜](https://github.com/woowacourse/java-subway-path-precourse) ํ’€์ด ๊ธฐ๋กํ•˜๊ธฐ. + +DDD ๊ตฌ์กฐ์™€ MVC ํŒจํ„ด์„ ์ ์šฉํ•˜์—ฌ TDD ๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœํ•˜๊ณ , ์ž…์ถœ๋ ฅ ๋ฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋ถ€ํ•ฉํ•˜๋„๋ก ํ’€์–ด ๋ณผ ์˜ˆ์ •. + +## 0. ์„ค๊ณ„ + +### application + +| ๋น„์ฆˆ๋‹ˆ์Šค | ๊ธฐ๋Šฅ | +|:-------:|:------------------------------------------------------------------| +| section | - ๊ตฌ๊ฐ„ CRUD
- ๊ทธ๋ž˜ํ”„ ๋…ธ๋“œ ์ถ”๊ฐ€
- ์ตœ๋‹จ๊ฑฐ๋ฆฌ ๊ฒฝ๋กœ ๊ตฌํ•˜๊ธฐ
- ์ตœ์†Œ์‹œ๊ฐ„ ๊ฒฝ๋กœ ๊ตฌํ•˜๊ธฐ | + +### domain + +| ๋น„์ฆˆ๋‹ˆ์Šค | ๊ธฐ๋Šฅ | +|:-------:|:-----------------------| +| line | - ๋…ธ์„  ๊ฐ์ฒด
- ๋…ธ์„  CRUD | +| section | - ๊ตฌ๊ฐ„ ๊ฐ์ฒด
- ๊ตฌ๊ฐ„ CRUD | +| station | - ์—ญ ๊ฐ์ฒด
- ์—ญ CRUD | + +### infrastructure + +| ํด๋ž˜์Šค | ๊ธฐ๋Šฅ | +|:-------------:|:------------------------| +| FileParser | - abstract
- ํŒŒ์ผ ๊ฒ€์ฆ | +| XmlFileParser | - xml ํŒŒ์ผ ๋กœ๋“œ ๋ฐ ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ | + +### presentation + +| ํด๋ž˜์Šค | ๊ธฐ๋Šฅ | +|:-------------------:|:-------------------------------| +| ViewController | - interface | +| IntroViewController | - ๋„๋ฉ”์ธ ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™”
- ์ธํŠธ๋กœ ํ™”๋ฉด ์ œ์–ด | +| MainViewController | - ๋ฉ”์ธ ํ™”๋ฉด ์ œ์–ด | +| PathViewController | - ๊ฒฝ๋กœ ๊ธฐ์ค€(ํ™”๋ฉด) ์ œ์–ด | +| LineController | - ๋…ธ์„  ๋น„์ฆˆ๋‹ˆ์Šค ์ฒ˜๋ฆฌ | +| SectionController | - ๊ตฌ๊ฐ„ ๋น„์ฆˆ๋‹ˆ์Šค ์ฒ˜๋ฆฌ | +| StationController | - ์—ญ ๋น„์ฆˆ๋‹ˆ์Šค ์ฒ˜๋ฆฌ | +| ShortCostController | - ์ตœ๋‹จ(์ตœ์†Œ) ๊ฒฝ๋กœ ์ฒ˜๋ฆฌ | + +### ui + +| ํด๋ž˜์Šค | ๊ธฐ๋Šฅ | +|:-------:|:------------| +| Console | - ์ฝ˜์†” ์ž…์ถœ๋ ฅ ์ฒ˜๋ฆฌ | + +### view + +| ํด๋ž˜์Šค | ๊ธฐ๋Šฅ | +|:-----------------:|:------------------------------------------------| +| View | - interface | +| MenuView | - ๋ฉ”๋‰ด ์ถœ๋ ฅ
- ํ•ญ๋ชฉ ์ž…๋ ฅ
- ๋ฉ”๋‰ด ์„ ํƒ ์ด๋ฒคํŠธ ๋ฐœ์ƒ | +| Menu | - interface
- ๋ฉ”๋‰ด ๋ชฉ๋ก ์กฐํšŒ
- ๋ช…๋ น์–ด ๊ธฐ์ค€ ๋‹จ๊ฑด ์กฐํšŒ | +| MenuEventRegister | - ๋ฉ”๋‰ด ์„ ํƒ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋“ฑ๋ก | + +### util + +| ํด๋ž˜์Šค | ๊ธฐ๋Šฅ | +|:----------:|:------------| +| Validation | - ๊ณตํ†ต ์œ ํšจ์„ฑ ๊ฒ€์ฆ | \ No newline at end of file diff --git a/README.md b/README.md index bb0c84ebb..4b9c0ceb9 100644 --- a/README.md +++ b/README.md @@ -251,3 +251,7 @@ public void getDijkstraShortestPath() { ## ๐Ÿ“ License This project is [MIT](https://github.com/woowacourse/java-subway-path-precourse/blob/master/LICENSE.md) licensed. + +## ๐Ÿงฉ ํ’€์ด ๊ณผ์ • + +[solving_process.md](https://github.com/jaehyeonjung0613/java-subway-path-precourse/blob/main/.github/solving_process.md) \ No newline at end of file From 5443b27ce895075a93796ea3fd5118f5420833a8 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 10:18:53 +0900 Subject: [PATCH 02/45] =?UTF-8?q?rename:=20DDD=20=EA=B5=AC=EC=A1=B0?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/subway/domain/{ => line}/Line.java | 2 +- src/main/java/subway/domain/{ => line}/LineRepository.java | 2 +- src/main/java/subway/domain/{ => station}/Station.java | 2 +- .../java/subway/domain/{ => station}/StationRepository.java | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) rename src/main/java/subway/domain/{ => line}/Line.java (87%) rename src/main/java/subway/domain/{ => line}/LineRepository.java (95%) rename src/main/java/subway/domain/{ => station}/Station.java (86%) rename src/main/java/subway/domain/{ => station}/StationRepository.java (95%) diff --git a/src/main/java/subway/domain/Line.java b/src/main/java/subway/domain/line/Line.java similarity index 87% rename from src/main/java/subway/domain/Line.java rename to src/main/java/subway/domain/line/Line.java index f4d738d5a..bb1a937bb 100644 --- a/src/main/java/subway/domain/Line.java +++ b/src/main/java/subway/domain/line/Line.java @@ -1,4 +1,4 @@ -package subway.domain; +package subway.domain.line; public class Line { private String name; diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/line/LineRepository.java similarity index 95% rename from src/main/java/subway/domain/LineRepository.java rename to src/main/java/subway/domain/line/LineRepository.java index 2c4a723c9..89982c4d8 100644 --- a/src/main/java/subway/domain/LineRepository.java +++ b/src/main/java/subway/domain/line/LineRepository.java @@ -1,4 +1,4 @@ -package subway.domain; +package subway.domain.line; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/subway/domain/Station.java b/src/main/java/subway/domain/station/Station.java similarity index 86% rename from src/main/java/subway/domain/Station.java rename to src/main/java/subway/domain/station/Station.java index bdb142590..ef99213b8 100644 --- a/src/main/java/subway/domain/Station.java +++ b/src/main/java/subway/domain/station/Station.java @@ -1,4 +1,4 @@ -package subway.domain; +package subway.domain.station; public class Station { private String name; diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/station/StationRepository.java similarity index 95% rename from src/main/java/subway/domain/StationRepository.java rename to src/main/java/subway/domain/station/StationRepository.java index 8ed9d103f..4f8c0482f 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/station/StationRepository.java @@ -1,4 +1,4 @@ -package subway.domain; +package subway.domain.station; import java.util.ArrayList; import java.util.Collections; @@ -24,3 +24,4 @@ public static void deleteAll() { stations.clear(); } } + From 80172e22a91b24daa2585218aa3fc4038eb123ad Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 13:42:50 +0900 Subject: [PATCH 03/45] feat: 1. Line CRUD --- src/main/java/subway/domain/line/LineDTO.java | 22 +++++++++ .../subway/domain/line/LineRepository.java | 9 ++++ .../java/subway/domain/line/LineService.java | 28 ++++++++++++ .../subway/presentation/LineController.java | 13 ++++++ .../java/subway/domain/line/LineDTOTest.java | 16 +++++++ .../domain/line/LineRepositoryTest.java | 26 +++++++++++ .../subway/domain/line/LineServiceTest.java | 45 +++++++++++++++++++ 7 files changed, 159 insertions(+) create mode 100644 src/main/java/subway/domain/line/LineDTO.java create mode 100644 src/main/java/subway/domain/line/LineService.java create mode 100644 src/main/java/subway/presentation/LineController.java create mode 100644 src/test/java/subway/domain/line/LineDTOTest.java create mode 100644 src/test/java/subway/domain/line/LineRepositoryTest.java create mode 100644 src/test/java/subway/domain/line/LineServiceTest.java diff --git a/src/main/java/subway/domain/line/LineDTO.java b/src/main/java/subway/domain/line/LineDTO.java new file mode 100644 index 000000000..6535443cf --- /dev/null +++ b/src/main/java/subway/domain/line/LineDTO.java @@ -0,0 +1,22 @@ +package subway.domain.line; + +public class LineDTO { + private static final String LINE_NAME_ESSENTIAL_MESSAGE = "๋…ธ์„  ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + + private final String name; + + public LineDTO(String name) { + this.validate(name); + this.name = name; + } + + private void validate(String name) { + if(name == null || name.trim().isEmpty()) { + throw new IllegalArgumentException(LINE_NAME_ESSENTIAL_MESSAGE); + } + } + + public String getName() { + return this.name; + } +} diff --git a/src/main/java/subway/domain/line/LineRepository.java b/src/main/java/subway/domain/line/LineRepository.java index 89982c4d8..caeb6af90 100644 --- a/src/main/java/subway/domain/line/LineRepository.java +++ b/src/main/java/subway/domain/line/LineRepository.java @@ -4,10 +4,15 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; public class LineRepository { private static final List lines = new ArrayList<>(); + public static Optional findByName(String name) { + return lines.stream().filter(line -> line.getName().equals(name)).findFirst(); + } + public static List lines() { return Collections.unmodifiableList(lines); } @@ -23,4 +28,8 @@ public static boolean deleteLineByName(String name) { public static void deleteAll() { lines.clear(); } + + public static boolean exists(Line other) { + return lines.stream().anyMatch(line -> line.getName().equals(other.getName())); + } } diff --git a/src/main/java/subway/domain/line/LineService.java b/src/main/java/subway/domain/line/LineService.java new file mode 100644 index 000000000..243c81a54 --- /dev/null +++ b/src/main/java/subway/domain/line/LineService.java @@ -0,0 +1,28 @@ +package subway.domain.line; + +import java.util.List; + +public class LineService { + private static final String NOT_EXISTS_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + private static final String ALREADY_EXISTS_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + + public Line findOneByName(String name) { + return LineRepository.findByName(name).orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_MESSAGE)); + } + + public List findAll() { + return LineRepository.lines(); + } + + public void addLine(LineDTO lineDTO) { + Line line = new Line(lineDTO.getName()); + if (LineRepository.exists(line)) { + throw new IllegalArgumentException(ALREADY_EXISTS_MESSAGE); + } + LineRepository.addLine(line); + } + + public void deleteAll() { + LineRepository.deleteAll(); + } +} diff --git a/src/main/java/subway/presentation/LineController.java b/src/main/java/subway/presentation/LineController.java new file mode 100644 index 000000000..b1318dfd9 --- /dev/null +++ b/src/main/java/subway/presentation/LineController.java @@ -0,0 +1,13 @@ +package subway.presentation; + +import subway.domain.line.LineDTO; +import subway.domain.line.LineService; + +public class LineController { + private final LineService lineService = new LineService(); + + public void addLine(String lineName) { + LineDTO lineDTO = new LineDTO(lineName); + this.lineService.addLine(lineDTO); + } +} diff --git a/src/test/java/subway/domain/line/LineDTOTest.java b/src/test/java/subway/domain/line/LineDTOTest.java new file mode 100644 index 000000000..7f91e3eaf --- /dev/null +++ b/src/test/java/subway/domain/line/LineDTOTest.java @@ -0,0 +1,16 @@ +package subway.domain.line; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class LineDTOTest { + @Test + public void new__LineNameEssentialException() { + String message = "๋…ธ์„  ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new LineDTO(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + assertThatThrownBy(() -> new LineDTO("")).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} diff --git a/src/test/java/subway/domain/line/LineRepositoryTest.java b/src/test/java/subway/domain/line/LineRepositoryTest.java new file mode 100644 index 000000000..3a71f5177 --- /dev/null +++ b/src/test/java/subway/domain/line/LineRepositoryTest.java @@ -0,0 +1,26 @@ +package subway.domain.line; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class LineRepositoryTest { + @Test + public void exists() { + Line line = new Line("test"); + assertThat(LineRepository.exists(line)).isEqualTo(false); + LineRepository.addLine(line); + assertThat(LineRepository.exists(line)).isEqualTo(true); + LineRepository.deleteAll(); + } + + @Test + public void findByName() { + String name = "test"; + Line line = new Line(name); + assertThat(LineRepository.findByName(name)).isNotPresent(); + LineRepository.addLine(line); + assertThat(LineRepository.findByName(name)).isPresent(); + LineRepository.deleteAll(); + } +} diff --git a/src/test/java/subway/domain/line/LineServiceTest.java b/src/test/java/subway/domain/line/LineServiceTest.java new file mode 100644 index 000000000..ca568e097 --- /dev/null +++ b/src/test/java/subway/domain/line/LineServiceTest.java @@ -0,0 +1,45 @@ +package subway.domain.line; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class LineServiceTest { + private final LineService lineService = new LineService(); + + @Test + public void addLine() { + LineDTO lineDTO = new LineDTO("test"); + assertThat(this.lineService.findAll()).hasSize(0); + this.lineService.addLine(lineDTO); + assertThat(this.lineService.findAll()).hasSize(1); + this.lineService.deleteAll(); + } + + @Test + public void addLine__AlreadyExistsException() { + LineDTO lineDTO = new LineDTO("test"); + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + this.lineService.addLine(lineDTO); + assertThatThrownBy(() -> this.lineService.addLine(lineDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + this.lineService.deleteAll(); + } + + @Test + public void findOneByName() { + String name = "test"; + LineDTO lineDTO = new LineDTO(name); + this.lineService.addLine(lineDTO); + Line line = this.lineService.findOneByName(name); + assertThat(line.getName()).isEqualTo(name); + this.lineService.deleteAll(); + } + + @Test + public void findOneByName__NotExistsException() { + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> this.lineService.findOneByName("test")).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} From f591c30616b7613c71943fa004db55cdf316ee06 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 13:53:44 +0900 Subject: [PATCH 04/45] =?UTF-8?q?docs:=201.=20Line=20CRUD=20-=20[solving?= =?UTF-8?q?=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 283 ++++++++++++++++++++++++++++++++++++- 1 file changed, 282 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 84b0986ad..62f7d5105 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -60,4 +60,285 @@ DDD ๊ตฌ์กฐ์™€ MVC ํŒจํ„ด์„ ์ ์šฉํ•˜์—ฌ TDD ๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœํ•˜๊ณ , ์ž…์ถœ | ํด๋ž˜์Šค | ๊ธฐ๋Šฅ | |:----------:|:------------| -| Validation | - ๊ณตํ†ต ์œ ํšจ์„ฑ ๊ฒ€์ฆ | \ No newline at end of file +| Validation | - ๊ณตํ†ต ์œ ํšจ์„ฑ ๊ฒ€์ฆ | + +## 1. Line CRUD + +```java +// LineDTOTest.java + +package subway.domain.line; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class LineDTOTest { + @Test + public void new__LineNameEssentialException() { + String message = "๋…ธ์„  ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new LineDTO(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + assertThatThrownBy(() -> new LineDTO("")).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} +``` + +```java +// LineDTO.java + +package subway.domain.line; + +public class LineDTO { + private static final String LINE_NAME_ESSENTIAL_MESSAGE = "๋…ธ์„  ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + + private final String name; + + public LineDTO(String name) { + this.validate(name); + this.name = name; + } + + private void validate(String name) { + if (name == null || name.trim().isEmpty()) { + throw new IllegalArgumentException(LINE_NAME_ESSENTIAL_MESSAGE); + } + } + + public String getName() { + return this.name; + } +} +``` + +๋‹ค์–‘ํ•œ ๊ณ„์ธต์—์„œ ์“ฐ์ผ ๊ธฐ๋ณธ LineDTO ๊ตฌํ˜„. + +```java +// LineService.java + +package subway.domain.line; + +import java.util.List; + +public class LineService { +public List findAll() { +return LineRepository.lines(); +} + + public void deleteAll() { + LineRepository.deleteAll(); + } +} +``` + +๊ธฐ๋ณธ ์ „์ฒด ์กฐํšŒ ๋ฐ ์‚ญ์ œ ๊ธฐ๋Šฅ ์ƒ์„ฑ. + +### 1-1. CREATE + +```java +// LineRepositoryTest.java + +package subway.domain.line; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class LineRepositoryTest { + @Test + public void exists() { + Line line = new Line("test"); + assertThat(LineRepository.exists(line)).isEqualTo(false); + LineRepository.addLine(line); + assertThat(LineRepository.exists(line)).isEqualTo(true); + LineRepository.deleteAll(); + } +} +``` + +```java +// LineRepository.java + +package subway.domain.line; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class LineRepository { + public static boolean exists(Line other) { + return lines.stream().anyMatch(line -> line.getName().equals(other.getName())); + } +} +``` + +๋…ธ์„  ์ค‘๋ณต ์ƒ์„ฑ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ์ด๋ฆ„ ๊ธฐ์ค€์œผ๋กœ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// LineServiceTest.java + +package subway.domain.line; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class LineServiceTest { + private final LineService lineService = new LineService(); + + @Test + public void addLine() { + LineDTO lineDTO = new LineDTO("test"); + assertThat(lineService.findAll()).hasSize(0); + this.lineService.addLine(lineDTO); + assertThat(lineService.findAll()).hasSize(1); + this.lineService.deleteAll(); + } + + @Test + public void addLine__AlreadyExistsException() { + LineDTO lineDTO = new LineDTO("test"); + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + this.lineService.addLine(lineDTO); + assertThatThrownBy(() -> this.lineService.addLine(lineDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + this.lineService.deleteAll(); + } +} +``` + +```java +// LineService.java + +package subway.domain.line; + +import java.util.List; + +public class LineService { + private static final String ALREADY_EXISTS_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + + public void addLine(LineDTO lineDTO) { + Line line = new Line(lineDTO.getName()); + if (LineRepository.exists(line)) { + throw new IllegalArgumentException(ALREADY_EXISTS_MESSAGE); + } + LineRepository.addLine(line); + } +} +``` + +๋…ธ์„  ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// LineController.java + +package subway.presentation; + +import subway.domain.line.LineDTO; +import subway.domain.line.LineService; + +public class LineController { + private final LineService lineService = new LineService(); + + public void addLine(String lineName) { + LineDTO lineDTO = new LineDTO(lineName); + this.lineService.addLine(lineDTO); + } +} +``` + +์ œ์–ด ๊ณ„์ธต์— ๋…ธ์„  ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๋งคํ•‘. + +### 1-2. READ + +```java +// LineRepositoryTest.java + +package subway.domain; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.line.LineRepository; + +public class LineRepositoryTest { + @Test + public void findByName() { + String name = "test"; + Line line = new Line(name); + assertThat(LineRepository.findByName(name)).isNotPresent(); + LineRepository.addLine(line); + assertThat(LineRepository.findByName(name)).isPresent(); + LineRepository.deleteAll(); + } +} +``` + +```java +// LineRepository.java + +package subway.domain.line; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class LineRepository { + public static Optional findByName(String name) { + return lines.stream().filter(line -> line.getName().equals(name)).findFirst(); + } +} +``` + +```java +// LineServiceTest.java + +package subway.domain.line; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class LineServiceTest { + @Test + public void findOneByName() { + String name = "test"; + LineDTO lineDTO = new LineDTO(name); + this.lineService.addLine(lineDTO); + Line line = this.lineService.findOneByName(name); + assertThat(line.getName()).isEqualTo(name); + this.lineService.deleteAll(); + } + + @Test + public void findOneByName__NotExistsException() { + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> this.lineService.findOneByName("test")).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} +``` + +```java +// LineService.java + +package subway.domain.line; + +import java.util.List; + +public class LineService { + private static final String NOT_EXISTS_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + + public Line findOneByName(String name) { + return LineRepository.findByName(name).orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_MESSAGE)); + } +} +``` + +๋…ธ์„  ์ด๋ฆ„ ๊ธฐ์ค€ ๋‹จ๊ฑด ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file From 90b46160452d0f7694d486d32f2f0989c4a0dee1 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 14:23:11 +0900 Subject: [PATCH 05/45] feat: 2. Station CRUD --- .../subway/domain/station/StationDTO.java | 22 +++++++++ .../domain/station/StationRepository.java | 10 ++++- .../subway/domain/station/StationService.java | 29 ++++++++++++ .../presentation/StationController.java | 13 ++++++ .../subway/domain/station/StationDTOTest.java | 16 +++++++ .../domain/station/StationRepositoryTest.java | 26 +++++++++++ .../domain/station/StationServiceTest.java | 45 +++++++++++++++++++ 7 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/main/java/subway/domain/station/StationDTO.java create mode 100644 src/main/java/subway/domain/station/StationService.java create mode 100644 src/main/java/subway/presentation/StationController.java create mode 100644 src/test/java/subway/domain/station/StationDTOTest.java create mode 100644 src/test/java/subway/domain/station/StationRepositoryTest.java create mode 100644 src/test/java/subway/domain/station/StationServiceTest.java diff --git a/src/main/java/subway/domain/station/StationDTO.java b/src/main/java/subway/domain/station/StationDTO.java new file mode 100644 index 000000000..4b50534eb --- /dev/null +++ b/src/main/java/subway/domain/station/StationDTO.java @@ -0,0 +1,22 @@ +package subway.domain.station; + +public class StationDTO { + private static final String STATION_NAME_ESSENTIAL_MESSAGE = "์—ญ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + + private final String name; + + public StationDTO(String name) { + this.validate(name); + this.name = name; + } + + private void validate(String name) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException(STATION_NAME_ESSENTIAL_MESSAGE); + } + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/subway/domain/station/StationRepository.java b/src/main/java/subway/domain/station/StationRepository.java index 4f8c0482f..1abd77fb4 100644 --- a/src/main/java/subway/domain/station/StationRepository.java +++ b/src/main/java/subway/domain/station/StationRepository.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; public class StationRepository { private static final List stations = new ArrayList<>(); @@ -12,6 +13,10 @@ public static List stations() { return Collections.unmodifiableList(stations); } + public static Optional findByName(String name) { + return stations.stream().filter(station -> station.getName().equals(name)).findFirst(); + } + public static void addStation(Station station) { stations.add(station); } @@ -23,5 +28,8 @@ public static boolean deleteStation(String name) { public static void deleteAll() { stations.clear(); } -} + public static boolean exists(Station other) { + return stations().stream().anyMatch(station -> station.getName().equals(other.getName())); + } +} diff --git a/src/main/java/subway/domain/station/StationService.java b/src/main/java/subway/domain/station/StationService.java new file mode 100644 index 000000000..e92dc682a --- /dev/null +++ b/src/main/java/subway/domain/station/StationService.java @@ -0,0 +1,29 @@ +package subway.domain.station; + +import java.util.List; + +public class StationService { + private static final String NOT_EXISTS_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์—ญ์ž…๋‹ˆ๋‹ค."; + private static final String ALREADY_EXISTS_STATION_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ์—ญ์ž…๋‹ˆ๋‹ค."; + + public Station findOneByName(String name) { + return StationRepository.findByName(name) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_STATION_MESSAGE)); + } + + public List findAll() { + return StationRepository.stations(); + } + + public void addStation(StationDTO stationDTO) { + Station station = new Station(stationDTO.getName()); + if (StationRepository.exists(station)) { + throw new IllegalArgumentException(ALREADY_EXISTS_STATION_MESSAGE); + } + StationRepository.addStation(station); + } + + public void deleteAll() { + StationRepository.deleteAll(); + } +} diff --git a/src/main/java/subway/presentation/StationController.java b/src/main/java/subway/presentation/StationController.java new file mode 100644 index 000000000..a2aecfd72 --- /dev/null +++ b/src/main/java/subway/presentation/StationController.java @@ -0,0 +1,13 @@ +package subway.presentation; + +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class StationController { + private final StationService stationService = new StationService(); + + public void addStation(String name) { + StationDTO stationDTO = new StationDTO(name); + stationService.addStation(stationDTO); + } +} diff --git a/src/test/java/subway/domain/station/StationDTOTest.java b/src/test/java/subway/domain/station/StationDTOTest.java new file mode 100644 index 000000000..97173f4dc --- /dev/null +++ b/src/test/java/subway/domain/station/StationDTOTest.java @@ -0,0 +1,16 @@ +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class StationDTOTest { + @Test + public void new__StationNameEssentialException() { + String message = "์—ญ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new StationDTO(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + assertThatThrownBy(() -> new StationDTO("")).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} diff --git a/src/test/java/subway/domain/station/StationRepositoryTest.java b/src/test/java/subway/domain/station/StationRepositoryTest.java new file mode 100644 index 000000000..e06ea7c3b --- /dev/null +++ b/src/test/java/subway/domain/station/StationRepositoryTest.java @@ -0,0 +1,26 @@ +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class StationRepositoryTest { + @Test + public void exists() { + Station station = new Station("test"); + assertThat(StationRepository.exists(station)).isEqualTo(false); + StationRepository.addStation(station); + assertThat(StationRepository.exists(station)).isEqualTo(true); + StationRepository.deleteAll(); + } + + @Test + public void findByName() { + String name = "test"; + Station station = new Station(name); + assertThat(StationRepository.findByName(name)).isNotPresent(); + StationRepository.addStation(station); + assertThat(StationRepository.findByName(name)).isPresent(); + StationRepository.deleteAll(); + } +} diff --git a/src/test/java/subway/domain/station/StationServiceTest.java b/src/test/java/subway/domain/station/StationServiceTest.java new file mode 100644 index 000000000..ac149205a --- /dev/null +++ b/src/test/java/subway/domain/station/StationServiceTest.java @@ -0,0 +1,45 @@ +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class StationServiceTest { + private final StationService stationService = new StationService(); + + @Test + public void addStation() { + StationDTO stationDTO = new StationDTO("test"); + assertThat(this.stationService.findAll()).hasSize(0); + this.stationService.addStation(stationDTO); + assertThat(this.stationService.findAll()).hasSize(1); + this.stationService.deleteAll(); + } + + @Test + public void addStation__AlreadyExistsStationException() { + StationDTO stationDTO = new StationDTO("test"); + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ์—ญ์ž…๋‹ˆ๋‹ค."; + this.stationService.addStation(stationDTO); + assertThatThrownBy(() -> this.stationService.addStation(stationDTO)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + this.stationService.deleteAll(); + } + + @Test + public void findOneByName() { + String name = "test"; + StationDTO stationDTO = new StationDTO(name); + this.stationService.addStation(stationDTO); + Station station = this.stationService.findOneByName(name); + assertThat(station.getName()).isEqualTo(name); + this.stationService.deleteAll(); + } + + @Test + public void findOneByName__NotExistsStationException() { + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์—ญ์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> this.stationService.findOneByName("test")).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} From a56aa5918a41928437340375468e6bba33fae011 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 14:24:50 +0900 Subject: [PATCH 06/45] =?UTF-8?q?docs:=202.=20Station=20CRUD=20-=20[solvin?= =?UTF-8?q?g=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 283 ++++++++++++++++++++++++++++++++++++- 1 file changed, 282 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 62f7d5105..6938ac3cb 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -341,4 +341,285 @@ public class LineService { } ``` -๋…ธ์„  ์ด๋ฆ„ ๊ธฐ์ค€ ๋‹จ๊ฑด ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file +๋…ธ์„  ์ด๋ฆ„ ๊ธฐ์ค€ ๋‹จ๊ฑด ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +## 2. Station CRUD + +```java +// StationDTOTest.java + +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class StationDTOTest { + @Test + public void new__StationNameEssentialException() { + String message = "์—ญ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new StationDTO(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + assertThatThrownBy(() -> new StationDTO("")).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} +``` + +```java +// StationDTO.java + +package subway.domain.station; + +public class StationDTO { + private static final String STATION_NAME_ESSENTIAL_MESSAGE = "์—ญ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + + private final String name; + + public StationDTO(String name) { + this.validate(name); + this.name = name; + } + + private void validate(String name) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException(STATION_NAME_ESSENTIAL_MESSAGE); + } + } + + public String getName() { + return name; + } +} +``` + +๋‹ค์–‘ํ•œ ๊ณ„์ธต์—์„œ ์“ฐ์ผ ๊ธฐ๋ณธ StationDTO ๊ตฌํ˜„. + +```java +// StationService.java + +package subway.domain.station; + +import java.util.List; + +public class StationService { + public List findAll() { + return StationRepository.stations(); + } + + public void deleteAll() { + StationRepository.deleteAll(); + } +} + +``` + +๊ธฐ๋ณธ ์ „์ฒด ์กฐํšŒ ๋ฐ ์‚ญ์ œ ๊ธฐ๋Šฅ ์ƒ์„ฑ. + +### 2-1. CREATE + +```java +// StationRepositoryTest.java + +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class StationRepositoryTest { + @Test + public void exists() { + Station station = new Station("test"); + assertThat(StationRepository.exists(station)).isEqualTo(false); + StationRepository.addStation(station); + assertThat(StationRepository.exists(station)).isEqualTo(true); + StationRepository.deleteAll(); + } +} +``` + +```java +// StationRepository.java + +package subway.domain.station; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class StationRepository { + public static boolean exists(Station other) { + return stations().stream().anyMatch(station -> station.getName().equals(other.getName())); + } +} +``` + +์—ญ ์ค‘๋ณต ์ƒ์„ฑ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ์ด๋ฆ„ ๊ธฐ์ค€์œผ๋กœ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// StationServiceTest.java + +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class StationServiceTest { + private final StationService stationService = new StationService(); + + @Test + public void addStation() { + StationDTO stationDTO = new StationDTO("test"); + assertThat(this.stationService.findAll()).hasSize(0); + this.stationService.addStation(stationDTO); + assertThat(this.stationService.findAll()).hasSize(1); + this.stationService.deleteAll(); + } + + @Test + public void addStation__AlreadyExistsStationException() { + StationDTO stationDTO = new StationDTO("test"); + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ์—ญ์ž…๋‹ˆ๋‹ค."; + this.stationService.addStation(stationDTO); + assertThatThrownBy(() -> this.stationService.addStation(stationDTO)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + this.stationService.deleteAll(); + } +} +``` + +```java +// StationService.java + +package subway.domain.station; + +import java.util.List; + +public class StationService { + private static final String ALREADY_EXISTS_STATION_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ์—ญ์ž…๋‹ˆ๋‹ค."; + + public void addStation(StationDTO stationDTO) { + Station station = new Station(stationDTO.getName()); + if (StationRepository.exists(station)) { + throw new IllegalArgumentException(ALREADY_EXISTS_STATION_MESSAGE); + } + StationRepository.addStation(station); + } +} +``` + +์—ญ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// StationController.java + +package subway.presentation; + +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class StationController { + private final StationService stationService = new StationService(); + + public void addStation(String name) { + StationDTO stationDTO = new StationDTO(name); + stationService.addStation(stationDTO); + } +} +``` + +์ œ์–ด ๊ณ„์ธต์— ์—ญ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๋งคํ•‘. + +### 2-2. READ + +```java +// StationRepositoryTest.java + +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class StationRepositoryTest { + @Test + public void findByName() { + String name = "test"; + Station station = new Station(name); + assertThat(StationRepository.findByName(name)).isNotPresent(); + StationRepository.addStation(station); + assertThat(StationRepository.findByName(name)).isPresent(); + StationRepository.deleteAll(); + } +} +``` + +```java +// StationRepository.java + +package subway.domain.station; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class StationRepository { + public static Optional findByName(String name) { + return stations.stream().filter(station -> station.getName().equals(name)).findFirst(); + } +} +``` + +```java +// StationRepositoryTest.java + +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class StationServiceTest { + @Test + public void findOneByName() { + String name = "test"; + StationDTO stationDTO = new StationDTO(name); + this.stationService.addStation(stationDTO); + Station station = this.stationService.findOneByName(name); + assertThat(station.getName()).isEqualTo(name); + this.stationService.deleteAll(); + } + + @Test + public void findOneByName__NotExistsStationException() { + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์—ญ์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> this.stationService.findOneByName("test")).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} +``` + +```java +// StationService.java + +package subway.domain.station; + +import java.util.List; + +public class StationService { + private static final String NOT_EXISTS_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์—ญ์ž…๋‹ˆ๋‹ค."; + + public Station findOneByName(String name) { + return StationRepository.findByName(name) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_STATION_MESSAGE)); + } +} +``` + +์—ญ ์ด๋ฆ„ ๊ธฐ์ค€ ๋‹จ๊ฑด ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file From 9fc4be9eee730e6dd53c092bd8388d1c82566758 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 14:33:14 +0900 Subject: [PATCH 07/45] =?UTF-8?q?refactor:=201.=20Line=20CRUD=20-=20[solvi?= =?UTF-8?q?ng=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=88=98=EC=A0=95=20-?= =?UTF-8?q?=20[LineService.java]=20NOT=5FEXISTS=5FMESSAGE=20=E2=86=92=20NO?= =?UTF-8?q?T=5FEXISTS=5FLINE=5FMESSAGE,=20ALREADY=5FEXISTS=5FLINE=5FMESSAG?= =?UTF-8?q?E=20=E2=86=92=20ALREADY=5FEXISTS=5FLINE=5FMESSAGE=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=EB=B3=80=EA=B2=BD=20-=20[LineServiceTest.?= =?UTF-8?q?java]=20findOneByName=5F=5FNotExistsException=20=E2=86=92=20fin?= =?UTF-8?q?dOneByName=5F=5FNotExistsLineException,=20addLine=5FAlreadyExis?= =?UTF-8?q?tsException=20=E2=86=92=20addLine=5F=5FAlreadyExistsLineExcepti?= =?UTF-8?q?on=20=ED=95=A8=EC=88=98=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 8 ++++---- src/main/java/subway/domain/line/LineService.java | 8 ++++---- src/test/java/subway/domain/line/LineServiceTest.java | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 6938ac3cb..7fd4b7944 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -198,7 +198,7 @@ public class LineServiceTest { } @Test - public void addLine__AlreadyExistsException() { + public void addLine__AlreadyExistsLineException() { LineDTO lineDTO = new LineDTO("test"); String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; this.lineService.addLine(lineDTO); @@ -217,7 +217,7 @@ package subway.domain.line; import java.util.List; public class LineService { - private static final String ALREADY_EXISTS_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + private static final String ALREADY_EXISTS_LINE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; public void addLine(LineDTO lineDTO) { Line line = new Line(lineDTO.getName()); @@ -317,7 +317,7 @@ public class LineServiceTest { } @Test - public void findOneByName__NotExistsException() { + public void findOneByName__NotExistsLineException() { String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> this.lineService.findOneByName("test")).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); @@ -333,7 +333,7 @@ package subway.domain.line; import java.util.List; public class LineService { - private static final String NOT_EXISTS_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_LINE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; public Line findOneByName(String name) { return LineRepository.findByName(name).orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_MESSAGE)); diff --git a/src/main/java/subway/domain/line/LineService.java b/src/main/java/subway/domain/line/LineService.java index 243c81a54..23a7a3b4e 100644 --- a/src/main/java/subway/domain/line/LineService.java +++ b/src/main/java/subway/domain/line/LineService.java @@ -3,11 +3,11 @@ import java.util.List; public class LineService { - private static final String NOT_EXISTS_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; - private static final String ALREADY_EXISTS_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_LINE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; + private static final String ALREADY_EXISTS_LINE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; public Line findOneByName(String name) { - return LineRepository.findByName(name).orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_MESSAGE)); + return LineRepository.findByName(name).orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_LINE_MESSAGE)); } public List findAll() { @@ -17,7 +17,7 @@ public List findAll() { public void addLine(LineDTO lineDTO) { Line line = new Line(lineDTO.getName()); if (LineRepository.exists(line)) { - throw new IllegalArgumentException(ALREADY_EXISTS_MESSAGE); + throw new IllegalArgumentException(ALREADY_EXISTS_LINE_MESSAGE); } LineRepository.addLine(line); } diff --git a/src/test/java/subway/domain/line/LineServiceTest.java b/src/test/java/subway/domain/line/LineServiceTest.java index ca568e097..102597f85 100644 --- a/src/test/java/subway/domain/line/LineServiceTest.java +++ b/src/test/java/subway/domain/line/LineServiceTest.java @@ -17,7 +17,7 @@ public void addLine() { } @Test - public void addLine__AlreadyExistsException() { + public void addLine__AlreadyExistsLineException() { LineDTO lineDTO = new LineDTO("test"); String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; this.lineService.addLine(lineDTO); @@ -37,7 +37,7 @@ public void findOneByName() { } @Test - public void findOneByName__NotExistsException() { + public void findOneByName__NotExistsLineException() { String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ๋…ธ์„ ์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> this.lineService.findOneByName("test")).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); From 24830ef5ddaa1f83735b3b24dc797e658dbef131 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 17:41:40 +0900 Subject: [PATCH 08/45] feat: 3. Section CRUD --- .../application/section/dto/SectionDTO.java | 69 +++++++++++++++++++ .../section/service/SectionService.java | 39 +++++++++++ src/main/java/subway/domain/line/Line.java | 26 ++++++- .../java/subway/domain/section/Section.java | 40 +++++++++++ .../domain/section/SectionRepository.java | 27 ++++++++ .../java/subway/domain/station/Station.java | 26 ++++++- .../presentation/SectionController.java | 46 +++++++++++++ src/main/java/subway/util/Validation.java | 12 ++++ .../section/dto/SectionDTOTest.java | 37 ++++++++++ .../section/service/SectionServiceTest.java | 63 +++++++++++++++++ .../java/subway/domain/line/LineTest.java | 33 +++++++++ .../domain/section/SectionRepositoryTest.java | 22 ++++++ .../subway/domain/station/StationTest.java | 33 +++++++++ .../presentation/SectionControllerTest.java | 63 +++++++++++++++++ src/test/java/subway/util/ValidationTest.java | 14 ++++ 15 files changed, 546 insertions(+), 4 deletions(-) create mode 100644 src/main/java/subway/application/section/dto/SectionDTO.java create mode 100644 src/main/java/subway/application/section/service/SectionService.java create mode 100644 src/main/java/subway/domain/section/Section.java create mode 100644 src/main/java/subway/domain/section/SectionRepository.java create mode 100644 src/main/java/subway/presentation/SectionController.java create mode 100644 src/main/java/subway/util/Validation.java create mode 100644 src/test/java/subway/application/section/dto/SectionDTOTest.java create mode 100644 src/test/java/subway/application/section/service/SectionServiceTest.java create mode 100644 src/test/java/subway/domain/line/LineTest.java create mode 100644 src/test/java/subway/domain/section/SectionRepositoryTest.java create mode 100644 src/test/java/subway/domain/station/StationTest.java create mode 100644 src/test/java/subway/presentation/SectionControllerTest.java create mode 100644 src/test/java/subway/util/ValidationTest.java diff --git a/src/main/java/subway/application/section/dto/SectionDTO.java b/src/main/java/subway/application/section/dto/SectionDTO.java new file mode 100644 index 000000000..056cbac4f --- /dev/null +++ b/src/main/java/subway/application/section/dto/SectionDTO.java @@ -0,0 +1,69 @@ +package subway.application.section.dto; + +import subway.domain.line.LineDTO; +import subway.domain.station.StationDTO; + +public class SectionDTO { + private static final String SECTION_ADDING_LINE_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ๋…ธ์„  ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + + private final LineDTO lineDTO; + private final StationDTO sourceDTO; + private final StationDTO sinkDTO; + private int distance; + private int time; + + public SectionDTO(LineDTO lineDTO, StationDTO sourceDTO, StationDTO sinkDTO) { + this(lineDTO, sourceDTO, sinkDTO, 0, 0); + } + + public SectionDTO(LineDTO lineDTO, StationDTO sourceDTO, StationDTO sinkDTO, int distance, int time) { + this.validate(lineDTO, sourceDTO, sinkDTO); + this.lineDTO = lineDTO; + this.sourceDTO = sourceDTO; + this.sinkDTO = sinkDTO; + this.distance = distance; + this.time = time; + } + + private void validate(LineDTO lineDTO, StationDTO sourceDTO, StationDTO sinkDTO) { + if (lineDTO == null) { + throw new IllegalArgumentException(SECTION_ADDING_LINE_INFO_ESSENTIAL_MESSAGE); + } + if (sourceDTO == null) { + throw new IllegalArgumentException(SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE); + } + if (sinkDTO == null) { + throw new IllegalArgumentException(SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE); + } + } + + public LineDTO getLineDTO() { + return lineDTO; + } + + public StationDTO getSourceDTO() { + return sourceDTO; + } + + public StationDTO getSinkDTO() { + return sinkDTO; + } + + public int getDistance() { + return distance; + } + + public void setDistance(int distance) { + this.distance = distance; + } + + public int getTime() { + return time; + } + + public void setTime(int time) { + this.time = time; + } +} diff --git a/src/main/java/subway/application/section/service/SectionService.java b/src/main/java/subway/application/section/service/SectionService.java new file mode 100644 index 000000000..9114152e8 --- /dev/null +++ b/src/main/java/subway/application/section/service/SectionService.java @@ -0,0 +1,39 @@ +package subway.application.section.service; + +import java.util.List; + +import subway.application.section.dto.SectionDTO; +import subway.domain.line.Line; +import subway.domain.line.LineService; +import subway.domain.section.Section; +import subway.domain.section.SectionRepository; +import subway.domain.station.Station; +import subway.domain.station.StationService; + +public class SectionService { + private static final String ALREADY_EXISTS_SECTION_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ตฌ๊ฐ„์ž…๋‹ˆ๋‹ค."; + + private final LineService lineService = new LineService(); + private final StationService stationService = new StationService(); + + public List
findAll() { + return SectionRepository.sections(); + } + + public void addSection(SectionDTO sectionDTO) { + Line line = this.lineService.findOneByName(sectionDTO.getLineDTO().getName()); + Station source = this.stationService.findOneByName(sectionDTO.getSourceDTO().getName()); + Station sink = this.stationService.findOneByName(sectionDTO.getSinkDTO().getName()); + Section section = new Section(line, source, sink, sectionDTO.getDistance(), sectionDTO.getTime()); + if (SectionRepository.exists(section)) { + throw new IllegalArgumentException(ALREADY_EXISTS_SECTION_MESSAGE); + } + SectionRepository.addSection(section); + line.addSection(section); + source.addSection(section); + } + + public void deleteAll() { + SectionRepository.deleteAll(); + } +} diff --git a/src/main/java/subway/domain/line/Line.java b/src/main/java/subway/domain/line/Line.java index bb1a937bb..7e2ac920b 100644 --- a/src/main/java/subway/domain/line/Line.java +++ b/src/main/java/subway/domain/line/Line.java @@ -1,7 +1,16 @@ package subway.domain.line; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import subway.domain.section.Section; + public class Line { - private String name; + private static final String SECTION_ADDING_OTHER_LINE_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ๋…ธ์„ ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + + private final String name; + private final List
sectionList = new ArrayList<>(); public Line(String name) { this.name = name; @@ -11,5 +20,18 @@ public String getName() { return name; } - // ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ + public List
getSectionList() { + return Collections.unmodifiableList(this.sectionList); + } + + public void addSection(Section section) { + this.validateSection(section); + this.sectionList.add(section); + } + + private void validateSection(Section section) { + if(this != section.getLine()) { + throw new IllegalArgumentException(SECTION_ADDING_OTHER_LINE_RECEIVE_MESSAGE); + } + } } diff --git a/src/main/java/subway/domain/section/Section.java b/src/main/java/subway/domain/section/Section.java new file mode 100644 index 000000000..d2f11bb30 --- /dev/null +++ b/src/main/java/subway/domain/section/Section.java @@ -0,0 +1,40 @@ +package subway.domain.section; + +import subway.domain.line.Line; +import subway.domain.station.Station; + +public class Section { + private final Line line; + private final Station source; + private final Station sink; + private final int distance; + private final int time; + + public Section(Line line, Station source, Station sink, int distance, int time) { + this.line = line; + this.source = source; + this.sink = sink; + this.distance = distance; + this.time = time; + } + + public Line getLine() { + return line; + } + + public Station getSource() { + return source; + } + + public Station getSink() { + return sink; + } + + public int getDistance() { + return distance; + } + + public int getTime() { + return time; + } +} diff --git a/src/main/java/subway/domain/section/SectionRepository.java b/src/main/java/subway/domain/section/SectionRepository.java new file mode 100644 index 000000000..c115f6554 --- /dev/null +++ b/src/main/java/subway/domain/section/SectionRepository.java @@ -0,0 +1,27 @@ +package subway.domain.section; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class SectionRepository { + private static final List
sections = new ArrayList<>(); + + public static List
sections() { + return Collections.unmodifiableList(sections); + } + + public static void addSection(Section section) { + sections.add(section); + } + + public static void deleteAll() { + sections.clear(); + } + + public static boolean exists(Section other) { + return sections.stream() + .anyMatch(section -> section.getLine() == other.getLine() && section.getSource() == other.getSource() + && section.getSink() == other.getSink()); + } +} diff --git a/src/main/java/subway/domain/station/Station.java b/src/main/java/subway/domain/station/Station.java index ef99213b8..4edcd1b5b 100644 --- a/src/main/java/subway/domain/station/Station.java +++ b/src/main/java/subway/domain/station/Station.java @@ -1,7 +1,16 @@ package subway.domain.station; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import subway.domain.section.Section; + public class Station { - private String name; + private static final String SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + + private final String name; + private final List
sectionList = new ArrayList<>(); public Station(String name) { this.name = name; @@ -11,5 +20,18 @@ public String getName() { return name; } - // ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„ + public List
getSectionList() { + return Collections.unmodifiableList(this.sectionList); + } + + public void addSection(Section section) { + this.validateSection(section); + this.sectionList.add(section); + } + + public void validateSection(Section section) { + if(this != section.getSource()) { + throw new IllegalArgumentException(SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE); + } + } } diff --git a/src/main/java/subway/presentation/SectionController.java b/src/main/java/subway/presentation/SectionController.java new file mode 100644 index 000000000..f30a24745 --- /dev/null +++ b/src/main/java/subway/presentation/SectionController.java @@ -0,0 +1,46 @@ +package subway.presentation; + +import subway.application.section.dto.SectionDTO; +import subway.application.section.service.SectionService; +import subway.domain.line.LineDTO; +import subway.domain.station.StationDTO; +import subway.util.Validation; + +public class SectionController { + private static final String INPUT_ESSENTIAL_DISTANCE_MESSAGE = "๊ฑฐ๋ฆฌ ์ž…๋ ฅ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String ONLY_POSSIBLE_NUMERIC_INPUT_DISTANCE_MESSAGE = "๊ฑฐ๋ฆฌ๋Š” ์ˆซ์ž ํ˜•์‹์˜ ์ž…๋ ฅ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."; + private static final String INPUT_ESSENTIAL_TIME_MESSAGE = "์‹œ๊ฐ„ ์ž…๋ ฅ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String ONLY_POSSIBLE_NUMERIC_INPUT_TIME_MESSAGE = "์‹œ๊ฐ„์€ ์ˆซ์ž ํ˜•์‹์˜ ์ž…๋ ฅ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."; + + private final SectionService sectionService = new SectionService(); + + public void addSection(String lineName, String sourceName, String sinkName, String _distance, String _time) { + LineDTO lineDTO = new LineDTO(lineName); + StationDTO sourceDTO = new StationDTO(sourceName); + StationDTO sinkDTO = new StationDTO(sinkName); + this.validateDistance(_distance); + int distance = Integer.parseInt(_distance); + this.validateTime(_time); + int time = Integer.parseInt(_time); + SectionDTO sectionDTO = new SectionDTO(lineDTO, sourceDTO, sinkDTO, distance, time); + this.sectionService.addSection(sectionDTO); + } + + private void validateDistance(String distance) { + if(distance == null || distance.trim().isEmpty()) { + throw new IllegalArgumentException(INPUT_ESSENTIAL_DISTANCE_MESSAGE); + } + if (!Validation.isNumeric(distance)) { + throw new IllegalArgumentException(ONLY_POSSIBLE_NUMERIC_INPUT_DISTANCE_MESSAGE); + } + } + + private void validateTime(String time) { + if(time == null || time.trim().isEmpty()) { + throw new IllegalArgumentException(INPUT_ESSENTIAL_TIME_MESSAGE); + } + if (!Validation.isNumeric(time)) { + throw new IllegalArgumentException(ONLY_POSSIBLE_NUMERIC_INPUT_TIME_MESSAGE); + } + } +} diff --git a/src/main/java/subway/util/Validation.java b/src/main/java/subway/util/Validation.java new file mode 100644 index 000000000..1b265efe2 --- /dev/null +++ b/src/main/java/subway/util/Validation.java @@ -0,0 +1,12 @@ +package subway.util; + +import java.util.regex.Pattern; + +public final class Validation { + private Validation() { + } + + public static boolean isNumeric(String str) { + return str != null && !str.isEmpty() && Pattern.matches("^[0-9]*$", str); + } +} diff --git a/src/test/java/subway/application/section/dto/SectionDTOTest.java b/src/test/java/subway/application/section/dto/SectionDTOTest.java new file mode 100644 index 000000000..559067d38 --- /dev/null +++ b/src/test/java/subway/application/section/dto/SectionDTOTest.java @@ -0,0 +1,37 @@ +package subway.application.section.dto; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.LineDTO; +import subway.domain.station.StationDTO; + +public class SectionDTOTest { + @Test + public void new__SectionAddingLineInfoEssentialException() { + StationDTO sourceDTO = new StationDTO("source"); + StationDTO sinkDTO = new StationDTO("sink"); + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ๋…ธ์„  ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new SectionDTO(null, sourceDTO, sinkDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void new__SectionAddingSourceStationInfoEssentialException() { + LineDTO lineDTO = new LineDTO("line"); + StationDTO sinkDTO = new StationDTO("sink"); + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new SectionDTO(lineDTO, null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void new__SectionAddingSinkStationInfoEssentialException() { + LineDTO lineDTO = new LineDTO("line"); + StationDTO sourceDTO = new StationDTO("source"); + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new SectionDTO(lineDTO, sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} diff --git a/src/test/java/subway/application/section/service/SectionServiceTest.java b/src/test/java/subway/application/section/service/SectionServiceTest.java new file mode 100644 index 000000000..09e78c214 --- /dev/null +++ b/src/test/java/subway/application/section/service/SectionServiceTest.java @@ -0,0 +1,63 @@ +package subway.application.section.service; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import subway.application.section.dto.SectionDTO; +import subway.domain.line.Line; +import subway.domain.line.LineDTO; +import subway.domain.line.LineService; +import subway.domain.station.Station; +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class SectionServiceTest { + private final LineDTO lineDTO = new LineDTO("line"); + private final StationDTO sourceDTO = new StationDTO("source"); + private final StationDTO sinkDTO = new StationDTO("sink"); + + private final LineService lineService = new LineService(); + private final StationService stationService = new StationService(); + private final SectionService sectionService = new SectionService(); + + @BeforeEach + public void setup() { + this.lineService.addLine(lineDTO); + this.stationService.addStation(sourceDTO); + this.stationService.addStation(sinkDTO); + } + + @Test + public void addSection() { + Line line = this.lineService.findOneByName(lineDTO.getName()); + Station source = this.stationService.findOneByName(sourceDTO.getName()); + SectionDTO sectionDTO = new SectionDTO(lineDTO, sourceDTO, sinkDTO); + assertThat(this.sectionService.findAll()).hasSize(0); + assertThat(line.getSectionList()).hasSize(0); + assertThat(source.getSectionList()).hasSize(0); + this.sectionService.addSection(sectionDTO); + assertThat(this.sectionService.findAll()).hasSize(1); + assertThat(line.getSectionList()).hasSize(1); + assertThat(source.getSectionList()).hasSize(1); + } + + @Test + public void addSection__AlreadyExistsSectionException() { + SectionDTO sectionDTO = new SectionDTO(lineDTO, sourceDTO, sinkDTO); + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ตฌ๊ฐ„์ž…๋‹ˆ๋‹ค."; + this.sectionService.addSection(sectionDTO); + assertThatThrownBy(() -> this.sectionService.addSection(sectionDTO)).isInstanceOf( + IllegalArgumentException.class) + .hasMessage(message); + } + + @AfterEach + public void init() { + lineService.deleteAll(); + stationService.deleteAll(); + sectionService.deleteAll(); + } +} diff --git a/src/test/java/subway/domain/line/LineTest.java b/src/test/java/subway/domain/line/LineTest.java new file mode 100644 index 000000000..6b476159e --- /dev/null +++ b/src/test/java/subway/domain/line/LineTest.java @@ -0,0 +1,33 @@ +package subway.domain.line; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class LineTest { + @Test + public void addSection() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + Section section = new Section(line, source, sink, 0, 0); + assertThat(line.getSectionList()).hasSize(0); + line.addSection(section); + assertThat(line.getSectionList()).hasSize(1); + } + + @Test + public void addSection__SectionAddingOtherLineReceiveException() { + Line line = new Line("line"); + Line other = new Line("other"); + Station source = new Station("source"); + Station sink = new Station("sink"); + Section section = new Section(other, source, sink, 0, 0); + String message = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ๋…ธ์„ ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> line.addSection(section)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} diff --git a/src/test/java/subway/domain/section/SectionRepositoryTest.java b/src/test/java/subway/domain/section/SectionRepositoryTest.java new file mode 100644 index 000000000..7844f9aef --- /dev/null +++ b/src/test/java/subway/domain/section/SectionRepositoryTest.java @@ -0,0 +1,22 @@ +package subway.domain.section; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.station.Station; + +public class SectionRepositoryTest { + @Test + public void exists() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + Section section = new Section(line, source, sink, 0, 0); + assertThat(SectionRepository.exists(section)).isEqualTo(false); + SectionRepository.addSection(section); + assertThat(SectionRepository.exists(section)).isEqualTo(true); + SectionRepository.deleteAll(); + } +} diff --git a/src/test/java/subway/domain/station/StationTest.java b/src/test/java/subway/domain/station/StationTest.java new file mode 100644 index 000000000..8e124a692 --- /dev/null +++ b/src/test/java/subway/domain/station/StationTest.java @@ -0,0 +1,33 @@ +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.section.Section; + +public class StationTest { + @Test + public void addSection() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + Section section = new Section(line, source, sink, 0, 0); + assertThat(source.getSectionList()).hasSize(0); + source.addSection(section); + assertThat(source.getSectionList()).hasSize(1); + } + + @Test + public void addSection__SectionAddingOtherSourceStationReceiveException() { + Line line = new Line("line"); + Station source = new Station("source"); + Station other = new Station("other"); + Station sink = new Station("sink"); + Section section = new Section(line, other, sink, 0, 0); + String message = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> source.addSection(section)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} diff --git a/src/test/java/subway/presentation/SectionControllerTest.java b/src/test/java/subway/presentation/SectionControllerTest.java new file mode 100644 index 000000000..17dc29dc5 --- /dev/null +++ b/src/test/java/subway/presentation/SectionControllerTest.java @@ -0,0 +1,63 @@ +package subway.presentation; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class SectionControllerTest { + private final SectionController sectionController = new SectionController(); + + @Test + public void addSection__InputEssentialDistanceException() { + String lineName = "line"; + String sourceName = "source"; + String sinkName = "sink"; + String time = "0"; + String message = "๊ฑฐ๋ฆฌ ์ž…๋ ฅ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, null, time)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, "", time)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addSection__OnlyPossibleNumericInputDistanceException() { + String lineName = "line"; + String sourceName = "source"; + String sinkName = "sink"; + String time = "0"; + String message = "๊ฑฐ๋ฆฌ๋Š” ์ˆซ์ž ํ˜•์‹์˜ ์ž…๋ ฅ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."; + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, "distance", time)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addSection__InputEssentialTimeException() { + String lineName = "line"; + String sourceName = "source"; + String sinkName = "sink"; + String distance = "0"; + String message = "์‹œ๊ฐ„ ์ž…๋ ฅ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, distance, null)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, distance, "")).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addSection__OnlyPossibleNumericInputTimeException() { + String lineName = "line"; + String sourceName = "source"; + String sinkName = "sink"; + String distance = "0"; + String message = "์‹œ๊ฐ„์€ ์ˆซ์ž ํ˜•์‹์˜ ์ž…๋ ฅ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."; + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, distance, "time")).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } +} diff --git a/src/test/java/subway/util/ValidationTest.java b/src/test/java/subway/util/ValidationTest.java new file mode 100644 index 000000000..0ec5c905f --- /dev/null +++ b/src/test/java/subway/util/ValidationTest.java @@ -0,0 +1,14 @@ +package subway.util; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class ValidationTest { + @Test + public void isNumeric() { + assertThat(Validation.isNumeric("1")).isEqualTo(true); + assertThat(Validation.isNumeric("")).isEqualTo(false); + assertThat(Validation.isNumeric("number")).isEqualTo(false); + } +} From 6c5c7cc2d8db6af4292fbd8cef9193f231a56b44 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 17:50:28 +0900 Subject: [PATCH 09/45] =?UTF-8?q?refactor:=201.=20Line=20CRUD=20-=20[solvi?= =?UTF-8?q?ng=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=88=98=EC=A0=95=20-?= =?UTF-8?q?=20[LineRepositoryTest.java]=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=A2=85=EB=A3=8C=EC=8B=9C=20=EC=A0=84=EC=B2=B4=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EC=A7=81=EC=A0=91=20=ED=98=B8=EC=B6=9C=20=E2=86=92?= =?UTF-8?q?=20AfterEach=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20-=20[LineServiceTest.java]=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=A7=88=EB=8B=A4=20=EC=A0=84=EC=B2=B4=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EC=A7=81=EC=A0=91=20=ED=98=B8=EC=B6=9C=20=E2=86=92?= =?UTF-8?q?=20AfterEach=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 702 +++++++++++++++++- .../domain/line/LineRepositoryTest.java | 6 +- .../subway/domain/line/LineServiceTest.java | 9 +- 3 files changed, 706 insertions(+), 11 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 7fd4b7944..941f58414 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -122,9 +122,9 @@ package subway.domain.line; import java.util.List; public class LineService { -public List findAll() { -return LineRepository.lines(); -} + public List findAll() { + return LineRepository.lines(); + } public void deleteAll() { LineRepository.deleteAll(); @@ -152,6 +152,10 @@ public class LineRepositoryTest { assertThat(LineRepository.exists(line)).isEqualTo(false); LineRepository.addLine(line); assertThat(LineRepository.exists(line)).isEqualTo(true); + } + + @AfterEach + public void init() { LineRepository.deleteAll(); } } @@ -194,7 +198,6 @@ public class LineServiceTest { assertThat(lineService.findAll()).hasSize(0); this.lineService.addLine(lineDTO); assertThat(lineService.findAll()).hasSize(1); - this.lineService.deleteAll(); } @Test @@ -204,6 +207,10 @@ public class LineServiceTest { this.lineService.addLine(lineDTO); assertThatThrownBy(() -> this.lineService.addLine(lineDTO)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); + } + + @AfterEach + public void init() { this.lineService.deleteAll(); } } @@ -273,7 +280,6 @@ public class LineRepositoryTest { assertThat(LineRepository.findByName(name)).isNotPresent(); LineRepository.addLine(line); assertThat(LineRepository.findByName(name)).isPresent(); - LineRepository.deleteAll(); } } ``` @@ -313,7 +319,6 @@ public class LineServiceTest { this.lineService.addLine(lineDTO); Line line = this.lineService.findOneByName(name); assertThat(line.getName()).isEqualTo(name); - this.lineService.deleteAll(); } @Test @@ -622,4 +627,687 @@ public class StationService { } ``` -์—ญ ์ด๋ฆ„ ๊ธฐ์ค€ ๋‹จ๊ฑด ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file +์—ญ ์ด๋ฆ„ ๊ธฐ์ค€ ๋‹จ๊ฑด ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +## 3. Section CRUD + +```java +// Section.java + +package subway.domain.section; + +import subway.domain.line.Line; +import subway.domain.station.Station; + +public class Section { + private final Line line; + private final Station source; + private final Station sink; + private final int distance; + private final int time; + + public Section(Line line, Station source, Station sink, int distance, int time) { + this.line = line; + this.source = source; + this.sink = sink; + this.distance = distance; + this.time = time; + } + + public Line getLine() { + return line; + } + + public Station getSource() { + return source; + } + + public Station getSink() { + return sink; + } + + public int getDistance() { + return distance; + } + + public int getTime() { + return time; + } +} +``` + +๊ตฌ๊ฐ„ ๊ฐ์ฒด ์ƒ์„ฑ. + +```java +// LineTest.java + +package subway.domain.line; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class LineTest { + @Test + public void addSection() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + Section section = new Section(line, source, sink, 0, 0); + assertThat(line.getSectionList()).hasSize(0); + line.addSection(section); + assertThat(line.getSectionList()).hasSize(1); + } + + @Test + public void addSection__SectionAddingOtherLineReceiveException() { + Line line = new Line("line"); + Line other = new Line("other"); + Station source = new Station("source"); + Station sink = new Station("sink"); + Section section = new Section(other, source, sink, 0, 0); + String message = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ๋…ธ์„ ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> line.addSection(section)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} +``` + +```java +// Line.java + +package subway.domain.line; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import subway.domain.section.Section; + +public class Line { + private static final String SECTION_ADDING_OTHER_LINE_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ๋…ธ์„ ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + + private final List
sectionList = new ArrayList<>(); + + public void addSection(Section section) { + this.validateSection(section); + this.sectionList.add(section); + } + + private void validateSection(Section section) { + if(this != section.getLine()) { + throw new IllegalArgumentException(SECTION_ADDING_OTHER_LINE_RECEIVE_MESSAGE); + } + } +} +``` + +Line 1 : N ๋งค์นญ. + +Section ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// StationTest.java + +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.section.Section; + +public class StationTest { + @Test + public void addSection() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + Section section = new Section(line, source, sink, 0, 0); + assertThat(source.getSectionList()).hasSize(0); + source.addSection(section); + assertThat(source.getSectionList()).hasSize(1); + } + + @Test + public void addSection__SectionAddingOtherSourceStationReceiveException() { + Line line = new Line("line"); + Station source = new Station("source"); + Station other = new Station("other"); + Station sink = new Station("sink"); + Section section = new Section(line, other, sink, 0, 0); + String message = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> source.addSection(section)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} +``` + +```java +// Station.java + +package subway.domain.station; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import subway.domain.section.Section; + +public class Station { + private static final String SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + + private final List
sectionList = new ArrayList<>(); + + public List
getSectionList() { + return Collections.unmodifiableList(this.sectionList); + } + + public void addSection(Section section) { + this.validateSection(section); + this.sectionList.add(section); + } + + public void validateSection(Section section) { + if(this != section.getSource()) { + throw new IllegalArgumentException(SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE); + } + } +} +``` + +Station 1 : N ๋งค์นญ. + +Section ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// SectionDTOTest.java + +package subway.application.section.dto; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.LineDTO; +import subway.domain.station.StationDTO; + +public class SectionDTOTest { + @Test + public void new__SectionAddingLineInfoEssentialException() { + StationDTO sourceDTO = new StationDTO("source"); + StationDTO sinkDTO = new StationDTO("sink"); + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ๋…ธ์„  ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new SectionDTO(null, sourceDTO, sinkDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void new__SectionAddingSourceStationInfoEssentialException() { + LineDTO lineDTO = new LineDTO("line"); + StationDTO sinkDTO = new StationDTO("sink"); + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new SectionDTO(lineDTO, null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void new__SectionAddingSinkStationInfoEssentialException() { + LineDTO lineDTO = new LineDTO("line"); + StationDTO sourceDTO = new StationDTO("source"); + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new SectionDTO(lineDTO, sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} +``` + +```java +// SectionDTO.java + +package subway.application.section.dto; + +import subway.domain.line.LineDTO; +import subway.domain.station.StationDTO; + +public class SectionDTO { + private static final String SECTION_ADDING_LINE_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ๋…ธ์„  ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + + private final LineDTO lineDTO; + private final StationDTO sourceDTO; + private final StationDTO sinkDTO; + private int distance; + private int time; + + public SectionDTO(LineDTO lineDTO, StationDTO sourceDTO, StationDTO sinkDTO) { + this(lineDTO, sourceDTO, sinkDTO, 0, 0); + } + + public SectionDTO(LineDTO lineDTO, StationDTO sourceDTO, StationDTO sinkDTO, int distance, int time) { + this.validate(lineDTO, sourceDTO, sinkDTO); + this.lineDTO = lineDTO; + this.sourceDTO = sourceDTO; + this.sinkDTO = sinkDTO; + this.distance = distance; + this.time = time; + } + + private void validate(LineDTO lineDTO, StationDTO sourceDTO, StationDTO sinkDTO) { + if (lineDTO == null) { + throw new IllegalArgumentException(SECTION_ADDING_LINE_INFO_ESSENTIAL_MESSAGE); + } + if (sourceDTO == null) { + throw new IllegalArgumentException(SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE); + } + if (sinkDTO == null) { + throw new IllegalArgumentException(SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE); + } + } + + public LineDTO getLineDTO() { + return lineDTO; + } + + public StationDTO getSourceDTO() { + return sourceDTO; + } + + public StationDTO getSinkDTO() { + return sinkDTO; + } + + public int getDistance() { + return distance; + } + + public void setDistance(int distance) { + this.distance = distance; + } + + public int getTime() { + return time; + } + + public void setTime(int time) { + this.time = time; + } +} +``` + +๋‹ค์–‘ํ•œ ๊ณ„์ธต์—์„œ ์“ฐ์ผ ๊ธฐ๋ณธ SectionDTO ๊ตฌํ˜„. + +```java +// SectionRepository.java + +package subway.domain.section; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class SectionRepository { + private static final List
sections = new ArrayList<>(); + + public static List
sections() { + return Collections.unmodifiableList(sections); + } + + public static void deleteAll() { + sections.clear(); + } +} +``` + +```java +// SectionService.java + +package subway.application.section.service; + +import java.util.List; + +import subway.domain.section.Section; +import subway.domain.section.SectionRepository; + +public class SectionService { + public List
findAll() { + return SectionRepository.sections(); + } + + public void deleteAll() { + SectionRepository.deleteAll(); + } +} +``` + +๊ธฐ๋ณธ ์ „์ฒด ์กฐํšŒ ๋ฐ ์‚ญ์ œ ๊ธฐ๋Šฅ ์ƒ์„ฑ. + +### 3-1. CREATE + +```java +// SectionRepositoryTest.java + +package subway.domain.section; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.station.Station; + +public class SectionRepositoryTest { + @Test + public void exists() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + Section section = new Section(line, source, sink, 0, 0); + assertThat(SectionRepository.exists(section)).isEqualTo(false); + SectionRepository.addSection(section); + assertThat(SectionRepository.exists(section)).isEqualTo(true); + SectionRepository.deleteAll(); + } +} +``` + +```java +// SectionRepository.java + +package subway.domain.section; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class SectionRepository { + public static void addSection(Section section) { + sections.add(section); + } + + public static boolean exists(Section other) { + return sections.stream() + .anyMatch(section -> section.getLine() == other.getLine() && section.getSource() == other.getSource() + && section.getSink() == other.getSink()); + } +} +``` + +๊ตฌ๊ฐ„ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +๊ตฌ๊ฐ„ ์ค‘๋ณต ์ƒ์„ฑ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ๋…ธ์„ , ์‹œ์ž‘ ์ง€์  ์—ญ, ์ข…๋ฃŒ ์ง€์  ์—ญ ๊ธฐ์ค€์œผ๋กœ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// SectionServiceTest.java + +package subway.application.section.service; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import subway.application.section.dto.SectionDTO; +import subway.domain.line.Line; +import subway.domain.line.LineDTO; +import subway.domain.line.LineService; +import subway.domain.station.Station; +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class SectionServiceTest { + private final LineDTO lineDTO = new LineDTO("line"); + private final StationDTO sourceDTO = new StationDTO("source"); + private final StationDTO sinkDTO = new StationDTO("sink"); + + private final LineService lineService = new LineService(); + private final StationService stationService = new StationService(); + private final SectionService sectionService = new SectionService(); + + @BeforeEach + public void setup() { + this.lineService.addLine(lineDTO); + this.stationService.addStation(sourceDTO); + this.stationService.addStation(sinkDTO); + } + + @Test + public void addSection() { + Line line = this.lineService.findOneByName(lineDTO.getName()); + Station source = this.stationService.findOneByName(sourceDTO.getName()); + SectionDTO sectionDTO = new SectionDTO(lineDTO, sourceDTO, sinkDTO); + assertThat(this.sectionService.findAll()).hasSize(0); + assertThat(line.getSectionList()).hasSize(0); + assertThat(source.getSectionList()).hasSize(0); + this.sectionService.addSection(sectionDTO); + assertThat(this.sectionService.findAll()).hasSize(1); + assertThat(line.getSectionList()).hasSize(1); + assertThat(source.getSectionList()).hasSize(1); + } + + @Test + public void addSection__AlreadyExistsSectionException() { + SectionDTO sectionDTO = new SectionDTO(lineDTO, sourceDTO, sinkDTO); + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ตฌ๊ฐ„์ž…๋‹ˆ๋‹ค."; + this.sectionService.addSection(sectionDTO); + assertThatThrownBy(() -> this.sectionService.addSection(sectionDTO)).isInstanceOf( + IllegalArgumentException.class) + .hasMessage(message); + } + + @AfterEach + public void init() { + lineService.deleteAll(); + stationService.deleteAll(); + sectionService.deleteAll(); + } +} +``` + +```java +// SectionService.java + +package subway.application.section.service; + +import java.util.List; + +import subway.application.section.dto.SectionDTO; +import subway.domain.line.Line; +import subway.domain.line.LineService; +import subway.domain.section.Section; +import subway.domain.section.SectionRepository; +import subway.domain.station.Station; +import subway.domain.station.StationService; + +public class SectionService { + private static final String ALREADY_EXISTS_SECTION_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ตฌ๊ฐ„์ž…๋‹ˆ๋‹ค."; + + private final LineService lineService = new LineService(); + private final StationService stationService = new StationService(); + + public void addSection(SectionDTO sectionDTO) { + Line line = this.lineService.findOneByName(sectionDTO.getLineDTO().getName()); + Station source = this.stationService.findOneByName(sectionDTO.getSourceDTO().getName()); + Station sink = this.stationService.findOneByName(sectionDTO.getSinkDTO().getName()); + Section section = new Section(line, source, sink, sectionDTO.getDistance(), sectionDTO.getTime()); + if (SectionRepository.exists(section)) { + throw new IllegalArgumentException(ALREADY_EXISTS_SECTION_MESSAGE); + } + SectionRepository.addSection(section); + line.addSection(section); + source.addSection(section); + } +} +``` + +๊ตฌ๊ฐ„ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// ValidationTest.java + +package subway.util; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class ValidationTest { + @Test + public void isNumeric() { + assertThat(Validation.isNumeric("1")).isEqualTo(true); + assertThat(Validation.isNumeric("")).isEqualTo(false); + assertThat(Validation.isNumeric("number")).isEqualTo(false); + } +} +``` + +```java +// Validation.java + +package subway.util; + +import java.util.regex.Pattern; + +public final class Validation { + private Validation() { + } + + public static boolean isNumeric(String str) { + return str != null && !str.isEmpty() && Pattern.matches("^[0-9]*$", str); + } +} +``` + +์ˆซ์ž ํ˜•์‹์˜ ๋ฌธ์ž์—ด ํ™•์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// SectionController.java + +package subway.presentation; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class SectionControllerTest { + private final SectionController sectionController = new SectionController(); + + @Test + public void addSection__InputEssentialDistanceException() { + String lineName = "line"; + String sourceName = "source"; + String sinkName = "sink"; + String time = "0"; + String message = "๊ฑฐ๋ฆฌ ์ž…๋ ฅ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, null, time)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, "", time)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addSection__OnlyPossibleNumericInputDistanceException() { + String lineName = "line"; + String sourceName = "source"; + String sinkName = "sink"; + String time = "0"; + String message = "๊ฑฐ๋ฆฌ๋Š” ์ˆซ์ž ํ˜•์‹์˜ ์ž…๋ ฅ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."; + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, "distance", time)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addSection__InputEssentialTimeException() { + String lineName = "line"; + String sourceName = "source"; + String sinkName = "sink"; + String distance = "0"; + String message = "์‹œ๊ฐ„ ์ž…๋ ฅ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, distance, null)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, distance, "")).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addSection__OnlyPossibleNumericInputTimeException() { + String lineName = "line"; + String sourceName = "source"; + String sinkName = "sink"; + String distance = "0"; + String message = "์‹œ๊ฐ„์€ ์ˆซ์ž ํ˜•์‹์˜ ์ž…๋ ฅ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."; + assertThatThrownBy( + () -> this.sectionController.addSection(lineName, sourceName, sinkName, distance, "time")).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } +} +``` + +```java +// SectionController.java + +package subway.presentation; + +import subway.application.section.dto.SectionDTO; +import subway.application.section.service.SectionService; +import subway.domain.line.LineDTO; +import subway.domain.station.StationDTO; +import subway.util.Validation; + +public class SectionController { + private static final String INPUT_ESSENTIAL_DISTANCE_MESSAGE = "๊ฑฐ๋ฆฌ ์ž…๋ ฅ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String ONLY_POSSIBLE_NUMERIC_INPUT_DISTANCE_MESSAGE = "๊ฑฐ๋ฆฌ๋Š” ์ˆซ์ž ํ˜•์‹์˜ ์ž…๋ ฅ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."; + private static final String INPUT_ESSENTIAL_TIME_MESSAGE = "์‹œ๊ฐ„ ์ž…๋ ฅ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String ONLY_POSSIBLE_NUMERIC_INPUT_TIME_MESSAGE = "์‹œ๊ฐ„์€ ์ˆซ์ž ํ˜•์‹์˜ ์ž…๋ ฅ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."; + + private final SectionService sectionService = new SectionService(); + + public void addSection(String lineName, String sourceName, String sinkName, String _distance, String _time) { + LineDTO lineDTO = new LineDTO(lineName); + StationDTO sourceDTO = new StationDTO(sourceName); + StationDTO sinkDTO = new StationDTO(sinkName); + this.validateDistance(_distance); + int distance = Integer.parseInt(_distance); + this.validateTime(_time); + int time = Integer.parseInt(_time); + SectionDTO sectionDTO = new SectionDTO(lineDTO, sourceDTO, sinkDTO, distance, time); + this.sectionService.addSection(sectionDTO); + } + + private void validateDistance(String distance) { + if(distance == null || distance.trim().isEmpty()) { + throw new IllegalArgumentException(INPUT_ESSENTIAL_DISTANCE_MESSAGE); + } + if (!Validation.isNumeric(distance)) { + throw new IllegalArgumentException(ONLY_POSSIBLE_NUMERIC_INPUT_DISTANCE_MESSAGE); + } + } + + private void validateTime(String time) { + if(time == null || time.trim().isEmpty()) { + throw new IllegalArgumentException(INPUT_ESSENTIAL_TIME_MESSAGE); + } + if (!Validation.isNumeric(time)) { + throw new IllegalArgumentException(ONLY_POSSIBLE_NUMERIC_INPUT_TIME_MESSAGE); + } + } +} +``` + +์ œ์–ด ๊ณ„์ธต์— ๊ตฌ๊ฐ„ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๋งคํ•‘. + + + + + diff --git a/src/test/java/subway/domain/line/LineRepositoryTest.java b/src/test/java/subway/domain/line/LineRepositoryTest.java index 3a71f5177..ec0a7acab 100644 --- a/src/test/java/subway/domain/line/LineRepositoryTest.java +++ b/src/test/java/subway/domain/line/LineRepositoryTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.*; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; public class LineRepositoryTest { @@ -11,7 +12,6 @@ public void exists() { assertThat(LineRepository.exists(line)).isEqualTo(false); LineRepository.addLine(line); assertThat(LineRepository.exists(line)).isEqualTo(true); - LineRepository.deleteAll(); } @Test @@ -21,6 +21,10 @@ public void findByName() { assertThat(LineRepository.findByName(name)).isNotPresent(); LineRepository.addLine(line); assertThat(LineRepository.findByName(name)).isPresent(); + } + + @AfterEach + public void init() { LineRepository.deleteAll(); } } diff --git a/src/test/java/subway/domain/line/LineServiceTest.java b/src/test/java/subway/domain/line/LineServiceTest.java index 102597f85..93dacca95 100644 --- a/src/test/java/subway/domain/line/LineServiceTest.java +++ b/src/test/java/subway/domain/line/LineServiceTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.*; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; public class LineServiceTest { @@ -13,7 +14,6 @@ public void addLine() { assertThat(this.lineService.findAll()).hasSize(0); this.lineService.addLine(lineDTO); assertThat(this.lineService.findAll()).hasSize(1); - this.lineService.deleteAll(); } @Test @@ -23,7 +23,6 @@ public void addLine__AlreadyExistsLineException() { this.lineService.addLine(lineDTO); assertThatThrownBy(() -> this.lineService.addLine(lineDTO)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); - this.lineService.deleteAll(); } @Test @@ -33,7 +32,6 @@ public void findOneByName() { this.lineService.addLine(lineDTO); Line line = this.lineService.findOneByName(name); assertThat(line.getName()).isEqualTo(name); - this.lineService.deleteAll(); } @Test @@ -42,4 +40,9 @@ public void findOneByName__NotExistsLineException() { assertThatThrownBy(() -> this.lineService.findOneByName("test")).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } + + @AfterEach + public void init() { + this.lineService.deleteAll(); + } } From 85737ee26f98c11eef117c3433435d81e1c75743 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 17:53:12 +0900 Subject: [PATCH 10/45] =?UTF-8?q?refactor:=202.=20Station=20CRUD=20-=20[so?= =?UTF-8?q?lving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20-=20[StationRepositoryTest.java]=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A2=85=EB=A3=8C=EC=8B=9C=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=A7=81=EC=A0=91=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=E2=86=92=20AfterEach=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20-=20[StationServiceTest.java]=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=A7=88=EB=8B=A4=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=A7=81=EC=A0=91=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=E2=86=92=20AfterEach=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 12 +++++++++--- .../subway/domain/station/StationRepositoryTest.java | 6 +++++- .../subway/domain/station/StationServiceTest.java | 9 ++++++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 941f58414..3cef6e6fe 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -439,6 +439,10 @@ public class StationRepositoryTest { assertThat(StationRepository.exists(station)).isEqualTo(false); StationRepository.addStation(station); assertThat(StationRepository.exists(station)).isEqualTo(true); + } + + @AfterEach + public void init() { StationRepository.deleteAll(); } } @@ -482,7 +486,6 @@ public class StationServiceTest { assertThat(this.stationService.findAll()).hasSize(0); this.stationService.addStation(stationDTO); assertThat(this.stationService.findAll()).hasSize(1); - this.stationService.deleteAll(); } @Test @@ -494,6 +497,11 @@ public class StationServiceTest { IllegalArgumentException.class).hasMessage(message); this.stationService.deleteAll(); } + + @AfterEach + public void init() { + this.stationService.deleteAll(); + } } ``` @@ -558,7 +566,6 @@ public class StationRepositoryTest { assertThat(StationRepository.findByName(name)).isNotPresent(); StationRepository.addStation(station); assertThat(StationRepository.findByName(name)).isPresent(); - StationRepository.deleteAll(); } } ``` @@ -598,7 +605,6 @@ public class StationServiceTest { this.stationService.addStation(stationDTO); Station station = this.stationService.findOneByName(name); assertThat(station.getName()).isEqualTo(name); - this.stationService.deleteAll(); } @Test diff --git a/src/test/java/subway/domain/station/StationRepositoryTest.java b/src/test/java/subway/domain/station/StationRepositoryTest.java index e06ea7c3b..207331ba5 100644 --- a/src/test/java/subway/domain/station/StationRepositoryTest.java +++ b/src/test/java/subway/domain/station/StationRepositoryTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.*; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; public class StationRepositoryTest { @@ -11,7 +12,6 @@ public void exists() { assertThat(StationRepository.exists(station)).isEqualTo(false); StationRepository.addStation(station); assertThat(StationRepository.exists(station)).isEqualTo(true); - StationRepository.deleteAll(); } @Test @@ -21,6 +21,10 @@ public void findByName() { assertThat(StationRepository.findByName(name)).isNotPresent(); StationRepository.addStation(station); assertThat(StationRepository.findByName(name)).isPresent(); + } + + @AfterEach + public void init() { StationRepository.deleteAll(); } } diff --git a/src/test/java/subway/domain/station/StationServiceTest.java b/src/test/java/subway/domain/station/StationServiceTest.java index ac149205a..b59807fe7 100644 --- a/src/test/java/subway/domain/station/StationServiceTest.java +++ b/src/test/java/subway/domain/station/StationServiceTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.*; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; public class StationServiceTest { @@ -13,7 +14,6 @@ public void addStation() { assertThat(this.stationService.findAll()).hasSize(0); this.stationService.addStation(stationDTO); assertThat(this.stationService.findAll()).hasSize(1); - this.stationService.deleteAll(); } @Test @@ -23,7 +23,6 @@ public void addStation__AlreadyExistsStationException() { this.stationService.addStation(stationDTO); assertThatThrownBy(() -> this.stationService.addStation(stationDTO)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); - this.stationService.deleteAll(); } @Test @@ -33,7 +32,6 @@ public void findOneByName() { this.stationService.addStation(stationDTO); Station station = this.stationService.findOneByName(name); assertThat(station.getName()).isEqualTo(name); - this.stationService.deleteAll(); } @Test @@ -42,4 +40,9 @@ public void findOneByName__NotExistsStationException() { assertThatThrownBy(() -> this.stationService.findOneByName("test")).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } + + @AfterEach + public void init() { + this.stationService.deleteAll(); + } } From fedc7ac88dcb6e17cbcc52f7f3dc388330f4678b Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Mon, 10 Feb 2025 17:54:48 +0900 Subject: [PATCH 11/45] =?UTF-8?q?refactor:=203.=20Section=20CRUD=20-=20[so?= =?UTF-8?q?lving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20-=20[SectionRepositoryTest.java]=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=A2=85=EB=A3=8C=EC=8B=9C=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EC=A7=81=EC=A0=91=20=ED=98=B8=EC=B6=9C=20?= =?UTF-8?q?=E2=86=92=20AfterEach=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 4 ++++ .../java/subway/domain/section/SectionRepositoryTest.java | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/.github/solving_process.md b/.github/solving_process.md index 3cef6e6fe..9d308f7e4 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -1017,6 +1017,10 @@ public class SectionRepositoryTest { assertThat(SectionRepository.exists(section)).isEqualTo(false); SectionRepository.addSection(section); assertThat(SectionRepository.exists(section)).isEqualTo(true); + } + + @AfterEach + public void init() { SectionRepository.deleteAll(); } } diff --git a/src/test/java/subway/domain/section/SectionRepositoryTest.java b/src/test/java/subway/domain/section/SectionRepositoryTest.java index 7844f9aef..952a407f4 100644 --- a/src/test/java/subway/domain/section/SectionRepositoryTest.java +++ b/src/test/java/subway/domain/section/SectionRepositoryTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.*; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import subway.domain.line.Line; @@ -17,6 +18,10 @@ public void exists() { assertThat(SectionRepository.exists(section)).isEqualTo(false); SectionRepository.addSection(section); assertThat(SectionRepository.exists(section)).isEqualTo(true); + } + + @AfterEach + public void init() { SectionRepository.deleteAll(); } } From 76d95921a7acd1795137c74a4784774355eda92d Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 11:28:21 +0900 Subject: [PATCH 12/45] =?UTF-8?q?feat:=204.=20=EC=B5=9C=EB=8B=A8=20?= =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EB=85=B8=EB=93=9C,=20=EA=B0=84=EC=84=A0?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../section/service/SectionService.java | 8 ++ .../section/service/ShortDistanceService.java | 65 ++++++++++++++++ .../service/ShortDistanceServiceTest.java | 77 +++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 src/main/java/subway/application/section/service/ShortDistanceService.java create mode 100644 src/test/java/subway/application/section/service/ShortDistanceServiceTest.java diff --git a/src/main/java/subway/application/section/service/SectionService.java b/src/main/java/subway/application/section/service/SectionService.java index 9114152e8..53db35528 100644 --- a/src/main/java/subway/application/section/service/SectionService.java +++ b/src/main/java/subway/application/section/service/SectionService.java @@ -8,6 +8,7 @@ import subway.domain.section.Section; import subway.domain.section.SectionRepository; import subway.domain.station.Station; +import subway.domain.station.StationDTO; import subway.domain.station.StationService; public class SectionService { @@ -15,11 +16,17 @@ public class SectionService { private final LineService lineService = new LineService(); private final StationService stationService = new StationService(); + private final ShortDistanceService shortDistanceService = new ShortDistanceService(); public List
findAll() { return SectionRepository.sections(); } + public void addNode(StationDTO stationDTO) { + Station station = this.stationService.findOneByName(stationDTO.getName()); + this.shortDistanceService.addNode(station); + } + public void addSection(SectionDTO sectionDTO) { Line line = this.lineService.findOneByName(sectionDTO.getLineDTO().getName()); Station source = this.stationService.findOneByName(sectionDTO.getSourceDTO().getName()); @@ -29,6 +36,7 @@ public void addSection(SectionDTO sectionDTO) { throw new IllegalArgumentException(ALREADY_EXISTS_SECTION_MESSAGE); } SectionRepository.addSection(section); + shortDistanceService.addEdge(section); line.addSection(section); source.addSection(section); } diff --git a/src/main/java/subway/application/section/service/ShortDistanceService.java b/src/main/java/subway/application/section/service/ShortDistanceService.java new file mode 100644 index 000000000..114ef61aa --- /dev/null +++ b/src/main/java/subway/application/section/service/ShortDistanceService.java @@ -0,0 +1,65 @@ +package subway.application.section.service; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedMultigraph; + +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class ShortDistanceService { + private static final DirectedWeightedMultigraph graph = new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class); + + private static final String ALREADY_EXISTS_NODE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String ALREADY_EXISTS_EDGE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; + + protected Set findAllNode() { + return Collections.unmodifiableSet(graph.vertexSet()); + } + + protected Set findAllEdge() { + return Collections.unmodifiableSet(graph.edgeSet()); + } + + protected void addNode(Station station) { + if (graph.containsVertex(station)) { + throw new IllegalArgumentException(ALREADY_EXISTS_NODE_MESSAGE); + } + graph.addVertex(station); + } + + protected void addEdge(Section section) { + Station source = section.getSource(); + Station sink = section.getSink(); + if (!graph.containsVertex(source)) { + throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); + } + if (!graph.containsVertex(sink)) { + throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); + } + if (graph.containsEdge(source, sink)) { + throw new IllegalArgumentException(ALREADY_EXISTS_EDGE_MESSAGE); + } + graph.setEdgeWeight(graph.addEdge(source, sink), section.getDistance()); + } + + protected void deleteAllNode() { + Set nodes = new HashSet<>(this.findAllNode()); + graph.removeAllVertices(nodes); + } + + protected void deleteAllEdge() { + graph.removeAllEdges(graph.edgeSet()); + } + + protected void deleteAll() { + this.deleteAllEdge(); + this.deleteAllNode(); + } +} diff --git a/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java b/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java new file mode 100644 index 000000000..e8a6e84e8 --- /dev/null +++ b/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java @@ -0,0 +1,77 @@ +package subway.application.section.service; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class ShortDistanceServiceTest { + private final Line line = new Line("line"); + private final Station source = new Station("source"); + private final Station sink = new Station("sink"); + + private final ShortDistanceService shortDistanceService = new ShortDistanceService(); + + @Test + public void addNode() { + assertThat(this.shortDistanceService.findAllNode()).hasSize(0); + this.shortDistanceService.addNode(this.source); + assertThat(this.shortDistanceService.findAllNode()).hasSize(1); + } + + @Test + public void addNode_AlreadyExistsNodeException() { + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.source); + assertThatThrownBy(() -> this.shortDistanceService.addNode(this.source)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addEdge() { + Section section = new Section(this.line, this.source, this.sink, 0, 0); + this.shortDistanceService.addNode(this.source); + this.shortDistanceService.addNode(this.sink); + assertThat(this.shortDistanceService.findAllEdge()).hasSize(0); + this.shortDistanceService.addEdge(section); + assertThat(this.shortDistanceService.findAllEdge()).hasSize(1); + } + + @Test + public void addEdge_NotExistsSourceNodeException() { + Section section = new Section(this.line, this.source, this.sink, 0, 0); + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.sink); + assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addEdge_NotExistsSinkNodeException() { + Section section = new Section(this.line, this.source, this.sink, 0, 0); + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.source); + assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addEdge_AlreadyExistsEdgeException() { + Section section = new Section(this.line, this.source, this.sink, 0, 0); + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.source); + this.shortDistanceService.addNode(this.sink); + this.shortDistanceService.addEdge(section); + assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @AfterEach + public void init() { + this.shortDistanceService.deleteAll(); + } +} From 11269d1e9eb9241d449a8546980e7b33301ec042 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 16:11:40 +0900 Subject: [PATCH 13/45] =?UTF-8?q?docs:=204.=20=EC=B5=9C=EB=8B=A8=20?= =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EB=85=B8=EB=93=9C,=20=EA=B0=84=EC=84=A0?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20-=20[solving=5Fprocess.md]=20=ED=92=80?= =?UTF-8?q?=EC=9D=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 308 +++++++++++++++++++++++++++++++++++-- 1 file changed, 296 insertions(+), 12 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 9d308f7e4..9bc4709fb 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -411,7 +411,7 @@ public class StationService { public List findAll() { return StationRepository.stations(); } - + public void deleteAll() { StationRepository.deleteAll(); } @@ -514,7 +514,7 @@ import java.util.List; public class StationService { private static final String ALREADY_EXISTS_STATION_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ์—ญ์ž…๋‹ˆ๋‹ค."; - + public void addStation(StationDTO stationDTO) { Station station = new Station(stationDTO.getName()); if (StationRepository.exists(station)) { @@ -735,23 +735,23 @@ import subway.domain.section.Section; public class Line { private static final String SECTION_ADDING_OTHER_LINE_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ๋…ธ์„ ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; - + private final List
sectionList = new ArrayList<>(); - + public void addSection(Section section) { this.validateSection(section); this.sectionList.add(section); } private void validateSection(Section section) { - if(this != section.getLine()) { + if (this != section.getLine()) { throw new IllegalArgumentException(SECTION_ADDING_OTHER_LINE_RECEIVE_MESSAGE); } } } ``` -Line 1 : N ๋งค์นญ. +Line 1 : N ๋งค์นญ. Section ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. @@ -806,9 +806,9 @@ import subway.domain.section.Section; public class Station { private static final String SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; - + private final List
sectionList = new ArrayList<>(); - + public List
getSectionList() { return Collections.unmodifiableList(this.sectionList); } @@ -819,14 +819,14 @@ public class Station { } public void validateSection(Section section) { - if(this != section.getSource()) { + if (this != section.getSource()) { throw new IllegalArgumentException(SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE); } } } ``` -Station 1 : N ๋งค์นญ. +Station 1 : N ๋งค์นญ. Section ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. @@ -1296,7 +1296,7 @@ public class SectionController { } private void validateDistance(String distance) { - if(distance == null || distance.trim().isEmpty()) { + if (distance == null || distance.trim().isEmpty()) { throw new IllegalArgumentException(INPUT_ESSENTIAL_DISTANCE_MESSAGE); } if (!Validation.isNumeric(distance)) { @@ -1305,7 +1305,7 @@ public class SectionController { } private void validateTime(String time) { - if(time == null || time.trim().isEmpty()) { + if (time == null || time.trim().isEmpty()) { throw new IllegalArgumentException(INPUT_ESSENTIAL_TIME_MESSAGE); } if (!Validation.isNumeric(time)) { @@ -1317,7 +1317,291 @@ public class SectionController { ์ œ์–ด ๊ณ„์ธต์— ๊ตฌ๊ฐ„ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๋งคํ•‘. +## 4. ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๋…ธ๋“œ, ๊ฐ„์„  ์ถ”๊ฐ€ + +### 4-1. ๋…ธ๋“œ + +```java +// ShortDistanceService.java + +package subway.application.section.service; + +import java.util.Collections; +import java.util.Set; + +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedMultigraph; + +import subway.domain.station.Station; + +public class ShortDistanceService { + private static final DirectedWeightedMultigraph graph = new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class); + + protected Set findAllNode() { + return Collections.unmodifiableSet(graph.vertexSet()); + } + + protected void deleteAllNode() { + Set nodes = new HashSet<>(this.findAllNode()); + graph.removeAllVertices(nodes); + } +} +``` + +๊ธฐ๋ณธ ์ „์ฒด ์กฐํšŒ ๋ฐ ์‚ญ์ œ ๊ธฐ๋Šฅ ์ƒ์„ฑ. + +```java +// ShortDistanceServiceTest.java + +package subway.application.section.service; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import subway.domain.station.Station; + +public class ShortDistanceServiceTest { + private final Station source = new Station("source"); + + private final ShortDistanceService shortDistanceService = new ShortDistanceService(); + + @Test + public void addNode() { + assertThat(this.shortDistanceService.findAllNode()).hasSize(0); + this.shortDistanceService.addNode(this.source); + assertThat(this.shortDistanceService.findAllNode()).hasSize(1); + } + + @Test + public void addNode_AlreadyExistsNodeException() { + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.source); + assertThatThrownBy(() -> this.shortDistanceService.addNode(this.source)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @AfterEach + public void init() { + this.shortDistanceService.deleteAllNode(); + } +} +``` + +```java +// ShortDistanceService.java + +package subway.application.section.service; + +import java.util.Collections; +import java.util.Set; + +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedMultigraph; + +import subway.domain.station.Station; + +public class ShortDistanceService { + private static final String ALREADY_EXISTS_NODE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + + protected void addNode(Station station) { + if (graph.containsVertex(station)) { + throw new IllegalArgumentException(ALREADY_EXISTS_NODE_MESSAGE); + } + graph.addVertex(station); + } +} +``` + +๋…ธ์„  ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// SectionService.java + +package subway.application.section.service; + +import java.util.List; + +import subway.application.section.dto.SectionDTO; +import subway.domain.line.Line; +import subway.domain.line.LineService; +import subway.domain.section.Section; +import subway.domain.section.SectionRepository; +import subway.domain.station.Station; +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; +public class SectionService { + private final ShortDistanceService shortDistanceService = new ShortDistanceService(); + + public void addNode(StationDTO stationDTO) { + Station station = this.stationService.findOneByName(stationDTO.getName()); + this.shortDistanceService.addNode(station); + } +} +``` + +๋ฌด๋ถ„๋ณ„ํ•œ ๋…ธ๋“œ ์ถ”๊ฐ€๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Section Service ๊ณ„์ธต์„ ํ†ตํ•ด์„œ๋งŒ ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ•จ. +## 4-2. ๊ฐ„์„  + +```java +// ShortDistanceService.java + +package subway.application.section.service; + +import java.util.Collections; +import java.util.Set; +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedMultigraph; + +import subway.domain.station.Station; + +public class ShortDistanceService { + protected Set findAllEdge() { + return Collections.unmodifiableSet(graph.edgeSet()); + } + + protected void deleteAllEdge() { + graph.removeAllEdges(graph.edgeSet()); + } + + protected void deleteAll() { + this.deleteAllEdge(); + this.deleteAllNode(); + } +} +``` + +๊ธฐ๋ณธ ์ „์ฒด ์กฐํšŒ ๋ฐ ์‚ญ์ œ ๊ธฐ๋Šฅ ์ƒ์„ฑ. + +```java +// ShortDistanceServiceTest.java + +package subway.application.section.service; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class ShortDistanceServiceTest { + private final Line line = new Line("line"); + private final Station sink = new Station("sink"); + + @Test + public void addEdge_NotExistsSourceNodeException() { + Section section = new Section(this.line, this.source, this.sink, 0, 0); + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.sink); + assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addEdge_NotExistsSinkNodeException() { + Section section = new Section(this.line, this.source, this.sink, 0, 0); + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.source); + assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addEdge_AlreadyExistsEdgeException() { + Section section = new Section(this.line, this.source, this.sink, 0, 0); + String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.source); + this.shortDistanceService.addNode(this.sink); + this.shortDistanceService.addEdge(section); + assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @AfterEach + public void init() { + this.shortDistanceService.deleteAll(); + } +} +``` + +```java +// ShortDistanceService.java + +package subway.application.section.service; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedMultigraph; + +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class ShortDistanceService { + private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String ALREADY_EXISTS_EDGE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; + + protected void addEdge(Section section) { + Station source = section.getSource(); + Station sink = section.getSink(); + if (!graph.containsVertex(source)) { + throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); + } + if (!graph.containsVertex(sink)) { + throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); + } + if (graph.containsEdge(source, sink)) { + throw new IllegalArgumentException(ALREADY_EXISTS_EDGE_MESSAGE); + } + graph.setEdgeWeight(graph.addEdge(source, sink), section.getDistance()); + } +} +``` + +๊ฐ„์„  ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// SectionService.java + +package subway.application.section.service; + +import java.util.List; + +import subway.application.section.dto.SectionDTO; +import subway.domain.line.Line; +import subway.domain.line.LineService; +import subway.domain.section.Section; +import subway.domain.section.SectionRepository; +import subway.domain.station.Station; +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class SectionService { + public void addSection(SectionDTO sectionDTO) { + Line line = this.lineService.findOneByName(sectionDTO.getLineDTO().getName()); + Station source = this.stationService.findOneByName(sectionDTO.getSourceDTO().getName()); + Station sink = this.stationService.findOneByName(sectionDTO.getSinkDTO().getName()); + Section section = new Section(line, source, sink, sectionDTO.getDistance(), sectionDTO.getTime()); + if (SectionRepository.exists(section)) { + throw new IllegalArgumentException(ALREADY_EXISTS_SECTION_MESSAGE); + } + SectionRepository.addSection(section); + +shortDistanceService.addEdge(section); + line.addSection(section); + source.addSection(section); + } +} +``` +๋ฌด๋ถ„๋ณ„ํ•œ ๊ฐ„์„  ์ถ”๊ฐ€๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Section Service ๊ณ„์ธต์„ ํ†ตํ•ด์„œ๋งŒ ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ•จ. \ No newline at end of file From 53e1727bc8b3fe39cf0d4588a1cec73d82239cf7 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 16:12:17 +0900 Subject: [PATCH 14/45] =?UTF-8?q?feat:=205.=20=EC=B5=9C=EB=8B=A8=20?= =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EA=B2=BD=EB=A1=9C=20=EA=B5=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../section/dto/ShortCostRequest.java | 38 ++++++++++++ .../section/dto/ShortCostResponse.java | 46 +++++++++++++++ .../section/service/SectionService.java | 20 +++++++ .../section/service/ShortDistanceService.java | 21 +++++++ .../java/subway/domain/station/Station.java | 17 ++++++ .../subway/domain/station/StationDTO.java | 10 ++++ .../subway/domain/station/StationService.java | 5 ++ .../presentation/SectionController.java | 13 ++++- .../section/dto/ShortCostRequestTest.java | 34 +++++++++++ .../section/dto/ShortCostResponseTest.java | 30 ++++++++++ .../section/service/SectionServiceTest.java | 58 ++++++++++++++++++- .../service/ShortDistanceServiceTest.java | 30 ++++++++++ .../subway/domain/station/StationTest.java | 40 +++++++++++++ 13 files changed, 357 insertions(+), 5 deletions(-) create mode 100644 src/main/java/subway/application/section/dto/ShortCostRequest.java create mode 100644 src/main/java/subway/application/section/dto/ShortCostResponse.java create mode 100644 src/test/java/subway/application/section/dto/ShortCostRequestTest.java create mode 100644 src/test/java/subway/application/section/dto/ShortCostResponseTest.java diff --git a/src/main/java/subway/application/section/dto/ShortCostRequest.java b/src/main/java/subway/application/section/dto/ShortCostRequest.java new file mode 100644 index 000000000..1f5e4dbd6 --- /dev/null +++ b/src/main/java/subway/application/section/dto/ShortCostRequest.java @@ -0,0 +1,38 @@ +package subway.application.section.dto; + +import subway.domain.station.StationDTO; + +public class ShortCostRequest { + private static final String SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SINK_STATION_INFO_ESSENTIAL_MESSAGE = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SAME_SOURCE_AND_SINK_STATION_MESSAGE = "์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๋™์ผํ•ฉ๋‹ˆ๋‹ค."; + + private final StationDTO sourceDTO; + private final StationDTO sinkDTO; + + public ShortCostRequest(StationDTO sourceDTO, StationDTO sinkDTO) { + this.validate(sourceDTO, sinkDTO); + this.sourceDTO = sourceDTO; + this.sinkDTO = sinkDTO; + } + + private void validate(StationDTO sourceDTO, StationDTO sinkDTO) { + if(sourceDTO == null) { + throw new IllegalArgumentException(SOURCE_STATION_INFO_ESSENTIAL_MESSAGE); + } + if(sinkDTO == null) { + throw new IllegalArgumentException(SINK_STATION_INFO_ESSENTIAL_MESSAGE); + } + if(sourceDTO.equals(sinkDTO)) { + throw new IllegalArgumentException(SAME_SOURCE_AND_SINK_STATION_MESSAGE); + } + } + + public StationDTO getSourceDTO() { + return sourceDTO; + } + + public StationDTO getSinkDTO() { + return sinkDTO; + } +} diff --git a/src/main/java/subway/application/section/dto/ShortCostResponse.java b/src/main/java/subway/application/section/dto/ShortCostResponse.java new file mode 100644 index 000000000..8bbed9219 --- /dev/null +++ b/src/main/java/subway/application/section/dto/ShortCostResponse.java @@ -0,0 +1,46 @@ +package subway.application.section.dto; + +import java.util.ArrayList; +import java.util.List; + +import subway.domain.station.Station; + +public class ShortCostResponse { + private int totalDistance; + private int totalTime; + private final List stationNameList; + + public ShortCostResponse(List stationList) { + this.stationNameList = new ArrayList<>(); + int length = stationList.size(); + for (int index = 0; index < length; index++) { + Station source = stationList.get(index); + if (index + 1 < length) { + Station sink = stationList.get(index + 1); + totalDistance += source.findDistanceTo(sink); + totalTime += source.findTimeTo(sink); + } + stationNameList.add(source.getName()); + } + } + + public int getTotalDistance() { + return totalDistance; + } + + public void setTotalDistance(int totalDistance) { + this.totalDistance = totalDistance; + } + + public int getTotalTime() { + return totalTime; + } + + public void setTotalTime(int totalTime) { + this.totalTime = totalTime; + } + + public List getStationNameList() { + return stationNameList; + } +} diff --git a/src/main/java/subway/application/section/service/SectionService.java b/src/main/java/subway/application/section/service/SectionService.java index 53db35528..522162812 100644 --- a/src/main/java/subway/application/section/service/SectionService.java +++ b/src/main/java/subway/application/section/service/SectionService.java @@ -2,7 +2,12 @@ import java.util.List; +import org.jgrapht.GraphPath; +import org.jgrapht.graph.DefaultWeightedEdge; + import subway.application.section.dto.SectionDTO; +import subway.application.section.dto.ShortCostRequest; +import subway.application.section.dto.ShortCostResponse; import subway.domain.line.Line; import subway.domain.line.LineService; import subway.domain.section.Section; @@ -13,6 +18,9 @@ public class SectionService { private static final String ALREADY_EXISTS_SECTION_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ตฌ๊ฐ„์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SOURCE_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ ์ง€์  ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; private final LineService lineService = new LineService(); private final StationService stationService = new StationService(); @@ -41,6 +49,18 @@ public void addSection(SectionDTO sectionDTO) { source.addSection(section); } + public ShortCostResponse computeShortDistance(ShortCostRequest shortCostRequest) { + Station source = this.stationService.findByName(shortCostRequest.getSourceDTO().getName()) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SOURCE_STATION_MESSAGE)); + Station sink = this.stationService.findByName(shortCostRequest.getSinkDTO().getName()) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SINK_STATION_MESSAGE)); + GraphPath graphPath = this.shortDistanceService.compute(source, sink); + if (graphPath == null) { + throw new IllegalArgumentException(NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE); + } + return new ShortCostResponse(graphPath.getVertexList()); + } + public void deleteAll() { SectionRepository.deleteAll(); } diff --git a/src/main/java/subway/application/section/service/ShortDistanceService.java b/src/main/java/subway/application/section/service/ShortDistanceService.java index 114ef61aa..6c2a302f1 100644 --- a/src/main/java/subway/application/section/service/ShortDistanceService.java +++ b/src/main/java/subway/application/section/service/ShortDistanceService.java @@ -4,6 +4,8 @@ import java.util.HashSet; import java.util.Set; +import org.jgrapht.GraphPath; +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.DirectedWeightedMultigraph; @@ -49,6 +51,25 @@ protected void addEdge(Section section) { graph.setEdgeWeight(graph.addEdge(source, sink), section.getDistance()); } + protected GraphPath compute(Station source, Station sink) { + this.validateSource(source); + this.validateSink(sink); + DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath<>(graph); + return dijkstraShortestPath.getPath(source, sink); + } + + private void validateSource(Station source) { + if (!graph.containsVertex(source)) { + throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); + } + } + + private void validateSink(Station sink) { + if (!graph.containsVertex(sink)) { + throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); + } + } + protected void deleteAllNode() { Set nodes = new HashSet<>(this.findAllNode()); graph.removeAllVertices(nodes); diff --git a/src/main/java/subway/domain/station/Station.java b/src/main/java/subway/domain/station/Station.java index 4edcd1b5b..c99e231bc 100644 --- a/src/main/java/subway/domain/station/Station.java +++ b/src/main/java/subway/domain/station/Station.java @@ -8,6 +8,7 @@ public class Station { private static final String SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; private final String name; private final List
sectionList = new ArrayList<>(); @@ -34,4 +35,20 @@ public void validateSection(Section section) { throw new IllegalArgumentException(SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE); } } + + public int findDistanceTo(Station sink) { + return this.sectionList.stream() + .filter(section -> section.getSink() == sink) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE)) + .getDistance(); + } + + public int findTimeTo(Station sink) { + return this.sectionList.stream() + .filter(section -> section.getSink() == sink) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE)) + .getTime(); + } } diff --git a/src/main/java/subway/domain/station/StationDTO.java b/src/main/java/subway/domain/station/StationDTO.java index 4b50534eb..b22b88cee 100644 --- a/src/main/java/subway/domain/station/StationDTO.java +++ b/src/main/java/subway/domain/station/StationDTO.java @@ -1,5 +1,7 @@ package subway.domain.station; +import java.util.Objects; + public class StationDTO { private static final String STATION_NAME_ESSENTIAL_MESSAGE = "์—ญ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; @@ -19,4 +21,12 @@ private void validate(String name) { public String getName() { return name; } + + @Override + public boolean equals(Object object) { + if(this == object) return true; + if(!(object instanceof StationDTO)) return false; + StationDTO other = (StationDTO)object; + return Objects.equals(this.name, other.name); + } } diff --git a/src/main/java/subway/domain/station/StationService.java b/src/main/java/subway/domain/station/StationService.java index e92dc682a..4374c1ec8 100644 --- a/src/main/java/subway/domain/station/StationService.java +++ b/src/main/java/subway/domain/station/StationService.java @@ -1,6 +1,7 @@ package subway.domain.station; import java.util.List; +import java.util.Optional; public class StationService { private static final String NOT_EXISTS_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์—ญ์ž…๋‹ˆ๋‹ค."; @@ -11,6 +12,10 @@ public Station findOneByName(String name) { .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_STATION_MESSAGE)); } + public Optional findByName(String name) { + return StationRepository.findByName(name); + } + public List findAll() { return StationRepository.stations(); } diff --git a/src/main/java/subway/presentation/SectionController.java b/src/main/java/subway/presentation/SectionController.java index f30a24745..565194277 100644 --- a/src/main/java/subway/presentation/SectionController.java +++ b/src/main/java/subway/presentation/SectionController.java @@ -1,6 +1,8 @@ package subway.presentation; import subway.application.section.dto.SectionDTO; +import subway.application.section.dto.ShortCostRequest; +import subway.application.section.dto.ShortCostResponse; import subway.application.section.service.SectionService; import subway.domain.line.LineDTO; import subway.domain.station.StationDTO; @@ -27,7 +29,7 @@ public void addSection(String lineName, String sourceName, String sinkName, Stri } private void validateDistance(String distance) { - if(distance == null || distance.trim().isEmpty()) { + if (distance == null || distance.trim().isEmpty()) { throw new IllegalArgumentException(INPUT_ESSENTIAL_DISTANCE_MESSAGE); } if (!Validation.isNumeric(distance)) { @@ -36,11 +38,18 @@ private void validateDistance(String distance) { } private void validateTime(String time) { - if(time == null || time.trim().isEmpty()) { + if (time == null || time.trim().isEmpty()) { throw new IllegalArgumentException(INPUT_ESSENTIAL_TIME_MESSAGE); } if (!Validation.isNumeric(time)) { throw new IllegalArgumentException(ONLY_POSSIBLE_NUMERIC_INPUT_TIME_MESSAGE); } } + + public ShortCostResponse computeShortDistance(String sourceName, String sinkName) { + StationDTO sourceDTO = new StationDTO(sourceName); + StationDTO sinkDTO = new StationDTO(sinkName); + ShortCostRequest shortCostRequest = new ShortCostRequest(sourceDTO, sinkDTO); + return this.sectionService.computeShortDistance(shortCostRequest); + } } diff --git a/src/test/java/subway/application/section/dto/ShortCostRequestTest.java b/src/test/java/subway/application/section/dto/ShortCostRequestTest.java new file mode 100644 index 000000000..32cddf44a --- /dev/null +++ b/src/test/java/subway/application/section/dto/ShortCostRequestTest.java @@ -0,0 +1,34 @@ +package subway.application.section.dto; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.station.StationDTO; + +public class ShortCostRequestTest { + @Test + public void new_SourceStationInfoEssentialException() { + StationDTO sinkDTO = new StationDTO("sink"); + String message = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new ShortCostRequest(null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void new_SinkStationInfoEssentialException() { + StationDTO sourceDTO = new StationDTO("source"); + String message = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new ShortCostRequest(sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void new_SameSourceAndSinkStationException() { + StationDTO sourceDTO = new StationDTO("same"); + StationDTO sinkDTO = new StationDTO("same"); + String message = "์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๋™์ผํ•ฉ๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new ShortCostRequest(sourceDTO, sinkDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} diff --git a/src/test/java/subway/application/section/dto/ShortCostResponseTest.java b/src/test/java/subway/application/section/dto/ShortCostResponseTest.java new file mode 100644 index 000000000..d58b355b9 --- /dev/null +++ b/src/test/java/subway/application/section/dto/ShortCostResponseTest.java @@ -0,0 +1,30 @@ +package subway.application.section.dto; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class ShortCostResponseTest { + @Test + public void constructor() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + List stationList = Arrays.asList(source, sink); + int distance = 1; + int time = 8; + Section section = new Section(line, source, sink, distance, time); + source.addSection(section); + ShortCostResponse shortCostResponse = new ShortCostResponse(stationList); + assertThat(shortCostResponse.getTotalDistance()).isEqualTo(distance); + assertThat(shortCostResponse.getTotalTime()).isEqualTo(time); + assertThat(shortCostResponse.getStationNameList()).containsExactly(source.getName(), sink.getName()); + } +} diff --git a/src/test/java/subway/application/section/service/SectionServiceTest.java b/src/test/java/subway/application/section/service/SectionServiceTest.java index 09e78c214..badbc2ca3 100644 --- a/src/test/java/subway/application/section/service/SectionServiceTest.java +++ b/src/test/java/subway/application/section/service/SectionServiceTest.java @@ -7,6 +7,8 @@ import org.junit.jupiter.api.Test; import subway.application.section.dto.SectionDTO; +import subway.application.section.dto.ShortCostRequest; +import subway.application.section.dto.ShortCostResponse; import subway.domain.line.Line; import subway.domain.line.LineDTO; import subway.domain.line.LineService; @@ -22,6 +24,7 @@ public class SectionServiceTest { private final LineService lineService = new LineService(); private final StationService stationService = new StationService(); private final SectionService sectionService = new SectionService(); + private final ShortDistanceService shortDistanceService = new ShortDistanceService(); @BeforeEach public void setup() { @@ -38,6 +41,8 @@ public void addSection() { assertThat(this.sectionService.findAll()).hasSize(0); assertThat(line.getSectionList()).hasSize(0); assertThat(source.getSectionList()).hasSize(0); + this.sectionService.addNode(this.sourceDTO); + this.sectionService.addNode(this.sinkDTO); this.sectionService.addSection(sectionDTO); assertThat(this.sectionService.findAll()).hasSize(1); assertThat(line.getSectionList()).hasSize(1); @@ -48,16 +53,63 @@ public void addSection() { public void addSection__AlreadyExistsSectionException() { SectionDTO sectionDTO = new SectionDTO(lineDTO, sourceDTO, sinkDTO); String message = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ตฌ๊ฐ„์ž…๋‹ˆ๋‹ค."; + this.sectionService.addNode(this.sourceDTO); + this.sectionService.addNode(this.sinkDTO); this.sectionService.addSection(sectionDTO); assertThatThrownBy(() -> this.sectionService.addSection(sectionDTO)).isInstanceOf( IllegalArgumentException.class) .hasMessage(message); } + @Test + public void computeShortDistance() { + int distance = 1; + int time = 8; + SectionDTO sectionDTO = new SectionDTO(this.lineDTO, this.sourceDTO, this.sinkDTO, distance, time); + ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, this.sinkDTO); + this.sectionService.addNode(this.sourceDTO); + this.sectionService.addNode(this.sinkDTO); + this.sectionService.addSection(sectionDTO); + ShortCostResponse shortCostResponse = this.sectionService.computeShortDistance(shortCostRequest); + assertThat(shortCostResponse.getTotalDistance()).isEqualTo(distance); + assertThat(shortCostResponse.getTotalTime()).isEqualTo(time); + assertThat(shortCostResponse.getStationNameList()).containsExactly(this.sourceDTO.getName(), + this.sinkDTO.getName()); + } + + @Test + public void computeShortDistance__NotExistsSourceStationException() { + StationDTO otherDTO = new StationDTO("other"); + ShortCostRequest shortCostRequest = new ShortCostRequest(otherDTO, this.sinkDTO); + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void computeShortDistance__NotExistsSinkStationException() { + StationDTO otherDTO = new StationDTO("other"); + ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, otherDTO); + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void computeShortDistance__NotConnectedSourceAndSinkStationException() { + ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, this.sinkDTO); + String message = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ ์ง€์  ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + this.sectionService.addNode(this.sourceDTO); + this.sectionService.addNode(this.sinkDTO); + assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + @AfterEach public void init() { - lineService.deleteAll(); - stationService.deleteAll(); - sectionService.deleteAll(); + this.lineService.deleteAll(); + this.stationService.deleteAll(); + this.sectionService.deleteAll(); + this.shortDistanceService.deleteAll(); } } diff --git a/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java b/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java index e8a6e84e8..3570da5e0 100644 --- a/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java +++ b/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java @@ -2,6 +2,8 @@ import static org.assertj.core.api.Assertions.*; +import org.jgrapht.GraphPath; +import org.jgrapht.graph.DefaultWeightedEdge; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -70,6 +72,34 @@ public void addEdge_AlreadyExistsEdgeException() { IllegalArgumentException.class).hasMessage(message); } + @Test + public void compute() { + int distance = 7; + Section section = new Section(this.line, this.source, this.sink, distance, 0); + this.shortDistanceService.addNode(this.source); + this.shortDistanceService.addNode(this.sink); + this.shortDistanceService.addEdge(section); + GraphPath graphPath = this.shortDistanceService.compute(this.source, this.sink); + assertThat(graphPath.getWeight()).isEqualTo(distance); + assertThat(graphPath.getVertexList()).containsExactly(this.source, this.sink); + } + + @Test + public void compute__NotExistsSourceNodeException() { + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.sink); + assertThatThrownBy(() -> this.shortDistanceService.compute(this.source, this.sink)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void compute__NotExistsSinkNodeException() { + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.source); + assertThatThrownBy(() -> this.shortDistanceService.compute(this.source, this.sink)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + @AfterEach public void init() { this.shortDistanceService.deleteAll(); diff --git a/src/test/java/subway/domain/station/StationTest.java b/src/test/java/subway/domain/station/StationTest.java index 8e124a692..476f7efc3 100644 --- a/src/test/java/subway/domain/station/StationTest.java +++ b/src/test/java/subway/domain/station/StationTest.java @@ -30,4 +30,44 @@ public void addSection__SectionAddingOtherSourceStationReceiveException() { assertThatThrownBy(() -> source.addSection(section)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } + + @Test + public void findDistanceTo() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + int distance = 1; + Section section = new Section(line, source, sink, distance, 0); + source.addSection(section); + assertThat(source.findDistanceTo(sink)).isEqualTo(distance); + } + + @Test + public void findDistanceTo__NotExistsPathToSinkStationException() { + Station source = new Station("source"); + Station sink = new Station("sink"); + String message = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> source.findDistanceTo(sink)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void findTimeTo() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + int time = 8; + Section section = new Section(line, source, sink, 0, time); + source.addSection(section); + assertThat(source.findTimeTo(sink)).isEqualTo(time); + } + + @Test + public void findTimeTo__NotExistsPathToSinkStationException() { + Station source = new Station("source"); + Station sink = new Station("sink"); + String message = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> source.findTimeTo(sink)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } } From f41ea4ada52bc41b952f6dde625b922df9d40678 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 16:12:34 +0900 Subject: [PATCH 15/45] =?UTF-8?q?docs:=205.=20=EC=B5=9C=EB=8B=A8=20?= =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EA=B2=BD=EB=A1=9C=20=EA=B5=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20-=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 523 ++++++++++++++++++++++++++++++++++++- 1 file changed, 522 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 9bc4709fb..1898417c4 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -1604,4 +1604,525 @@ public class SectionService { } ``` -๋ฌด๋ถ„๋ณ„ํ•œ ๊ฐ„์„  ์ถ”๊ฐ€๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Section Service ๊ณ„์ธต์„ ํ†ตํ•ด์„œ๋งŒ ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ•จ. \ No newline at end of file +๋ฌด๋ถ„๋ณ„ํ•œ ๊ฐ„์„  ์ถ”๊ฐ€๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Section Service ๊ณ„์ธต์„ ํ†ตํ•ด์„œ๋งŒ ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ•จ. + +## 5. ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๊ฒฝ๋กœ ๊ตฌํ•˜๊ธฐ + +```java +// ShortDistanceServiceTest.java + +package subway.application.section.service; + +import static org.assertj.core.api.Assertions.*; + +import org.jgrapht.GraphPath; +import org.jgrapht.graph.DefaultWeightedEdge; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class ShortDistanceServiceTest { + @Test + public void compute__NotExistsSourceNodeException() { + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.sink); + assertThatThrownBy(() -> this.shortDistanceService.compute(this.source, this.sink)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void compute__NotExistsSinkNodeException() { + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + this.shortDistanceService.addNode(this.source); + assertThatThrownBy(() -> this.shortDistanceService.compute(this.source, this.sink)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } +} +``` + +```java +// ShortDistanceService.java + +package subway.application.section.service; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.jgrapht.GraphPath; +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedMultigraph; + +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class ShortDistanceService { + protected GraphPath compute(Station source, Station sink) { + this.validateSource(source); + this.validateSink(sink); + DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath<>(graph); + return dijkstraShortestPath.getPath(source, sink); + } + + private void validateSource(Station source) { + if (!graph.containsVertex(source)) { + throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); + } + } + + private void validateSink(Station sink) { + if (!graph.containsVertex(sink)) { + throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); + } + } +} +``` + +์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๊ฒฝ๋กœ ๋ฐ˜ํ™˜ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// ShortCostRequestTest.java + +package subway.application.section.dto; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.station.StationDTO; + +public class ShortCostRequestTest { + @Test + public void new_SourceStationInfoEssentialException() { + StationDTO sinkDTO = new StationDTO("sink"); + String message = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new ShortCostRequest(null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void new_SinkStationInfoEssentialException() { + StationDTO sourceDTO = new StationDTO("source"); + String message = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new ShortCostRequest(sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void new_SameSourceAndSinkStationException() { + StationDTO sourceDTO = new StationDTO("same"); + StationDTO sinkDTO = new StationDTO("same"); + String message = "์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๋™์ผํ•ฉ๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new ShortCostRequest(sourceDTO, sinkDTO)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} +``` + +```java +// StationDTO.java + +package subway.domain.station; + +import java.util.Objects; + +public class StationDTO { + @Override + public boolean equals(Object object) { + if (this == object) + return true; + if (!(object instanceof StationDTO)) + return false; + StationDTO other = (StationDTO)object; + return Objects.equals(this.name, other.name); + } +} +``` + +๋™์ผ ์ฒดํฌ๋ฅผ ์œ„ํ•ด ์ด๋ฆ„ ๊ธฐ์ค€์œผ๋กœ ๋น„๊ต๋˜๋„๋ก equal ์˜ค๋ฒ„๋ผ์ด๋”ฉ. + +```java +// ShortCostRequest.java + +package subway.application.section.dto; + +import subway.domain.station.StationDTO; + +public class ShortCostRequest { + private static final String SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SINK_STATION_INFO_ESSENTIAL_MESSAGE = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SAME_SOURCE_AND_SINK_STATION_MESSAGE = "์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๋™์ผํ•ฉ๋‹ˆ๋‹ค."; + + private final StationDTO sourceDTO; + private final StationDTO sinkDTO; + + public ShortCostRequest(StationDTO sourceDTO, StationDTO sinkDTO) { + this.validate(sourceDTO, sinkDTO); + this.sourceDTO = sourceDTO; + this.sinkDTO = sinkDTO; + } + + private void validate(StationDTO sourceDTO, StationDTO sinkDTO) { + if (sourceDTO == null) { + throw new IllegalArgumentException(SOURCE_STATION_INFO_ESSENTIAL_MESSAGE); + } + if (sinkDTO == null) { + throw new IllegalArgumentException(SINK_STATION_INFO_ESSENTIAL_MESSAGE); + } + if (sourceDTO.equals(sinkDTO)) { + throw new IllegalArgumentException(SAME_SOURCE_AND_SINK_STATION_MESSAGE); + } + } + + public StationDTO getSourceDTO() { + return sourceDTO; + } + + public StationDTO getSinkDTO() { + return sinkDTO; + } +} +``` + +์ตœ๋‹จ(์ตœ์†Œ) ๊ฒฝ๋กœ ๊ณ„์‚ฐ ์š”์ฒญ DTO ๊ตฌํ˜„. + +```java +// ShortCostResponseTest.java + +package subway.application.section.dto; + +import static org.assertj.core.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.section.Section; +import subway.domain.station.Station; + +public class ShortCostResponseTest { + @Test + public void constructor() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + List stationList = Arrays.asList(source, sink); + int distance = 1; + int time = 8; + Section section = new Section(line, source, sink, distance, time); + source.addSection(section); + ShortCostResponse shortCostResponse = new ShortCostResponse(stationList); + assertThat(shortCostResponse.getTotalDistance()).isEqualTo(distance); + assertThat(shortCostResponse.getTotalTime()).isEqualTo(time); + assertThat(shortCostResponse.getStationNameList()).containsExactly(source.getName(), sink.getName()); + } +} +``` + +```java +// StationTest.java + +package subway.domain.station; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import subway.domain.line.Line; +import subway.domain.section.Section; + +public class StationTest { + @Test + public void findDistanceTo() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + int distance = 1; + Section section = new Section(line, source, sink, distance, 0); + source.addSection(section); + assertThat(source.findDistanceTo(sink)).isEqualTo(distance); + } + + @Test + public void findDistanceTo__NotExistsPathToSinkStationException() { + Station source = new Station("source"); + Station sink = new Station("sink"); + String message = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> source.findDistanceTo(sink)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void findTimeTo() { + Line line = new Line("line"); + Station source = new Station("source"); + Station sink = new Station("sink"); + int time = 8; + Section section = new Section(line, source, sink, 0, time); + source.addSection(section); + assertThat(source.findTimeTo(sink)).isEqualTo(time); + } + + @Test + public void findTimeTo__NotExistsPathToSinkStationException() { + Station source = new Station("source"); + Station sink = new Station("sink"); + String message = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> source.findTimeTo(sink)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } +} +``` + +```java +// Station.java + +package subway.domain.station; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import subway.domain.section.Section; + +public class Station { + private static final String NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + + public int findDistanceTo(Station sink) { + return this.sectionList.stream() + .filter(section -> section.getSink() == sink) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE)) + .getDistance(); + } + + public int findTimeTo(Station sink) { + return this.sectionList.stream() + .filter(section -> section.getSink() == sink) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE)) + .getTime(); + } +} +``` + +์ง€์ • ๊ฒฝ๋กœ๊นŒ์ง€์˜ ๊ฑฐ๋ฆฌ์™€ ์‹œ๊ฐ„์„ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// ShortCostResponse.java + +package subway.application.section.dto; + +import java.util.ArrayList; +import java.util.List; + +import subway.domain.station.Station; + +public class ShortCostResponse { + private int totalDistance; + private int totalTime; + private final List stationNameList; + + public ShortCostResponse(List stationList) { + this.stationNameList = new ArrayList<>(); + int length = stationList.size(); + for (int index = 0; index < length; index++) { + Station source = stationList.get(index); + if (index + 1 < length) { + Station sink = stationList.get(index + 1); + totalDistance += source.findDistanceTo(sink); + totalTime += source.findTimeTo(sink); + } + stationNameList.add(source.getName()); + } + } + + public int getTotalDistance() { + return totalDistance; + } + + public void setTotalDistance(int totalDistance) { + this.totalDistance = totalDistance; + } + + public int getTotalTime() { + return totalTime; + } + + public void setTotalTime(int totalTime) { + this.totalTime = totalTime; + } + + public List getStationNameList() { + return stationNameList; + } +} +``` + +์ง€์ • ๊ฒฝ๋กœ๊นŒ์ง€ ์ด ๊ฑฐ๋ฆฌ, ์‹œ๊ฐ„๊ณผ ์œ„์น˜ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„. + +```java +// SectionServiceTest.java + +package subway.application.section.service; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import subway.application.section.dto.SectionDTO; +import subway.application.section.dto.ShortCostRequest; +import subway.application.section.dto.ShortCostResponse; +import subway.domain.line.Line; +import subway.domain.line.LineDTO; +import subway.domain.line.LineService; +import subway.domain.station.Station; +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class SectionServiceTest { + private final ShortDistanceService shortDistanceService = new ShortDistanceService(); + + @Test + public void computeShortDistance() { + int distance = 1; + int time = 8; + SectionDTO sectionDTO = new SectionDTO(this.lineDTO, this.sourceDTO, this.sinkDTO, distance, time); + ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, this.sinkDTO); + this.sectionService.addNode(this.sourceDTO); + this.sectionService.addNode(this.sinkDTO); + this.sectionService.addSection(sectionDTO); + ShortCostResponse shortCostResponse = this.sectionService.computeShortDistance(shortCostRequest); + assertThat(shortCostResponse.getTotalDistance()).isEqualTo(distance); + assertThat(shortCostResponse.getTotalTime()).isEqualTo(time); + assertThat(shortCostResponse.getStationNameList()).containsExactly(this.sourceDTO.getName(), + this.sinkDTO.getName()); + } + + @Test + public void computeShortDistance__NotExistsSourceStationException() { + StationDTO otherDTO = new StationDTO("other"); + ShortCostRequest shortCostRequest = new ShortCostRequest(otherDTO, this.sinkDTO); + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void computeShortDistance__NotExistsSinkStationException() { + StationDTO otherDTO = new StationDTO("other"); + ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, otherDTO); + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void computeShortDistance__NotConnectedSourceAndSinkStationException() { + ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, this.sinkDTO); + String message = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ ์ง€์  ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + this.sectionService.addNode(this.sourceDTO); + this.sectionService.addNode(this.sinkDTO); + assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @AfterEach + public void init() { + this.lineService.deleteAll(); + this.stationService.deleteAll(); + this.sectionService.deleteAll(); + this.shortDistanceService.deleteAll(); + } +} +``` + +```java +// StationService.java + +package subway.domain.station; + +import java.util.List; +import java.util.Optional; + +public class StationService { + public Optional findByName(String name) { + return StationRepository.findByName(name); + } +} +``` + +```java +// SectionService.java + +package subway.application.section.service; + +import java.util.List; + +import org.jgrapht.GraphPath; +import org.jgrapht.graph.DefaultWeightedEdge; + +import subway.application.section.dto.SectionDTO; +import subway.application.section.dto.ShortCostRequest; +import subway.application.section.dto.ShortCostResponse; +import subway.domain.line.Line; +import subway.domain.line.LineService; +import subway.domain.section.Section; +import subway.domain.section.SectionRepository; +import subway.domain.station.Station; +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class SectionService { + private static final String NOT_EXISTS_SOURCE_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ ์ง€์  ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + + public ShortCostResponse computeShortDistance(ShortCostRequest shortCostRequest) { + Station source = this.stationService.findByName(shortCostRequest.getSourceDTO().getName()) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SOURCE_STATION_MESSAGE)); + Station sink = this.stationService.findByName(shortCostRequest.getSinkDTO().getName()) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SINK_STATION_MESSAGE)); + GraphPath graphPath = this.shortDistanceService.compute(source, sink); + if (graphPath == null) { + throw new IllegalArgumentException(NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE); + } + return new ShortCostResponse(graphPath.getVertexList()); + } +} +``` + +์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ ๊ตฌํ˜„. + +```java +// SectionController.java + +package subway.presentation; + +import subway.application.section.dto.SectionDTO; +import subway.application.section.dto.ShortCostRequest; +import subway.application.section.dto.ShortCostResponse; +import subway.application.section.service.SectionService; +import subway.domain.line.LineDTO; +import subway.domain.station.StationDTO; +import subway.util.Validation; + +public class SectionController { + public ShortCostResponse computeShortDistance(String sourceName, String sinkName) { + StationDTO sourceDTO = new StationDTO(sourceName); + StationDTO sinkDTO = new StationDTO(sinkName); + ShortCostRequest shortCostRequest = new ShortCostRequest(sourceDTO, sinkDTO); + return this.sectionService.computeShortDistance(shortCostRequest); + } +} +``` + +์ œ์–ด ๊ณ„์ธต์— ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ ๊ธฐ๋Šฅ ๋งคํ•‘. \ No newline at end of file From 6040632aa1546559cd6dc5062e9734634c0a0e62 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 16:26:56 +0900 Subject: [PATCH 16/45] =?UTF-8?q?refactor:=204.=20=EC=B5=9C=EB=8B=A8=20?= =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EB=85=B8=EB=93=9C,=20=EA=B0=84=EC=84=A0?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20-=20[solving=5Fprocess.md]=20=ED=92=80?= =?UTF-8?q?=EC=9D=B4=20=EC=88=98=EC=A0=95=20-=20[ShortDistanceService.java?= =?UTF-8?q?]=20=EC=9D=B8=EB=9D=BC=EC=9D=B8=20source,=20sink=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=BD=94=EB=93=9C=EB=A5=BC=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD,=20public=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=20=EC=A0=9C=EC=96=B4=EC=9E=90=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 44 +++++++++---------- .../section/service/ShortDistanceService.java | 10 ++--- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 1898417c4..514eea57a 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -1334,7 +1334,7 @@ import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.station.Station; -public class ShortDistanceService { +class shortDistanceService { private static final DirectedWeightedMultigraph graph = new DirectedWeightedMultigraph<>( DefaultWeightedEdge.class); @@ -1363,7 +1363,7 @@ import org.junit.jupiter.api.Test; import subway.domain.station.Station; -public class ShortDistanceServiceTest { +class shortDistanceServiceTest { private final Station source = new Station("source"); private final ShortDistanceService shortDistanceService = new ShortDistanceService(); @@ -1403,7 +1403,7 @@ import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.station.Station; -public class ShortDistanceService { +class shortDistanceService { private static final String ALREADY_EXISTS_NODE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; protected void addNode(Station station) { @@ -1460,7 +1460,7 @@ import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.station.Station; -public class ShortDistanceService { +class shortDistanceService { protected Set findAllEdge() { return Collections.unmodifiableSet(graph.edgeSet()); } @@ -1492,7 +1492,7 @@ import subway.domain.line.Line; import subway.domain.section.Section; import subway.domain.station.Station; -public class ShortDistanceServiceTest { +class shortDistanceServiceTest { private final Line line = new Line("line"); private final Station sink = new Station("sink"); @@ -1547,7 +1547,7 @@ import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.section.Section; import subway.domain.station.Station; -public class ShortDistanceService { +class shortDistanceService { private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; private static final String ALREADY_EXISTS_EDGE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; @@ -1555,16 +1555,24 @@ public class ShortDistanceService { protected void addEdge(Section section) { Station source = section.getSource(); Station sink = section.getSink(); + this.validateSource(source); + this.validateSink(sink); + if (graph.containsEdge(source, sink)) { + throw new IllegalArgumentException(ALREADY_EXISTS_EDGE_MESSAGE); + } + graph.setEdgeWeight(graph.addEdge(source, sink), section.getDistance()); + } + + private void validateSource(Station source) { if (!graph.containsVertex(source)) { throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); } + } + + private void validateSink(Station sink) { if (!graph.containsVertex(sink)) { throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); } - if (graph.containsEdge(source, sink)) { - throw new IllegalArgumentException(ALREADY_EXISTS_EDGE_MESSAGE); - } - graph.setEdgeWeight(graph.addEdge(source, sink), section.getDistance()); } } ``` @@ -1624,7 +1632,7 @@ import subway.domain.line.Line; import subway.domain.section.Section; import subway.domain.station.Station; -public class ShortDistanceServiceTest { +class shortDistanceServiceTest { @Test public void compute__NotExistsSourceNodeException() { String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; @@ -1660,25 +1668,13 @@ import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.section.Section; import subway.domain.station.Station; -public class ShortDistanceService { +class shortDistanceService { protected GraphPath compute(Station source, Station sink) { this.validateSource(source); this.validateSink(sink); DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath<>(graph); return dijkstraShortestPath.getPath(source, sink); } - - private void validateSource(Station source) { - if (!graph.containsVertex(source)) { - throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); - } - } - - private void validateSink(Station sink) { - if (!graph.containsVertex(sink)) { - throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); - } - } } ``` diff --git a/src/main/java/subway/application/section/service/ShortDistanceService.java b/src/main/java/subway/application/section/service/ShortDistanceService.java index 6c2a302f1..4eb6ce2c1 100644 --- a/src/main/java/subway/application/section/service/ShortDistanceService.java +++ b/src/main/java/subway/application/section/service/ShortDistanceService.java @@ -12,7 +12,7 @@ import subway.domain.section.Section; import subway.domain.station.Station; -public class ShortDistanceService { +class ShortDistanceService { private static final DirectedWeightedMultigraph graph = new DirectedWeightedMultigraph<>( DefaultWeightedEdge.class); @@ -39,12 +39,8 @@ protected void addNode(Station station) { protected void addEdge(Section section) { Station source = section.getSource(); Station sink = section.getSink(); - if (!graph.containsVertex(source)) { - throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); - } - if (!graph.containsVertex(sink)) { - throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); - } + this.validateSource(source); + this.validateSink(sink); if (graph.containsEdge(source, sink)) { throw new IllegalArgumentException(ALREADY_EXISTS_EDGE_MESSAGE); } From 02bed473b7e1b254453b2d10b4affc2a6d5108f6 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 16:30:50 +0900 Subject: [PATCH 17/45] =?UTF-8?q?refactor:=201.=20Line=20CRUD=20-=20[solvi?= =?UTF-8?q?ng=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=88=98=EC=A0=95=20-?= =?UTF-8?q?=20[LineDTOTest.java]=20new=5F=5F*=20=E2=86=92=20constructor=5F?= =?UTF-8?q?=5F*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 2 +- src/test/java/subway/domain/line/LineDTOTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 514eea57a..72a88cd7d 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -75,7 +75,7 @@ import org.junit.jupiter.api.Test; public class LineDTOTest { @Test - public void new__LineNameEssentialException() { + public void constructor__LineNameEssentialException() { String message = "๋…ธ์„  ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new LineDTO(null)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); diff --git a/src/test/java/subway/domain/line/LineDTOTest.java b/src/test/java/subway/domain/line/LineDTOTest.java index 7f91e3eaf..6cdc8fe0d 100644 --- a/src/test/java/subway/domain/line/LineDTOTest.java +++ b/src/test/java/subway/domain/line/LineDTOTest.java @@ -6,7 +6,7 @@ public class LineDTOTest { @Test - public void new__LineNameEssentialException() { + public void constructor__LineNameEssentialException() { String message = "๋…ธ์„  ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new LineDTO(null)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); From 14eaf9aa901534ff46abb4551c3f511d0379fd10 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 16:31:57 +0900 Subject: [PATCH 18/45] =?UTF-8?q?refactor:=202.=20Station=20CRUD=20-=20[so?= =?UTF-8?q?lving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20-=20[StationDTOTest.java]=20new=5F=5F*=20=E2=86=92=20constru?= =?UTF-8?q?ctor=5F=5F*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 2 +- src/test/java/subway/domain/station/StationDTOTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 72a88cd7d..2ef68e400 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -361,7 +361,7 @@ import org.junit.jupiter.api.Test; public class StationDTOTest { @Test - public void new__StationNameEssentialException() { + public void constructor__StationNameEssentialException() { String message = "์—ญ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new StationDTO(null)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); diff --git a/src/test/java/subway/domain/station/StationDTOTest.java b/src/test/java/subway/domain/station/StationDTOTest.java index 97173f4dc..76ea8b460 100644 --- a/src/test/java/subway/domain/station/StationDTOTest.java +++ b/src/test/java/subway/domain/station/StationDTOTest.java @@ -6,7 +6,7 @@ public class StationDTOTest { @Test - public void new__StationNameEssentialException() { + public void constructor__StationNameEssentialException() { String message = "์—ญ ์ด๋ฆ„์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new StationDTO(null)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); From c6474001cca2100cfa0f741835395e1f90a3caba Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 16:33:23 +0900 Subject: [PATCH 19/45] =?UTF-8?q?refactor:=203.=20Section=20CRUD=20-=20[so?= =?UTF-8?q?lving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20-=20[SectionDTOTest.java]=20new=5F=5F*=20=E2=86=92=20constru?= =?UTF-8?q?ctor=5F=5F*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 6 +++--- .../java/subway/application/section/dto/SectionDTOTest.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 2ef68e400..a93fde4e3 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -844,7 +844,7 @@ import subway.domain.station.StationDTO; public class SectionDTOTest { @Test - public void new__SectionAddingLineInfoEssentialException() { + public void constructor__SectionAddingLineInfoEssentialException() { StationDTO sourceDTO = new StationDTO("source"); StationDTO sinkDTO = new StationDTO("sink"); String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ๋…ธ์„  ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; @@ -853,7 +853,7 @@ public class SectionDTOTest { } @Test - public void new__SectionAddingSourceStationInfoEssentialException() { + public void constructor__SectionAddingSourceStationInfoEssentialException() { LineDTO lineDTO = new LineDTO("line"); StationDTO sinkDTO = new StationDTO("sink"); String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; @@ -862,7 +862,7 @@ public class SectionDTOTest { } @Test - public void new__SectionAddingSinkStationInfoEssentialException() { + public void constructor__SectionAddingSinkStationInfoEssentialException() { LineDTO lineDTO = new LineDTO("line"); StationDTO sourceDTO = new StationDTO("source"); String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; diff --git a/src/test/java/subway/application/section/dto/SectionDTOTest.java b/src/test/java/subway/application/section/dto/SectionDTOTest.java index 559067d38..d561ad7d0 100644 --- a/src/test/java/subway/application/section/dto/SectionDTOTest.java +++ b/src/test/java/subway/application/section/dto/SectionDTOTest.java @@ -9,7 +9,7 @@ public class SectionDTOTest { @Test - public void new__SectionAddingLineInfoEssentialException() { + public void constructor__SectionAddingLineInfoEssentialException() { StationDTO sourceDTO = new StationDTO("source"); StationDTO sinkDTO = new StationDTO("sink"); String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ๋…ธ์„  ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; @@ -18,7 +18,7 @@ public void new__SectionAddingLineInfoEssentialException() { } @Test - public void new__SectionAddingSourceStationInfoEssentialException() { + public void constructor__SectionAddingSourceStationInfoEssentialException() { LineDTO lineDTO = new LineDTO("line"); StationDTO sinkDTO = new StationDTO("sink"); String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; @@ -27,7 +27,7 @@ public void new__SectionAddingSourceStationInfoEssentialException() { } @Test - public void new__SectionAddingSinkStationInfoEssentialException() { + public void constructor__SectionAddingSinkStationInfoEssentialException() { LineDTO lineDTO = new LineDTO("line"); StationDTO sourceDTO = new StationDTO("source"); String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; From 226bcb8b7d07f3f1c635f742783a13ea43569425 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 16:34:50 +0900 Subject: [PATCH 20/45] =?UTF-8?q?refactor:=205.=20=EC=B5=9C=EB=8B=A8=20?= =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EA=B2=BD=EB=A1=9C=20=EA=B5=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20-=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20-=20[ShortCostRequestTest.java]=20new=5F*?= =?UTF-8?q?=20=E2=86=92=20constructor=5F=5F*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 6 +++--- .../application/section/dto/ShortCostRequestTest.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index a93fde4e3..3b9e8c1d7 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -1693,7 +1693,7 @@ import subway.domain.station.StationDTO; public class ShortCostRequestTest { @Test - public void new_SourceStationInfoEssentialException() { + public void constructor__SourceStationInfoEssentialException() { StationDTO sinkDTO = new StationDTO("sink"); String message = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new ShortCostRequest(null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) @@ -1701,7 +1701,7 @@ public class ShortCostRequestTest { } @Test - public void new_SinkStationInfoEssentialException() { + public void constructor__SinkStationInfoEssentialException() { StationDTO sourceDTO = new StationDTO("source"); String message = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new ShortCostRequest(sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) @@ -1709,7 +1709,7 @@ public class ShortCostRequestTest { } @Test - public void new_SameSourceAndSinkStationException() { + public void constructor__SameSourceAndSinkStationException() { StationDTO sourceDTO = new StationDTO("same"); StationDTO sinkDTO = new StationDTO("same"); String message = "์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๋™์ผํ•ฉ๋‹ˆ๋‹ค."; diff --git a/src/test/java/subway/application/section/dto/ShortCostRequestTest.java b/src/test/java/subway/application/section/dto/ShortCostRequestTest.java index 32cddf44a..138bf1dac 100644 --- a/src/test/java/subway/application/section/dto/ShortCostRequestTest.java +++ b/src/test/java/subway/application/section/dto/ShortCostRequestTest.java @@ -8,7 +8,7 @@ public class ShortCostRequestTest { @Test - public void new_SourceStationInfoEssentialException() { + public void constructor__SourceStationInfoEssentialException() { StationDTO sinkDTO = new StationDTO("sink"); String message = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new ShortCostRequest(null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) @@ -16,7 +16,7 @@ public void new_SourceStationInfoEssentialException() { } @Test - public void new_SinkStationInfoEssentialException() { + public void constructor__SinkStationInfoEssentialException() { StationDTO sourceDTO = new StationDTO("source"); String message = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new ShortCostRequest(sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) @@ -24,7 +24,7 @@ public void new_SinkStationInfoEssentialException() { } @Test - public void new_SameSourceAndSinkStationException() { + public void constructor__SameSourceAndSinkStationException() { StationDTO sourceDTO = new StationDTO("same"); StationDTO sinkDTO = new StationDTO("same"); String message = "์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๋™์ผํ•ฉ๋‹ˆ๋‹ค."; From a35877acf05c70452eae98e678313f04441f171b Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 16:58:36 +0900 Subject: [PATCH 21/45] =?UTF-8?q?feat:=206.=20=EA=B7=B8=EB=9E=98=ED=94=84?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../section/service/ShortCostService.java | 87 +++++++++++++++++++ .../section/service/ShortDistanceService.java | 78 ++--------------- 2 files changed, 94 insertions(+), 71 deletions(-) create mode 100644 src/main/java/subway/application/section/service/ShortCostService.java diff --git a/src/main/java/subway/application/section/service/ShortCostService.java b/src/main/java/subway/application/section/service/ShortCostService.java new file mode 100644 index 000000000..b898aaf0b --- /dev/null +++ b/src/main/java/subway/application/section/service/ShortCostService.java @@ -0,0 +1,87 @@ +package subway.application.section.service; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.jgrapht.GraphPath; +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; +import org.jgrapht.graph.AbstractBaseGraph; +import org.jgrapht.graph.DefaultWeightedEdge; + +import subway.domain.section.Section; +import subway.domain.station.Station; + +abstract class ShortCostService { + protected final AbstractBaseGraph graph; + + public ShortCostService(AbstractBaseGraph graph) { + this.graph = graph; + } + + private static final String ALREADY_EXISTS_NODE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String ALREADY_EXISTS_EDGE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; + + protected Set findAllNode() { + return Collections.unmodifiableSet(graph.vertexSet()); + } + + protected Set findAllEdge() { + return Collections.unmodifiableSet(graph.edgeSet()); + } + + protected void addNode(Station station) { + if (graph.containsVertex(station)) { + throw new IllegalArgumentException(ALREADY_EXISTS_NODE_MESSAGE); + } + graph.addVertex(station); + } + + protected void addEdge(Section section) { + Station source = section.getSource(); + Station sink = section.getSink(); + this.validateSource(source); + this.validateSink(sink); + if (graph.containsEdge(source, sink)) { + throw new IllegalArgumentException(ALREADY_EXISTS_EDGE_MESSAGE); + } + graph.setEdgeWeight(graph.addEdge(source, sink), this.getWeight(section)); + } + + protected abstract double getWeight(Section section); + + protected GraphPath compute(Station source, Station sink) { + this.validateSource(source); + this.validateSink(sink); + DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath<>(graph); + return dijkstraShortestPath.getPath(source, sink); + } + + protected void validateSource(Station source) { + if (!graph.containsVertex(source)) { + throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); + } + } + + protected void validateSink(Station sink) { + if (!graph.containsVertex(sink)) { + throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); + } + } + + protected void deleteAllNode() { + Set nodes = new HashSet<>(this.findAllNode()); + graph.removeAllVertices(nodes); + } + + protected void deleteAllEdge() { + graph.removeAllEdges(graph.edgeSet()); + } + + protected void deleteAll() { + this.deleteAllEdge(); + this.deleteAllNode(); + } +} diff --git a/src/main/java/subway/application/section/service/ShortDistanceService.java b/src/main/java/subway/application/section/service/ShortDistanceService.java index 4eb6ce2c1..e42f2302c 100644 --- a/src/main/java/subway/application/section/service/ShortDistanceService.java +++ b/src/main/java/subway/application/section/service/ShortDistanceService.java @@ -1,82 +1,18 @@ package subway.application.section.service; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.jgrapht.GraphPath; -import org.jgrapht.alg.shortestpath.DijkstraShortestPath; import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.section.Section; -import subway.domain.station.Station; - -class ShortDistanceService { - private static final DirectedWeightedMultigraph graph = new DirectedWeightedMultigraph<>( - DefaultWeightedEdge.class); - - private static final String ALREADY_EXISTS_NODE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; - private static final String ALREADY_EXISTS_EDGE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; - - protected Set findAllNode() { - return Collections.unmodifiableSet(graph.vertexSet()); - } - - protected Set findAllEdge() { - return Collections.unmodifiableSet(graph.edgeSet()); - } - - protected void addNode(Station station) { - if (graph.containsVertex(station)) { - throw new IllegalArgumentException(ALREADY_EXISTS_NODE_MESSAGE); - } - graph.addVertex(station); - } - - protected void addEdge(Section section) { - Station source = section.getSource(); - Station sink = section.getSink(); - this.validateSource(source); - this.validateSink(sink); - if (graph.containsEdge(source, sink)) { - throw new IllegalArgumentException(ALREADY_EXISTS_EDGE_MESSAGE); - } - graph.setEdgeWeight(graph.addEdge(source, sink), section.getDistance()); - } - - protected GraphPath compute(Station source, Station sink) { - this.validateSource(source); - this.validateSink(sink); - DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath<>(graph); - return dijkstraShortestPath.getPath(source, sink); - } - - private void validateSource(Station source) { - if (!graph.containsVertex(source)) { - throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); - } - } - - private void validateSink(Station sink) { - if (!graph.containsVertex(sink)) { - throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); - } - } - - protected void deleteAllNode() { - Set nodes = new HashSet<>(this.findAllNode()); - graph.removeAllVertices(nodes); - } - protected void deleteAllEdge() { - graph.removeAllEdges(graph.edgeSet()); +class ShortDistanceService extends ShortCostService { + public ShortDistanceService() { + super(new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class)); } - protected void deleteAll() { - this.deleteAllEdge(); - this.deleteAllNode(); + @Override + protected double getWeight(Section section) { + return section.getDistance(); } } From 768e1636f9a08f22bcde5015b41d1c26bd393479 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 17:06:26 +0900 Subject: [PATCH 22/45] =?UTF-8?q?docs:=206.=20=EA=B7=B8=EB=9E=98=ED=94=84?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20=ED=86=B5=ED=95=A9?= =?UTF-8?q?=20-=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 122 ++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 3b9e8c1d7..0c2f75d78 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -2121,4 +2121,124 @@ public class SectionController { } ``` -์ œ์–ด ๊ณ„์ธต์— ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ ๊ธฐ๋Šฅ ๋งคํ•‘. \ No newline at end of file +์ œ์–ด ๊ณ„์ธต์— ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ ๊ธฐ๋Šฅ ๋งคํ•‘. + +## 6. ๊ทธ๋ž˜ํ”„ ๊ด€๋ จ ๊ธฐ๋Šฅ ํ†ตํ•ฉ + +```java +// ShortCostService.java + +package subway.application.section.service; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.jgrapht.GraphPath; +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; +import org.jgrapht.graph.AbstractBaseGraph; +import org.jgrapht.graph.DefaultWeightedEdge; + +import subway.domain.section.Section; +import subway.domain.station.Station; + +abstract class ShortCostService { + protected final AbstractBaseGraph graph; + + public ShortCostService(AbstractBaseGraph graph) { + this.graph = graph; + } + + private static final String ALREADY_EXISTS_NODE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String ALREADY_EXISTS_EDGE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; + + protected Set findAllNode() { + return Collections.unmodifiableSet(graph.vertexSet()); + } + + protected Set findAllEdge() { + return Collections.unmodifiableSet(graph.edgeSet()); + } + + protected void addNode(Station station) { + if (graph.containsVertex(station)) { + throw new IllegalArgumentException(ALREADY_EXISTS_NODE_MESSAGE); + } + graph.addVertex(station); + } + + protected void addEdge(Section section) { + Station source = section.getSource(); + Station sink = section.getSink(); + this.validateSource(source); + this.validateSink(sink); + if (graph.containsEdge(source, sink)) { + throw new IllegalArgumentException(ALREADY_EXISTS_EDGE_MESSAGE); + } + graph.setEdgeWeight(graph.addEdge(source, sink), this.getWeight(section)); + } + + protected abstract double getWeight(Section section); + + protected GraphPath compute(Station source, Station sink) { + this.validateSource(source); + this.validateSink(sink); + DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath<>(graph); + return dijkstraShortestPath.getPath(source, sink); + } + + protected void validateSource(Station source) { + if (!graph.containsVertex(source)) { + throw new IllegalArgumentException(NOT_EXISTS_SOURCE_NODE_MESSAGE); + } + } + + protected void validateSink(Station sink) { + if (!graph.containsVertex(sink)) { + throw new IllegalArgumentException(NOT_EXISTS_SINK_NODE_MESSAGE); + } + } + + protected void deleteAllNode() { + Set nodes = new HashSet<>(this.findAllNode()); + graph.removeAllVertices(nodes); + } + + protected void deleteAllEdge() { + graph.removeAllEdges(graph.edgeSet()); + } + + protected void deleteAll() { + this.deleteAllEdge(); + this.deleteAllNode(); + } +} + +``` + +```java +// ShortDistanceService.java + +package subway.application.section.service; + +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedMultigraph; + +import subway.domain.section.Section; + +class ShortDistanceService extends ShortCostService { + public ShortDistanceService() { + super(new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class)); + } + + @Override + protected double getWeight(Section section) { + return section.getDistance(); + } +} +``` + +์ดํ›„์— ๊ตฌํ˜„๋  ์ตœ์†Œ ์‹œ๊ฐ„ ๊ฒฝ๋กœ์™€ ๊ทธ๋ž˜ํ”„ ๊ด€๋ จ ๊ธฐ๋Šฅ์€ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์ถ”์ƒ ๊ณตํ†ต ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฝ”๋“œ ์ค‘๋ณต ์ค„์ž„. \ No newline at end of file From e705bbae52218a5dc2f2a290ce0675eedc8d19ee Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 17:08:48 +0900 Subject: [PATCH 23/45] =?UTF-8?q?feat:=207.=20=EC=B5=9C=EC=86=8C=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EA=B2=BD=EB=A1=9C=20=EA=B5=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../section/service/SectionService.java | 17 ++++++++++++++++- .../section/service/ShortTimeService.java | 18 ++++++++++++++++++ .../subway/presentation/StationController.java | 6 ++++-- .../section/service/SectionServiceTest.java | 2 ++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/main/java/subway/application/section/service/ShortTimeService.java diff --git a/src/main/java/subway/application/section/service/SectionService.java b/src/main/java/subway/application/section/service/SectionService.java index 522162812..f38fa73ba 100644 --- a/src/main/java/subway/application/section/service/SectionService.java +++ b/src/main/java/subway/application/section/service/SectionService.java @@ -25,6 +25,7 @@ public class SectionService { private final LineService lineService = new LineService(); private final StationService stationService = new StationService(); private final ShortDistanceService shortDistanceService = new ShortDistanceService(); + private final ShortTimeService shortTimeService = new ShortTimeService(); public List
findAll() { return SectionRepository.sections(); @@ -33,6 +34,7 @@ public List
findAll() { public void addNode(StationDTO stationDTO) { Station station = this.stationService.findOneByName(stationDTO.getName()); this.shortDistanceService.addNode(station); + this.shortTimeService.addNode(station); } public void addSection(SectionDTO sectionDTO) { @@ -44,7 +46,8 @@ public void addSection(SectionDTO sectionDTO) { throw new IllegalArgumentException(ALREADY_EXISTS_SECTION_MESSAGE); } SectionRepository.addSection(section); - shortDistanceService.addEdge(section); + this.shortDistanceService.addEdge(section); + this.shortTimeService.addEdge(section); line.addSection(section); source.addSection(section); } @@ -61,6 +64,18 @@ public ShortCostResponse computeShortDistance(ShortCostRequest shortCostRequest) return new ShortCostResponse(graphPath.getVertexList()); } + public ShortCostResponse computeShortTime(ShortCostRequest shortCostRequest) { + Station source = this.stationService.findByName(shortCostRequest.getSourceDTO().getName()) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SOURCE_STATION_MESSAGE)); + Station sink = this.stationService.findByName(shortCostRequest.getSinkDTO().getName()) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SINK_STATION_MESSAGE)); + GraphPath graphPath = this.shortDistanceService.compute(source, sink); + if (graphPath == null) { + throw new IllegalArgumentException(NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE); + } + return new ShortCostResponse(graphPath.getVertexList()); + } + public void deleteAll() { SectionRepository.deleteAll(); } diff --git a/src/main/java/subway/application/section/service/ShortTimeService.java b/src/main/java/subway/application/section/service/ShortTimeService.java new file mode 100644 index 000000000..18ae15fcd --- /dev/null +++ b/src/main/java/subway/application/section/service/ShortTimeService.java @@ -0,0 +1,18 @@ +package subway.application.section.service; + +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedMultigraph; + +import subway.domain.section.Section; + +class ShortTimeService extends ShortCostService { + public ShortTimeService() { + super(new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class)); + } + + @Override + protected double getWeight(Section section) { + return section.getTime(); + } +} diff --git a/src/main/java/subway/presentation/StationController.java b/src/main/java/subway/presentation/StationController.java index a2aecfd72..84af3844c 100644 --- a/src/main/java/subway/presentation/StationController.java +++ b/src/main/java/subway/presentation/StationController.java @@ -1,13 +1,15 @@ package subway.presentation; -import subway.domain.station.StationDTO; +import subway.application.section.service.SectionService;import subway.domain.station.StationDTO; import subway.domain.station.StationService; public class StationController { private final StationService stationService = new StationService(); + private final SectionService sectionService = new SectionService(); public void addStation(String name) { StationDTO stationDTO = new StationDTO(name); - stationService.addStation(stationDTO); + this.stationService.addStation(stationDTO); + this.sectionService.addNode(stationDTO); } } diff --git a/src/test/java/subway/application/section/service/SectionServiceTest.java b/src/test/java/subway/application/section/service/SectionServiceTest.java index badbc2ca3..081254441 100644 --- a/src/test/java/subway/application/section/service/SectionServiceTest.java +++ b/src/test/java/subway/application/section/service/SectionServiceTest.java @@ -25,6 +25,7 @@ public class SectionServiceTest { private final StationService stationService = new StationService(); private final SectionService sectionService = new SectionService(); private final ShortDistanceService shortDistanceService = new ShortDistanceService(); + private final ShortTimeService shortTimeService = new ShortTimeService(); @BeforeEach public void setup() { @@ -111,5 +112,6 @@ public void init() { this.stationService.deleteAll(); this.sectionService.deleteAll(); this.shortDistanceService.deleteAll(); + this.shortTimeService.deleteAll(); } } From 2f0a8be78830ff719c7fd57aa8204be638617406 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 17:31:47 +0900 Subject: [PATCH 24/45] =?UTF-8?q?docs:=207.=20=EC=B5=9C=EC=86=8C=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EA=B2=BD=EB=A1=9C=20=EA=B5=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20-=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 150 ++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 0c2f75d78..f99303e6d 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -2241,4 +2241,152 @@ class ShortDistanceService extends ShortCostService { } ``` -์ดํ›„์— ๊ตฌํ˜„๋  ์ตœ์†Œ ์‹œ๊ฐ„ ๊ฒฝ๋กœ์™€ ๊ทธ๋ž˜ํ”„ ๊ด€๋ จ ๊ธฐ๋Šฅ์€ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์ถ”์ƒ ๊ณตํ†ต ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฝ”๋“œ ์ค‘๋ณต ์ค„์ž„. \ No newline at end of file +์ดํ›„์— ๊ตฌํ˜„๋  ์ตœ์†Œ ์‹œ๊ฐ„ ๊ฒฝ๋กœ์™€ ๊ทธ๋ž˜ํ”„ ๊ด€๋ จ ๊ธฐ๋Šฅ์€ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์ถ”์ƒ ๊ณตํ†ต ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฝ”๋“œ ์ค‘๋ณต ์ค„์ž„. + +## 7. ์ตœ์†Œ ์‹œ๊ฐ„ ๊ฒฝ๋กœ ๊ตฌํ•˜๊ธฐ + +```java +// ShortTimeService.java + +package subway.application.section.service; + +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.DirectedWeightedMultigraph; + +import subway.domain.section.Section; + +class ShortTimeService extends ShortCostService { + public ShortTimeService() { + super(new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class)); + } + + @Override + protected double getWeight(Section section) { + return section.getTime(); + } +} +``` + +์ตœ์†Œ ์‹œ๊ฐ„ ๊ฒฝ๋กœ ๋ฐ˜ํ™˜ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// SectionService.java + +package subway.application.section.service; + +import java.util.List; + +import org.jgrapht.GraphPath; +import org.jgrapht.graph.DefaultWeightedEdge; + +import subway.application.section.dto.SectionDTO; +import subway.application.section.dto.ShortCostRequest; +import subway.application.section.dto.ShortCostResponse; +import subway.domain.line.Line; +import subway.domain.line.LineService; +import subway.domain.section.Section; +import subway.domain.section.SectionRepository; +import subway.domain.station.Station; +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class SectionService { + private final ShortTimeService shortTimeService = new ShortTimeService(); + + public void addNode(StationDTO stationDTO) { + Station station = this.stationService.findOneByName(stationDTO.getName()); + this.shortDistanceService.addNode(station); ++ this.shortTimeService.addNode(station); + } + + public void addSection(SectionDTO sectionDTO) { + Line line = this.lineService.findOneByName(sectionDTO.getLineDTO().getName()); + Station source = this.stationService.findOneByName(sectionDTO.getSourceDTO().getName()); + Station sink = this.stationService.findOneByName(sectionDTO.getSinkDTO().getName()); + Section section = new Section(line, source, sink, sectionDTO.getDistance(), sectionDTO.getTime()); + if (SectionRepository.exists(section)) { + throw new IllegalArgumentException(ALREADY_EXISTS_SECTION_MESSAGE); + } + SectionRepository.addSection(section); + this.shortDistanceService.addEdge(section); ++ this.shortTimeService.addEdge(section); + line.addSection(section); + source.addSection(section); + } + + public ShortCostResponse computeShortTime(ShortCostRequest shortCostRequest) { + Station source = this.stationService.findByName(shortCostRequest.getSourceDTO().getName()) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SOURCE_STATION_MESSAGE)); + Station sink = this.stationService.findByName(shortCostRequest.getSinkDTO().getName()) + .orElseThrow(() -> new IllegalArgumentException(NOT_EXISTS_SINK_STATION_MESSAGE)); + GraphPath graphPath = this.shortDistanceService.compute(source, sink); + if (graphPath == null) { + throw new IllegalArgumentException(NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE); + } + return new ShortCostResponse(graphPath.getVertexList()); + } +} +``` + +์ตœ์†Œ ์‹œ๊ฐ„ ๊ทธ๋ž˜ํ”„๋„ ๊ฐ™์ด ๋…ธ๋“œ, ๊ฐ„์„  ์ถ”๊ฐ€์— ํฌํ•จ. + +์ตœ์†Œ ์‹œ๊ฐ„ ๊ณ„์‚ฐ ๊ตฌํ˜„. + +```java +// SectionServiceTest.java + +package subway.application.section.service; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import subway.application.section.dto.SectionDTO; +import subway.application.section.dto.ShortCostRequest; +import subway.application.section.dto.ShortCostResponse; +import subway.domain.line.Line; +import subway.domain.line.LineDTO; +import subway.domain.line.LineService; +import subway.domain.station.Station; +import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class SectionServiceTest { + private final ShortTimeService shortTimeService = new ShortTimeService(); + + @AfterEach + public void init() { + this.lineService.deleteAll(); + this.stationService.deleteAll(); + this.sectionService.deleteAll(); + this.shortDistanceService.deleteAll(); ++ this.shortTimeService.deleteAll(); + } +} +``` + +์ตœ์†Œ ์‹œ๊ฐ„ ๊ธฐ๋Šฅ ๋„์ž…์œผ๋กœ ์ธํ•œ ํ…Œ์ŠคํŠธ ์ดˆ๊ธฐํ™” ์†Œ์Šค ๋ณ€๊ฒฝ. + +```java +// StationController.java + +package subway.presentation; + +import subway.application.section.service.SectionService;import subway.domain.station.StationDTO; +import subway.domain.station.StationService; + +public class StationController { + private final SectionService sectionService = new SectionService(); + + public void addStation(String name) { + StationDTO stationDTO = new StationDTO(name); + stationService.addStation(stationDTO); ++ this.sectionService.addNode(stationDTO); + } +} +``` + +์—ญ๊ณผ ๊ฐ™์ด ๋…ธ๋“œ๋„ ๊ฐ™์ด ์ถ”๊ฐ€๋˜๋„๋ก ๋ณ€๊ฒฝ. \ No newline at end of file From 8c81180b51997b083064257bd50791fb23520a98 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 17:39:49 +0900 Subject: [PATCH 25/45] =?UTF-8?q?refactor:=206.=20=EA=B7=B8=EB=9E=98?= =?UTF-8?q?=ED=94=84=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=20-=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20-=20[ShortCostService.java]=20graph=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=20=EC=A0=9C=EC=96=B4=EC=9E=90=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD(protected=20=E2=86=92=20private)=20-=20[ShortDistance?= =?UTF-8?q?Service.java]=20=EC=A0=95=EC=A0=81=20graph=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 12 ++++++++---- .../section/service/ShortCostService.java | 2 +- .../section/service/ShortDistanceService.java | 8 ++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index f99303e6d..7dbf2b21f 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -2143,7 +2143,7 @@ import subway.domain.section.Section; import subway.domain.station.Station; abstract class ShortCostService { - protected final AbstractBaseGraph graph; + private final AbstractBaseGraph graph; public ShortCostService(AbstractBaseGraph graph) { this.graph = graph; @@ -2223,15 +2223,19 @@ abstract class ShortCostService { package subway.application.section.service; +import org.jgrapht.graph.AbstractBaseGraph; import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.section.Section; +import subway.domain.station.Station; class ShortDistanceService extends ShortCostService { + private static final AbstractBaseGraph graph = new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class); + public ShortDistanceService() { - super(new DirectedWeightedMultigraph<>( - DefaultWeightedEdge.class)); + super(graph); } @Override @@ -2241,7 +2245,7 @@ class ShortDistanceService extends ShortCostService { } ``` -์ดํ›„์— ๊ตฌํ˜„๋  ์ตœ์†Œ ์‹œ๊ฐ„ ๊ฒฝ๋กœ์™€ ๊ทธ๋ž˜ํ”„ ๊ด€๋ จ ๊ธฐ๋Šฅ์€ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์ถ”์ƒ ๊ณตํ†ต ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฝ”๋“œ ์ค‘๋ณต ์ค„์ž„. +์ดํ›„์— ๊ตฌํ˜„๋  ์ตœ์†Œ ์‹œ๊ฐ„ ๊ฒฝ๋กœ์™€ ๊ทธ๋ž˜ํ”„ ๊ด€๋ จ ๊ธฐ๋Šฅ์€ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์ถ”์ƒ ๊ณตํ†ต ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฝ”๋“œ ์ค‘๋ณต ๋ฐฉ์ง€. ## 7. ์ตœ์†Œ ์‹œ๊ฐ„ ๊ฒฝ๋กœ ๊ตฌํ•˜๊ธฐ diff --git a/src/main/java/subway/application/section/service/ShortCostService.java b/src/main/java/subway/application/section/service/ShortCostService.java index b898aaf0b..a9ecf7fb7 100644 --- a/src/main/java/subway/application/section/service/ShortCostService.java +++ b/src/main/java/subway/application/section/service/ShortCostService.java @@ -13,7 +13,7 @@ import subway.domain.station.Station; abstract class ShortCostService { - protected final AbstractBaseGraph graph; + private final AbstractBaseGraph graph; public ShortCostService(AbstractBaseGraph graph) { this.graph = graph; diff --git a/src/main/java/subway/application/section/service/ShortDistanceService.java b/src/main/java/subway/application/section/service/ShortDistanceService.java index e42f2302c..c0be24d50 100644 --- a/src/main/java/subway/application/section/service/ShortDistanceService.java +++ b/src/main/java/subway/application/section/service/ShortDistanceService.java @@ -1,14 +1,18 @@ package subway.application.section.service; +import org.jgrapht.graph.AbstractBaseGraph; import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.section.Section; +import subway.domain.station.Station; class ShortDistanceService extends ShortCostService { + private static final AbstractBaseGraph graph = new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class); + public ShortDistanceService() { - super(new DirectedWeightedMultigraph<>( - DefaultWeightedEdge.class)); + super(graph); } @Override From f89f6b617386482859bcb0ce4386508760deb49e Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 17:40:47 +0900 Subject: [PATCH 26/45] =?UTF-8?q?refactor:=207.=20=EC=B5=9C=EC=86=8C=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EA=B2=BD=EB=A1=9C=20=EA=B5=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20-=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20-=20[ShortTimeService.java]=20=EC=A0=95?= =?UTF-8?q?=EC=A0=81=20graph=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 8 ++++++-- .../application/section/service/ShortTimeService.java | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 7dbf2b21f..c1bab555c 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -2254,15 +2254,19 @@ class ShortDistanceService extends ShortCostService { package subway.application.section.service; +import org.jgrapht.graph.AbstractBaseGraph; import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.section.Section; +import subway.domain.station.Station; class ShortTimeService extends ShortCostService { + private static final AbstractBaseGraph graph = new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class); + public ShortTimeService() { - super(new DirectedWeightedMultigraph<>( - DefaultWeightedEdge.class)); + super(graph); } @Override diff --git a/src/main/java/subway/application/section/service/ShortTimeService.java b/src/main/java/subway/application/section/service/ShortTimeService.java index 18ae15fcd..d0b775a4a 100644 --- a/src/main/java/subway/application/section/service/ShortTimeService.java +++ b/src/main/java/subway/application/section/service/ShortTimeService.java @@ -1,14 +1,18 @@ package subway.application.section.service; +import org.jgrapht.graph.AbstractBaseGraph; import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.DirectedWeightedMultigraph; import subway.domain.section.Section; +import subway.domain.station.Station; class ShortTimeService extends ShortCostService { + private static final AbstractBaseGraph graph = new DirectedWeightedMultigraph<>( + DefaultWeightedEdge.class); + public ShortTimeService() { - super(new DirectedWeightedMultigraph<>( - DefaultWeightedEdge.class)); + super(graph); } @Override From 7515e91126512b99c557f3da770d2d8c6bb76a1f Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Tue, 11 Feb 2025 18:04:41 +0900 Subject: [PATCH 27/45] =?UTF-8?q?refactor:=20=EC=A7=80=EC=A0=90=20?= =?UTF-8?q?=EC=9A=A9=EC=96=B4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 56 +++++++++---------- .../application/section/dto/SectionDTO.java | 4 +- .../section/dto/ShortCostRequest.java | 4 +- .../section/service/SectionService.java | 6 +- .../section/service/ShortCostService.java | 4 +- .../java/subway/domain/station/Station.java | 4 +- .../section/dto/SectionDTOTest.java | 4 +- .../section/dto/ShortCostRequestTest.java | 4 +- .../section/service/SectionServiceTest.java | 6 +- .../service/ShortDistanceServiceTest.java | 8 +-- .../subway/domain/station/StationTest.java | 6 +- 11 files changed, 53 insertions(+), 53 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index c1bab555c..ace551613 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -786,7 +786,7 @@ public class StationTest { Station other = new Station("other"); Station sink = new Station("sink"); Section section = new Section(line, other, sink, 0, 0); - String message = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + String message = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; assertThatThrownBy(() -> source.addSection(section)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -805,7 +805,7 @@ import java.util.List; import subway.domain.section.Section; public class Station { - private static final String SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; private final List
sectionList = new ArrayList<>(); @@ -856,7 +856,7 @@ public class SectionDTOTest { public void constructor__SectionAddingSourceStationInfoEssentialException() { LineDTO lineDTO = new LineDTO("line"); StationDTO sinkDTO = new StationDTO("sink"); - String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new SectionDTO(lineDTO, null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -865,7 +865,7 @@ public class SectionDTOTest { public void constructor__SectionAddingSinkStationInfoEssentialException() { LineDTO lineDTO = new LineDTO("line"); StationDTO sourceDTO = new StationDTO("source"); - String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new SectionDTO(lineDTO, sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -882,8 +882,8 @@ import subway.domain.station.StationDTO; public class SectionDTO { private static final String SECTION_ADDING_LINE_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ๋…ธ์„  ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; - private static final String SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; - private static final String SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; private final LineDTO lineDTO; private final StationDTO sourceDTO; @@ -1050,7 +1050,7 @@ public class SectionRepository { ๊ตฌ๊ฐ„ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๊ตฌํ˜„. -๊ตฌ๊ฐ„ ์ค‘๋ณต ์ƒ์„ฑ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ๋…ธ์„ , ์‹œ์ž‘ ์ง€์  ์—ญ, ์ข…๋ฃŒ ์ง€์  ์—ญ ๊ธฐ์ค€์œผ๋กœ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„. +๊ตฌ๊ฐ„ ์ค‘๋ณต ์ƒ์„ฑ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ๋…ธ์„ , ์‹œ์ž‘์—ญ, ์ข…๋ฃŒ์—ญ ๊ธฐ์ค€์œผ๋กœ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„. ```java // SectionServiceTest.java @@ -1499,7 +1499,7 @@ class shortDistanceServiceTest { @Test public void addEdge_NotExistsSourceNodeException() { Section section = new Section(this.line, this.source, this.sink, 0, 0); - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; this.shortDistanceService.addNode(this.sink); assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); @@ -1508,7 +1508,7 @@ class shortDistanceServiceTest { @Test public void addEdge_NotExistsSinkNodeException() { Section section = new Section(this.line, this.source, this.sink, 0, 0); - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; this.shortDistanceService.addNode(this.source); assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); @@ -1548,8 +1548,8 @@ import subway.domain.section.Section; import subway.domain.station.Station; class shortDistanceService { - private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; private static final String ALREADY_EXISTS_EDGE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; protected void addEdge(Section section) { @@ -1635,7 +1635,7 @@ import subway.domain.station.Station; class shortDistanceServiceTest { @Test public void compute__NotExistsSourceNodeException() { - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; this.shortDistanceService.addNode(this.sink); assertThatThrownBy(() -> this.shortDistanceService.compute(this.source, this.sink)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); @@ -1643,7 +1643,7 @@ class shortDistanceServiceTest { @Test public void compute__NotExistsSinkNodeException() { - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; this.shortDistanceService.addNode(this.source); assertThatThrownBy(() -> this.shortDistanceService.compute(this.source, this.sink)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); @@ -1695,7 +1695,7 @@ public class ShortCostRequestTest { @Test public void constructor__SourceStationInfoEssentialException() { StationDTO sinkDTO = new StationDTO("sink"); - String message = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + String message = "์‹œ์ž‘์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new ShortCostRequest(null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -1703,7 +1703,7 @@ public class ShortCostRequestTest { @Test public void constructor__SinkStationInfoEssentialException() { StationDTO sourceDTO = new StationDTO("source"); - String message = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + String message = "์ข…๋ฃŒ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new ShortCostRequest(sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -1749,8 +1749,8 @@ package subway.application.section.dto; import subway.domain.station.StationDTO; public class ShortCostRequest { - private static final String SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; - private static final String SINK_STATION_INFO_ESSENTIAL_MESSAGE = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "์‹œ์ž‘์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SINK_STATION_INFO_ESSENTIAL_MESSAGE = "์ข…๋ฃŒ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; private static final String SAME_SOURCE_AND_SINK_STATION_MESSAGE = "์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๋™์ผํ•ฉ๋‹ˆ๋‹ค."; private final StationDTO sourceDTO; @@ -1849,7 +1849,7 @@ public class StationTest { public void findDistanceTo__NotExistsPathToSinkStationException() { Station source = new Station("source"); Station sink = new Station("sink"); - String message = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + String message = "์ข…๋ฃŒ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; assertThatThrownBy(() -> source.findDistanceTo(sink)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -1869,7 +1869,7 @@ public class StationTest { public void findTimeTo__NotExistsPathToSinkStationException() { Station source = new Station("source"); Station sink = new Station("sink"); - String message = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + String message = "์ข…๋ฃŒ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; assertThatThrownBy(() -> source.findTimeTo(sink)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -1888,7 +1888,7 @@ import java.util.List; import subway.domain.section.Section; public class Station { - private static final String NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE = "์ข…๋ฃŒ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; public int findDistanceTo(Station sink) { return this.sectionList.stream() @@ -2007,7 +2007,7 @@ public class SectionServiceTest { public void computeShortDistance__NotExistsSourceStationException() { StationDTO otherDTO = new StationDTO("other"); ShortCostRequest shortCostRequest = new ShortCostRequest(otherDTO, this.sinkDTO); - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘์—ญ์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); } @@ -2016,7 +2016,7 @@ public class SectionServiceTest { public void computeShortDistance__NotExistsSinkStationException() { StationDTO otherDTO = new StationDTO("other"); ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, otherDTO); - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ์—ญ์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); } @@ -2024,7 +2024,7 @@ public class SectionServiceTest { @Test public void computeShortDistance__NotConnectedSourceAndSinkStationException() { ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, this.sinkDTO); - String message = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ ์ง€์  ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + String message = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; this.sectionService.addNode(this.sourceDTO); this.sectionService.addNode(this.sinkDTO); assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( @@ -2078,9 +2078,9 @@ import subway.domain.station.StationDTO; import subway.domain.station.StationService; public class SectionService { - private static final String NOT_EXISTS_SOURCE_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SINK_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ ์ง€์  ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SOURCE_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘์—ญ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ์—ญ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; public ShortCostResponse computeShortDistance(ShortCostRequest shortCostRequest) { Station source = this.stationService.findByName(shortCostRequest.getSourceDTO().getName()) @@ -2150,8 +2150,8 @@ abstract class ShortCostService { } private static final String ALREADY_EXISTS_NODE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; private static final String ALREADY_EXISTS_EDGE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; protected Set findAllNode() { diff --git a/src/main/java/subway/application/section/dto/SectionDTO.java b/src/main/java/subway/application/section/dto/SectionDTO.java index 056cbac4f..abeee3d8d 100644 --- a/src/main/java/subway/application/section/dto/SectionDTO.java +++ b/src/main/java/subway/application/section/dto/SectionDTO.java @@ -5,8 +5,8 @@ public class SectionDTO { private static final String SECTION_ADDING_LINE_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ๋…ธ์„  ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; - private static final String SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; - private static final String SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_SINK_STATION_INFO_ESSENTIAL_MESSAGE = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; private final LineDTO lineDTO; private final StationDTO sourceDTO; diff --git a/src/main/java/subway/application/section/dto/ShortCostRequest.java b/src/main/java/subway/application/section/dto/ShortCostRequest.java index 1f5e4dbd6..716b0c39c 100644 --- a/src/main/java/subway/application/section/dto/ShortCostRequest.java +++ b/src/main/java/subway/application/section/dto/ShortCostRequest.java @@ -3,8 +3,8 @@ import subway.domain.station.StationDTO; public class ShortCostRequest { - private static final String SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; - private static final String SINK_STATION_INFO_ESSENTIAL_MESSAGE = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SOURCE_STATION_INFO_ESSENTIAL_MESSAGE = "์‹œ์ž‘์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + private static final String SINK_STATION_INFO_ESSENTIAL_MESSAGE = "์ข…๋ฃŒ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; private static final String SAME_SOURCE_AND_SINK_STATION_MESSAGE = "์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ๋™์ผํ•ฉ๋‹ˆ๋‹ค."; private final StationDTO sourceDTO; diff --git a/src/main/java/subway/application/section/service/SectionService.java b/src/main/java/subway/application/section/service/SectionService.java index f38fa73ba..82fbae905 100644 --- a/src/main/java/subway/application/section/service/SectionService.java +++ b/src/main/java/subway/application/section/service/SectionService.java @@ -18,9 +18,9 @@ public class SectionService { private static final String ALREADY_EXISTS_SECTION_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ตฌ๊ฐ„์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SOURCE_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SINK_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ ์ง€์  ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SOURCE_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘์—ญ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_STATION_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ์—ญ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_CONNECTED_SOURCE_AND_SINK_STATION_MESSAGE = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; private final LineService lineService = new LineService(); private final StationService stationService = new StationService(); diff --git a/src/main/java/subway/application/section/service/ShortCostService.java b/src/main/java/subway/application/section/service/ShortCostService.java index a9ecf7fb7..54c501abf 100644 --- a/src/main/java/subway/application/section/service/ShortCostService.java +++ b/src/main/java/subway/application/section/service/ShortCostService.java @@ -20,8 +20,8 @@ public ShortCostService(AbstractBaseGraph graph) { } private static final String ALREADY_EXISTS_NODE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SOURCE_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_SINK_NODE_MESSAGE = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; private static final String ALREADY_EXISTS_EDGE_MESSAGE = "์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฐ„์„ ์ž…๋‹ˆ๋‹ค."; protected Set findAllNode() { diff --git a/src/main/java/subway/domain/station/Station.java b/src/main/java/subway/domain/station/Station.java index c99e231bc..908388b6e 100644 --- a/src/main/java/subway/domain/station/Station.java +++ b/src/main/java/subway/domain/station/Station.java @@ -7,8 +7,8 @@ import subway.domain.section.Section; public class Station { - private static final String SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; - private static final String NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + private static final String SECTION_ADDING_OTHER_SOURCE_STATION_RECEIVE_MESSAGE = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + private static final String NOT_EXISTS_PATH_TO_SINK_STATION_MESSAGE = "์ข…๋ฃŒ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; private final String name; private final List
sectionList = new ArrayList<>(); diff --git a/src/test/java/subway/application/section/dto/SectionDTOTest.java b/src/test/java/subway/application/section/dto/SectionDTOTest.java index d561ad7d0..9c2814e76 100644 --- a/src/test/java/subway/application/section/dto/SectionDTOTest.java +++ b/src/test/java/subway/application/section/dto/SectionDTOTest.java @@ -21,7 +21,7 @@ public void constructor__SectionAddingLineInfoEssentialException() { public void constructor__SectionAddingSourceStationInfoEssentialException() { LineDTO lineDTO = new LineDTO("line"); StationDTO sinkDTO = new StationDTO("sink"); - String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์‹œ์ž‘์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new SectionDTO(lineDTO, null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -30,7 +30,7 @@ public void constructor__SectionAddingSourceStationInfoEssentialException() { public void constructor__SectionAddingSinkStationInfoEssentialException() { LineDTO lineDTO = new LineDTO("line"); StationDTO sourceDTO = new StationDTO("source"); - String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + String message = "๊ตฌ๊ฐ„ ์ƒ์„ฑ์‹œ ์ข…๋ฃŒ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new SectionDTO(lineDTO, sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } diff --git a/src/test/java/subway/application/section/dto/ShortCostRequestTest.java b/src/test/java/subway/application/section/dto/ShortCostRequestTest.java index 138bf1dac..d647e1cf0 100644 --- a/src/test/java/subway/application/section/dto/ShortCostRequestTest.java +++ b/src/test/java/subway/application/section/dto/ShortCostRequestTest.java @@ -10,7 +10,7 @@ public class ShortCostRequestTest { @Test public void constructor__SourceStationInfoEssentialException() { StationDTO sinkDTO = new StationDTO("sink"); - String message = "์‹œ์ž‘ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + String message = "์‹œ์ž‘์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new ShortCostRequest(null, sinkDTO)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -18,7 +18,7 @@ public void constructor__SourceStationInfoEssentialException() { @Test public void constructor__SinkStationInfoEssentialException() { StationDTO sourceDTO = new StationDTO("source"); - String message = "์ข…๋ฃŒ ์ง€์  ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; + String message = "์ข…๋ฃŒ์—ญ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> new ShortCostRequest(sourceDTO, null)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } diff --git a/src/test/java/subway/application/section/service/SectionServiceTest.java b/src/test/java/subway/application/section/service/SectionServiceTest.java index 081254441..2ee1f96fd 100644 --- a/src/test/java/subway/application/section/service/SectionServiceTest.java +++ b/src/test/java/subway/application/section/service/SectionServiceTest.java @@ -82,7 +82,7 @@ public void computeShortDistance() { public void computeShortDistance__NotExistsSourceStationException() { StationDTO otherDTO = new StationDTO("other"); ShortCostRequest shortCostRequest = new ShortCostRequest(otherDTO, this.sinkDTO); - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘์—ญ์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); } @@ -91,7 +91,7 @@ public void computeShortDistance__NotExistsSourceStationException() { public void computeShortDistance__NotExistsSinkStationException() { StationDTO otherDTO = new StationDTO("other"); ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, otherDTO); - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ์—ญ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ์—ญ์ž…๋‹ˆ๋‹ค."; assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); } @@ -99,7 +99,7 @@ public void computeShortDistance__NotExistsSinkStationException() { @Test public void computeShortDistance__NotConnectedSourceAndSinkStationException() { ShortCostRequest shortCostRequest = new ShortCostRequest(this.sourceDTO, this.sinkDTO); - String message = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ ์ง€์  ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + String message = "์‹œ์ž‘ ์ง€์ ๊ณผ ์ข…๋ฃŒ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; this.sectionService.addNode(this.sourceDTO); this.sectionService.addNode(this.sinkDTO); assertThatThrownBy(() -> this.sectionService.computeShortDistance(shortCostRequest)).isInstanceOf( diff --git a/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java b/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java index 3570da5e0..e80441ad4 100644 --- a/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java +++ b/src/test/java/subway/application/section/service/ShortDistanceServiceTest.java @@ -46,7 +46,7 @@ public void addEdge() { @Test public void addEdge_NotExistsSourceNodeException() { Section section = new Section(this.line, this.source, this.sink, 0, 0); - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; this.shortDistanceService.addNode(this.sink); assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); @@ -55,7 +55,7 @@ public void addEdge_NotExistsSourceNodeException() { @Test public void addEdge_NotExistsSinkNodeException() { Section section = new Section(this.line, this.source, this.sink, 0, 0); - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; this.shortDistanceService.addNode(this.source); assertThatThrownBy(() -> this.shortDistanceService.addEdge(section)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); @@ -86,7 +86,7 @@ public void compute() { @Test public void compute__NotExistsSourceNodeException() { - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์‹œ์ž‘๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; this.shortDistanceService.addNode(this.sink); assertThatThrownBy(() -> this.shortDistanceService.compute(this.source, this.sink)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); @@ -94,7 +94,7 @@ public void compute__NotExistsSourceNodeException() { @Test public void compute__NotExistsSinkNodeException() { - String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ ์ง€์  ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; + String message = "์กด์žฌํ•˜์ง€ ์•Š์€ ์ข…๋ฃŒ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."; this.shortDistanceService.addNode(this.source); assertThatThrownBy(() -> this.shortDistanceService.compute(this.source, this.sink)).isInstanceOf( IllegalArgumentException.class).hasMessage(message); diff --git a/src/test/java/subway/domain/station/StationTest.java b/src/test/java/subway/domain/station/StationTest.java index 476f7efc3..a4df622b7 100644 --- a/src/test/java/subway/domain/station/StationTest.java +++ b/src/test/java/subway/domain/station/StationTest.java @@ -26,7 +26,7 @@ public void addSection__SectionAddingOtherSourceStationReceiveException() { Station other = new Station("other"); Station sink = new Station("sink"); Section section = new Section(line, other, sink, 0, 0); - String message = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘ ์ง€์  ์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; + String message = "๊ตฌ๊ฐ„ ์ถ”๊ฐ€์‹œ ๋‹ค๋ฅธ ์‹œ์ž‘์—ญ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค."; assertThatThrownBy(() -> source.addSection(section)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -46,7 +46,7 @@ public void findDistanceTo() { public void findDistanceTo__NotExistsPathToSinkStationException() { Station source = new Station("source"); Station sink = new Station("sink"); - String message = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + String message = "์ข…๋ฃŒ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; assertThatThrownBy(() -> source.findDistanceTo(sink)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } @@ -66,7 +66,7 @@ public void findTimeTo() { public void findTimeTo__NotExistsPathToSinkStationException() { Station source = new Station("source"); Station sink = new Station("sink"); - String message = "์ข…๋ฃŒ ์ง€์  ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + String message = "์ข…๋ฃŒ์—ญ๊นŒ์ง€ ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; assertThatThrownBy(() -> source.findTimeTo(sink)).isInstanceOf(IllegalArgumentException.class) .hasMessage(message); } From a0983eac6f34c5009355839855c53fca3b0e13bf Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Wed, 12 Feb 2025 13:14:19 +0900 Subject: [PATCH 28/45] =?UTF-8?q?feat:=207.=20=EC=B5=9C=EC=86=8C=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EA=B2=BD=EB=A1=9C=20=EA=B5=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20-=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20-=20[SectionController.java]=20=EC=B5=9C?= =?UTF-8?q?=EC=86=8C=20=EC=8B=9C=EA=B0=84=20=EA=B3=84=EC=82=B0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 25 +++++++++++++++++++ .../presentation/SectionController.java | 7 ++++++ 2 files changed, 32 insertions(+) diff --git a/.github/solving_process.md b/.github/solving_process.md index ace551613..3ff131edd 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -2378,6 +2378,31 @@ public class SectionServiceTest { ์ตœ์†Œ ์‹œ๊ฐ„ ๊ธฐ๋Šฅ ๋„์ž…์œผ๋กœ ์ธํ•œ ํ…Œ์ŠคํŠธ ์ดˆ๊ธฐํ™” ์†Œ์Šค ๋ณ€๊ฒฝ. +```java +// SectionController.java + +package subway.presentation; + +import subway.application.section.dto.SectionDTO; +import subway.application.section.dto.ShortCostRequest; +import subway.application.section.dto.ShortCostResponse; +import subway.application.section.service.SectionService; +import subway.domain.line.LineDTO; +import subway.domain.station.StationDTO; +import subway.util.Validation; + +public class SectionController { + public ShortCostResponse computeShortTime(String sourceName, String sinkName) { + StationDTO sourceDTO = new StationDTO(sourceName); + StationDTO sinkDTO = new StationDTO(sinkName); + ShortCostRequest shortCostRequest = new ShortCostRequest(sourceDTO, sinkDTO); + return this.sectionService.computeShortTime(shortCostRequest); + } +} +``` + +์ œ์–ด ๊ณ„์ธต์— ์ตœ์†Œ ์‹œ๊ฐ„ ๊ณ„์‚ฐ ๊ธฐ๋Šฅ ๋งคํ•‘. + ```java // StationController.java diff --git a/src/main/java/subway/presentation/SectionController.java b/src/main/java/subway/presentation/SectionController.java index 565194277..c7338456b 100644 --- a/src/main/java/subway/presentation/SectionController.java +++ b/src/main/java/subway/presentation/SectionController.java @@ -52,4 +52,11 @@ public ShortCostResponse computeShortDistance(String sourceName, String sinkName ShortCostRequest shortCostRequest = new ShortCostRequest(sourceDTO, sinkDTO); return this.sectionService.computeShortDistance(shortCostRequest); } + + public ShortCostResponse computeShortTime(String sourceName, String sinkName) { + StationDTO sourceDTO = new StationDTO(sourceName); + StationDTO sinkDTO = new StationDTO(sinkName); + ShortCostRequest shortCostRequest = new ShortCostRequest(sourceDTO, sinkDTO); + return this.sectionService.computeShortTime(shortCostRequest); + } } From ec1fe4aa73f44bf56155d1bc35404a7753bfddb9 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Wed, 12 Feb 2025 13:20:40 +0900 Subject: [PATCH 29/45] =?UTF-8?q?refactor:=205.=20=EC=B5=9C=EB=8B=A8=20?= =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EA=B2=BD=EB=A1=9C=20=EA=B5=AC=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20-=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20-=20[SectionController.java]=20=EC=B5=9C?= =?UTF-8?q?=EB=8B=A8(=EC=B5=9C=EC=86=8C)=20=EA=B1=B0=EB=A6=AC=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20DTO=20=EC=83=9D=EC=84=B1=20=EC=9D=B8=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20=EB=A1=9C=EC=A7=81=EC=9D=84=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=A1=9C=20=EB=91=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 12 +++++++----- .../java/subway/presentation/SectionController.java | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 3ff131edd..891e87794 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -2113,10 +2113,14 @@ import subway.util.Validation; public class SectionController { public ShortCostResponse computeShortDistance(String sourceName, String sinkName) { + ShortCostRequest shortCostRequest = this.createShortCostRequest(sourceName, sinkName); + return this.sectionService.computeShortDistance(shortCostRequest); + } + + private ShortCostRequest createShortCostRequest(String sourceName, String sinkName) { StationDTO sourceDTO = new StationDTO(sourceName); StationDTO sinkDTO = new StationDTO(sinkName); - ShortCostRequest shortCostRequest = new ShortCostRequest(sourceDTO, sinkDTO); - return this.sectionService.computeShortDistance(shortCostRequest); + return new ShortCostRequest(sourceDTO, sinkDTO); } } ``` @@ -2393,9 +2397,7 @@ import subway.util.Validation; public class SectionController { public ShortCostResponse computeShortTime(String sourceName, String sinkName) { - StationDTO sourceDTO = new StationDTO(sourceName); - StationDTO sinkDTO = new StationDTO(sinkName); - ShortCostRequest shortCostRequest = new ShortCostRequest(sourceDTO, sinkDTO); + ShortCostRequest shortCostRequest = this.createShortCostRequest(sourceName, sinkName); return this.sectionService.computeShortTime(shortCostRequest); } } diff --git a/src/main/java/subway/presentation/SectionController.java b/src/main/java/subway/presentation/SectionController.java index c7338456b..9ddf5405d 100644 --- a/src/main/java/subway/presentation/SectionController.java +++ b/src/main/java/subway/presentation/SectionController.java @@ -47,16 +47,18 @@ private void validateTime(String time) { } public ShortCostResponse computeShortDistance(String sourceName, String sinkName) { - StationDTO sourceDTO = new StationDTO(sourceName); - StationDTO sinkDTO = new StationDTO(sinkName); - ShortCostRequest shortCostRequest = new ShortCostRequest(sourceDTO, sinkDTO); + ShortCostRequest shortCostRequest = this.createShortCostRequest(sourceName, sinkName); return this.sectionService.computeShortDistance(shortCostRequest); } public ShortCostResponse computeShortTime(String sourceName, String sinkName) { + ShortCostRequest shortCostRequest = this.createShortCostRequest(sourceName, sinkName); + return this.sectionService.computeShortTime(shortCostRequest); + } + + private ShortCostRequest createShortCostRequest(String sourceName, String sinkName) { StationDTO sourceDTO = new StationDTO(sourceName); StationDTO sinkDTO = new StationDTO(sinkName); - ShortCostRequest shortCostRequest = new ShortCostRequest(sourceDTO, sinkDTO); - return this.sectionService.computeShortTime(shortCostRequest); + return new ShortCostRequest(sourceDTO, sinkDTO); } } From 67a7ac0158a6a27d6460e26cd97b7ac1f8e7f543 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 10:38:06 +0900 Subject: [PATCH 30/45] feat: 8. Screen Layer Skeleton --- src/main/java/subway/screen/ui/Console.java | 38 +++++ src/main/java/subway/screen/view/Menu.java | 30 ++++ .../subway/screen/view/MenuEventManager.java | 51 +++++++ .../java/subway/screen/view/MenuView.java | 60 ++++++++ src/main/java/subway/screen/view/View.java | 6 + .../screen/view/MenuEventManagerTest.java | 53 +++++++ .../java/subway/screen/view/MenuTest.java | 61 ++++++++ .../java/subway/screen/view/MenuViewTest.java | 142 ++++++++++++++++++ 8 files changed, 441 insertions(+) create mode 100644 src/main/java/subway/screen/ui/Console.java create mode 100644 src/main/java/subway/screen/view/Menu.java create mode 100644 src/main/java/subway/screen/view/MenuEventManager.java create mode 100644 src/main/java/subway/screen/view/MenuView.java create mode 100644 src/main/java/subway/screen/view/View.java create mode 100644 src/test/java/subway/screen/view/MenuEventManagerTest.java create mode 100644 src/test/java/subway/screen/view/MenuTest.java create mode 100644 src/test/java/subway/screen/view/MenuViewTest.java diff --git a/src/main/java/subway/screen/ui/Console.java b/src/main/java/subway/screen/ui/Console.java new file mode 100644 index 000000000..5c72fd351 --- /dev/null +++ b/src/main/java/subway/screen/ui/Console.java @@ -0,0 +1,38 @@ +package subway.screen.ui; + +import java.io.PrintStream; +import java.util.Scanner; + +public final class Console { + private static final Scanner scanner = new Scanner(System.in); + private static final PrintStream printer = System.out; + + private static final String HEADER_OUTPUT_FORMAT = "## %s"; + private static final String INFO_OUTPUT_FORMAT = "[INFO] %s"; + private static final String ERROR_OUTPUT_FORMAT = "[ERROR] %s"; + + public static String readline() { + return scanner.nextLine(); + } + + public static void println() { + printer.println(); + } + + public static void println(String message) { + printer.println(message); + } + + public static void printHeader(String message) { + println(String.format(HEADER_OUTPUT_FORMAT, message)); + } + + public static void printInfo(String message) { + println(String.format(INFO_OUTPUT_FORMAT, message)); + } + + public static void printError(String message) { + println(String.format(ERROR_OUTPUT_FORMAT, message)); + } + +} diff --git a/src/main/java/subway/screen/view/Menu.java b/src/main/java/subway/screen/view/Menu.java new file mode 100644 index 000000000..f6c6a17fc --- /dev/null +++ b/src/main/java/subway/screen/view/Menu.java @@ -0,0 +1,30 @@ +package subway.screen.view; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public interface Menu { + String getCommand(); + + String getName(); + + static List findAll(Class menuClass) { + Menu[] enumValues = menuClass.getEnumConstants(); + if(enumValues == null) { + throw new IllegalArgumentException("Enum ํ˜•์‹์˜ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."); + } + return Arrays.stream(enumValues).collect(Collectors.toList()); + } + + static Optional findByCommand(Class menuClass, String command) { + List menuList = findAll(menuClass); + for (Menu menu : menuList) { + if (menu.getCommand().equals(command)) { + return Optional.of(menu); + } + } + return Optional.empty(); + } +} diff --git a/src/main/java/subway/screen/view/MenuEventManager.java b/src/main/java/subway/screen/view/MenuEventManager.java new file mode 100644 index 000000000..47134cb4b --- /dev/null +++ b/src/main/java/subway/screen/view/MenuEventManager.java @@ -0,0 +1,51 @@ +package subway.screen.view; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public final class MenuEventManager { + private static final String NOT_RECEIVED_MENU_MESSAGE = "๋ฉ”๋‰ด๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + private static final String NOT_RECEIVED_HANDLER_MESSAGE = "์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + + private final Map handlerMap = new HashMap<>(); + + private MenuEventManager() { + } + + public static MenuEventManager builder() { + return new MenuEventManager(); + } + + public MenuEventManager addEventListener(Menu menu) { + return this.addEventListener(menu, () -> { + }); + } + + public MenuEventManager addEventListener(Menu menu, Runnable handler) { + this.validate(menu, handler); + this.handlerMap.put(menu, handler); + return this; + } + + private void validate(Menu menu, Runnable runnable) { + if (menu == null) { + throw new IllegalArgumentException(NOT_RECEIVED_MENU_MESSAGE); + } + if (runnable == null) { + throw new IllegalArgumentException(NOT_RECEIVED_HANDLER_MESSAGE); + } + } + + public void removeEventListener(Menu menu) { + this.handlerMap.remove(menu); + } + + public void removeAllEventListener() { + this.handlerMap.clear(); + } + + Optional select(Menu menu) { + return Optional.ofNullable(this.handlerMap.get(menu)); + } +} diff --git a/src/main/java/subway/screen/view/MenuView.java b/src/main/java/subway/screen/view/MenuView.java new file mode 100644 index 000000000..4e5559d55 --- /dev/null +++ b/src/main/java/subway/screen/view/MenuView.java @@ -0,0 +1,60 @@ +package subway.screen.view; + +import java.util.List; + +import subway.screen.ui.Console; + +public abstract class MenuView implements View { + private static final String NOT_RECEIVED_EVENT_MANAGER_MESSAGE = "์ด๋ฒคํŠธ ๊ด€๋ฆฌ์ž๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + private static final String MENU_OUTPUT_FORMAT = "%s. %s"; + private static final String CAN_NOT_SELECTED_FUNCTION_MESSAGE = "์„ ํƒํ•  ์ˆ˜ ์—†๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค."; + private static final String CAN_NOT_PROCESS_EVENT_HANDLER_MESSAGE = "์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."; + + private final MenuEventManager menuEventManager; + + protected MenuView() { + this(MenuEventManager.builder()); + } + + protected MenuView(MenuEventManager menuEventManager) { + if (menuEventManager == null) { + throw new IllegalArgumentException(NOT_RECEIVED_EVENT_MANAGER_MESSAGE); + } + this.menuEventManager = menuEventManager; + } + + protected abstract Class getType(); + + @Override + public void show() { + Console.printHeader(this.title()); + List menuList = Menu.findAll(this.getType()); + for (Menu menu : menuList) { + Console.println(String.format(MENU_OUTPUT_FORMAT, menu.getCommand(), menu.getName())); + } + Console.println(); + } + + public Menu question() { + do { + Console.printHeader("์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์„ ํƒํ•˜์„ธ์š”."); + String command = Console.readline(); + try { + Menu menu = Menu.findByCommand(this.getType(), command) + .orElseThrow(() -> new IllegalArgumentException(CAN_NOT_SELECTED_FUNCTION_MESSAGE)); + Console.println(); + return menu; + } catch (IllegalArgumentException e) { + Console.println(); + Console.printError(e.getMessage()); + Console.println(); + } + } while (true); + } + + public void onEvent(Menu menu) { + Runnable handler = this.menuEventManager.select(menu) + .orElseThrow(() -> new IllegalArgumentException(CAN_NOT_PROCESS_EVENT_HANDLER_MESSAGE)); + handler.run(); + } +} diff --git a/src/main/java/subway/screen/view/View.java b/src/main/java/subway/screen/view/View.java new file mode 100644 index 000000000..ab128c2c5 --- /dev/null +++ b/src/main/java/subway/screen/view/View.java @@ -0,0 +1,6 @@ +package subway.screen.view; + +public interface View { + String title(); + void show(); +} diff --git a/src/test/java/subway/screen/view/MenuEventManagerTest.java b/src/test/java/subway/screen/view/MenuEventManagerTest.java new file mode 100644 index 000000000..0c01ab575 --- /dev/null +++ b/src/test/java/subway/screen/view/MenuEventManagerTest.java @@ -0,0 +1,53 @@ +package subway.screen.view; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class MenuEventManagerTest { + private enum EnumMenu implements Menu { + ITEM("command", "name"), NONE("", ""); + + private final String command; + private final String name; + + EnumMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } + } + + @Test + public void addEventListener__NotReceivedMenuException() { + MenuEventManager menuEventManager = MenuEventManager.builder(); + String message = "๋ฉ”๋‰ด๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> menuEventManager.addEventListener(null, () -> { + })).isInstanceOf(IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addEventListener__NotReceivedHandlerException() { + MenuEventManager menuEventManager = MenuEventManager.builder(); + String message = "์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> menuEventManager.addEventListener(EnumMenu.ITEM, null)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void select() { + MenuEventManager menuEventManager = MenuEventManager.builder().addEventListener(EnumMenu.ITEM, () -> { + }); + assertThat(menuEventManager.select(EnumMenu.NONE)).isNotPresent(); + assertThat(menuEventManager.select(EnumMenu.ITEM)).isPresent(); + } +} diff --git a/src/test/java/subway/screen/view/MenuTest.java b/src/test/java/subway/screen/view/MenuTest.java new file mode 100644 index 000000000..755ddd6cd --- /dev/null +++ b/src/test/java/subway/screen/view/MenuTest.java @@ -0,0 +1,61 @@ +package subway.screen.view; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class MenuTest { + private static class ClassMenu implements Menu { + @Override + public String getCommand() { + return ""; + } + + @Override + public String getName() { + return ""; + } + } + + private enum EnumMenu implements Menu { + ITEM("command", "name"); + + private final String command; + private final String name; + + EnumMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } + } + + @Test + public void findAll() { + EnumMenu[] enumMenus = EnumMenu.values(); + assertThat(Menu.findAll(EnumMenu.class)).containsExactly(enumMenus); + } + + @Test + public void findAll__NotEnumTypeClassException() { + String message = "Enum ํ˜•์‹์˜ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> Menu.findAll(ClassMenu.class)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void findByCommand() { + EnumMenu item = EnumMenu.ITEM; + assertThat(Menu.findByCommand(EnumMenu.class, "none")).isNotPresent(); + assertThat(Menu.findByCommand(EnumMenu.class, item.getCommand())).isPresent(); + } +} diff --git a/src/test/java/subway/screen/view/MenuViewTest.java b/src/test/java/subway/screen/view/MenuViewTest.java new file mode 100644 index 000000000..111ddd4ad --- /dev/null +++ b/src/test/java/subway/screen/view/MenuViewTest.java @@ -0,0 +1,142 @@ +package subway.screen.view; + +import static org.assertj.core.api.Assertions.*; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import subway.screen.ui.Console; + +public class MenuViewTest { + private MockedStatic mockConsole; + + private enum TestMenu implements Menu { + ITEM("command", "name"); + + private final String command; + private final String name; + + TestMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } + } + + private static class TestMenuView extends MenuView { + public TestMenuView() { + } + + public TestMenuView(MenuEventManager menuEventManager) { + super(menuEventManager); + } + + @Override + protected Class getType() { + return TestMenu.class; + } + + @Override + public String title() { + return "ํ…Œ์ŠคํŠธ ํ™”๋ฉด"; + } + } + + @BeforeEach + public void setup() { + mockConsole = Mockito.mockStatic(Console.class); + } + + @Test + public void constructor__NotReceivedEventManagerException() { + String message = "์ด๋ฒคํŠธ ๊ด€๋ฆฌ์ž๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new MenuView(null) { + @Override + public String title() { + return ""; + } + + @Override + protected Class getType() { + return null; + } + }).isInstanceOf(IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void show() { + TestMenu item = TestMenu.ITEM; + TestMenuView testMenuView = new TestMenuView(); + testMenuView.show(); + this.mockConsole.verify(() -> { + Console.printHeader(testMenuView.title()); + Console.println(String.format("%s. %s", item.command, item.name)); + Console.println(); + }); + } + + @Test + public void question() { + TestMenu item = TestMenu.ITEM; + TestMenuView testMenuView = new TestMenuView(); + this.mockConsole.when(Console::readline).thenReturn(item.command); + assertThat(testMenuView.question()).isEqualTo(item); + } + + @Test + public void question_CanNotSelectedFunctionException() { + TestMenu item = TestMenu.ITEM; + TestMenuView testMenuView = new TestMenuView(); + String message = "์„ ํƒํ•  ์ˆ˜ ์—†๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค."; + this.mockConsole.when(Console::readline).thenReturn("none"); + this.mockConsole.when(Console::readline).thenReturn(item.command); + testMenuView.question(); + this.mockConsole.verify(() -> { + Console.println(); + Console.printError(message); + Console.println(); + + Console.println(); + }); + } + + @Test + public void onEvent() { + TestMenu item = TestMenu.ITEM; + AtomicInteger count = new AtomicInteger(0); + TestMenuView testMenuView = new TestMenuView( + MenuEventManager.builder().addEventListener(item, count::getAndIncrement)); + testMenuView.onEvent(item); + assertThat(count.get()).isEqualTo(1); + } + + @Test + public void onEvent__CanNotProcessEventHandlerException() { + TestMenu item = TestMenu.ITEM; + TestMenuView testMenuView = new TestMenuView(); + String message = "์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> testMenuView.onEvent(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + assertThatThrownBy(() -> testMenuView.onEvent(item)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @AfterEach + public void init() { + mockConsole.close(); + } +} From c3a6daa43b01c684064b8975d9f0d608ebe9fdde Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 10:39:05 +0900 Subject: [PATCH 31/45] =?UTF-8?q?docs:=208.=20Screen=20Layer=20Skeleton=20?= =?UTF-8?q?-=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 503 ++++++++++++++++++++++++++++++++++++- 1 file changed, 502 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 891e87794..c5fae9353 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -2424,4 +2424,505 @@ public class StationController { } ``` -์—ญ๊ณผ ๊ฐ™์ด ๋…ธ๋“œ๋„ ๊ฐ™์ด ์ถ”๊ฐ€๋˜๋„๋ก ๋ณ€๊ฒฝ. \ No newline at end of file +์—ญ๊ณผ ๊ฐ™์ด ๋…ธ๋“œ๋„ ๊ฐ™์ด ์ถ”๊ฐ€๋˜๋„๋ก ๋ณ€๊ฒฝ. + +## 8. Screen Layer Skeleton + +### Ui + +```java +// Console.java + +package subway.screen.ui; + +import java.io.PrintStream; +import java.util.Scanner; + +public final class Console { + private static final Scanner scanner = new Scanner(System.in); + private static final PrintStream printer = System.out; + + private static final String HEADER_OUTPUT_FORMAT = "## %s"; + private static final String INFO_OUTPUT_FORMAT = "[INFO] %s"; + private static final String ERROR_OUTPUT_FORMAT = "[ERROR] %s"; + + public static String readline() { + return scanner.nextLine(); + } + + public static void println() { + printer.println(); + } + + public static void println(String message) { + printer.println(message); + } + + public static void printHeader(String message) { + println(String.format(HEADER_OUTPUT_FORMAT, message)); + } + + public static void printInfo(String message) { + println(String.format(INFO_OUTPUT_FORMAT, message)); + } + + public static void printError(String message) { + println(String.format(ERROR_OUTPUT_FORMAT, message)); + } + +} +``` + +์ฝ˜์†” ์ž…์ถœ๋ ฅ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +### View + +```java +// View.java + +package subway.screen.view; + +public interface View { + String title(); + void show(); +} +``` + +ํ™”๋ฉด ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ์ •์˜. + +```java +// MenuTest.java + +package subway.screen.view; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class MenuTest { + private static class ClassMenu implements Menu { + @Override + public String getCommand() { + return ""; + } + + @Override + public String getName() { + return ""; + } + } + + private enum EnumMenu implements Menu { + ITEM("command", "name"); + + private final String command; + private final String name; + + EnumMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } + } + + @Test + public void findAll() { + EnumMenu[] enumMenus = EnumMenu.values(); + assertThat(Menu.findAll(EnumMenu.class)).containsExactly(enumMenus); + } + + @Test + public void findAll__NotEnumTypeClassException() { + String message = "Enum ํ˜•์‹์˜ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> Menu.findAll(ClassMenu.class)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void findByCommand() { + EnumMenu item = EnumMenu.ITEM; + assertThat(Menu.findByCommand(EnumMenu.class, "none")).isNotPresent(); + assertThat(Menu.findByCommand(EnumMenu.class, item.getCommand())).isPresent(); + } +} +``` + +```java +// Menu.java + +package subway.screen.view; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public interface Menu { + String getCommand(); + + String getName(); + + static List findAll(Class menuClass) { + Menu[] enumValues = menuClass.getEnumConstants(); + if(enumValues == null) { + throw new IllegalArgumentException("Enum ํ˜•์‹์˜ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."); + } + return Arrays.stream(enumValues).collect(Collectors.toList()); + } + + static Optional findByCommand(Class menuClass, String command) { + List menuList = findAll(menuClass); + for (Menu menu : menuList) { + if (menu.getCommand().equals(command)) { + return Optional.of(menu); + } + } + return Optional.empty(); + } +} +``` + +๋ฉ”๋‰ด ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ์ •์˜. + +๋ฉ”๋‰ด ๋ชฉ๋ก ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +๋ช…๋ น์–ด ๊ธฐ์ค€ ๋‹จ๊ฑด ์กฐํšŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// MenuEventManagerTest.java + +package subway.screen.view; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public class MenuEventManagerTest { + private enum EnumMenu implements Menu { + ITEM("command", "name"), NONE("", ""); + + private final String command; + private final String name; + + EnumMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } + } + + @Test + public void addEventListener__NotReceivedMenuException() { + MenuEventManager menuEventManager = MenuEventManager.builder(); + String message = "๋ฉ”๋‰ด๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> menuEventManager.addEventListener(null, () -> { + })).isInstanceOf(IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void addEventListener__NotReceivedHandlerException() { + MenuEventManager menuEventManager = MenuEventManager.builder(); + String message = "์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> menuEventManager.addEventListener(EnumMenu.ITEM, null)).isInstanceOf( + IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void select() { + MenuEventManager menuEventManager = MenuEventManager.builder().addEventListener(EnumMenu.ITEM, () -> { + }); + assertThat(menuEventManager.select(EnumMenu.NONE)).isNotPresent(); + assertThat(menuEventManager.select(EnumMenu.ITEM)).isPresent(); + } +} +``` + +```java +// MenuEventManager.java + +package subway.screen.view; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public final class MenuEventManager { + private static final String NOT_RECEIVED_MENU_MESSAGE = "๋ฉ”๋‰ด๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + private static final String NOT_RECEIVED_HANDLER_MESSAGE = "์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + + private final Map handlerMap = new HashMap<>(); + + private MenuEventManager() { + } + + public static MenuEventManager builder() { + return new MenuEventManager(); + } + + public MenuEventManager addEventListener(Menu menu) { + return this.addEventListener(menu, () -> { + }); + } + + public MenuEventManager addEventListener(Menu menu, Runnable handler) { + this.validate(menu, handler); + this.handlerMap.put(menu, handler); + return this; + } + + private void validate(Menu menu, Runnable runnable) { + if (menu == null) { + throw new IllegalArgumentException(NOT_RECEIVED_MENU_MESSAGE); + } + if (runnable == null) { + throw new IllegalArgumentException(NOT_RECEIVED_HANDLER_MESSAGE); + } + } + + public void removeEventListener(Menu menu) { + this.handlerMap.remove(menu); + } + + public void removeAllEventListener() { + this.handlerMap.clear(); + } + + Optional select(Menu menu) { + return Optional.ofNullable(this.handlerMap.get(menu)); + } +} +``` + +๋ฉ”๋‰ด ์ด๋ฒคํŠธ ๋“ฑ๋ก ๋ฐ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +```java +// MenuViewTest.java + +package subway.screen.view; + +import static org.assertj.core.api.Assertions.*; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +import subway.screen.ui.Console; + +public class MenuViewTest { + private MockedStatic mockConsole; + + private enum TestMenu implements Menu { + ITEM("command", "name"); + + private final String command; + private final String name; + + TestMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } + } + + private static class TestMenuView extends MenuView { + public TestMenuView() { + } + + public TestMenuView(MenuEventManager menuEventManager) { + super(menuEventManager); + } + + @Override + protected Class getType() { + return TestMenu.class; + } + + @Override + public String title() { + return "ํ…Œ์ŠคํŠธ ํ™”๋ฉด"; + } + } + + @BeforeEach + public void setup() { + mockConsole = Mockito.mockStatic(Console.class); + } + + @Test + public void constructor__NotReceivedEventManagerException() { + String message = "์ด๋ฒคํŠธ ๊ด€๋ฆฌ์ž๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new MenuView(null) { + @Override + public String title() { + return ""; + } + + @Override + protected Class getType() { + return null; + } + }).isInstanceOf(IllegalArgumentException.class).hasMessage(message); + } + + @Test + public void show() { + TestMenu item = TestMenu.ITEM; + TestMenuView testMenuView = new TestMenuView(); + testMenuView.show(); + this.mockConsole.verify(() -> { + Console.printHeader(testMenuView.title()); + Console.println(String.format("%s. %s", item.command, item.name)); + Console.println(); + }); + } + + @Test + public void question() { + TestMenu item = TestMenu.ITEM; + TestMenuView testMenuView = new TestMenuView(); + this.mockConsole.when(Console::readline).thenReturn(item.command); + assertThat(testMenuView.question()).isEqualTo(item); + } + + @Test + public void question_CanNotSelectedFunctionException() { + TestMenu item = TestMenu.ITEM; + TestMenuView testMenuView = new TestMenuView(); + String message = "์„ ํƒํ•  ์ˆ˜ ์—†๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค."; + this.mockConsole.when(Console::readline).thenReturn("none"); + this.mockConsole.when(Console::readline).thenReturn(item.command); + testMenuView.question(); + this.mockConsole.verify(() -> { + Console.println(); + Console.printError(message); + Console.println(); + + Console.println(); + }); + } + + @Test + public void onEvent() { + TestMenu item = TestMenu.ITEM; + AtomicInteger count = new AtomicInteger(0); + TestMenuView testMenuView = new TestMenuView( + MenuEventManager.builder().addEventListener(item, count::getAndIncrement)); + testMenuView.onEvent(item); + assertThat(count.get()).isEqualTo(1); + } + + @Test + public void onEvent__CanNotProcessEventHandlerException() { + TestMenu item = TestMenu.ITEM; + TestMenuView testMenuView = new TestMenuView(); + String message = "์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> testMenuView.onEvent(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + assertThatThrownBy(() -> testMenuView.onEvent(item)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @AfterEach + public void init() { + mockConsole.close(); + } +} +``` + +```java +// MenuView.java + +package subway.screen.view; + +import java.util.List; + +import subway.screen.ui.Console; + +public abstract class MenuView implements View { + private static final String NOT_RECEIVED_EVENT_MANAGER_MESSAGE = "์ด๋ฒคํŠธ ๊ด€๋ฆฌ์ž๋ฅผ ์ „๋‹ฌ๋ฐ›์ง€ ๋ชปํ•˜์˜€์Šต๋‹ˆ๋‹ค."; + private static final String MENU_OUTPUT_FORMAT = "%s. %s"; + private static final String CAN_NOT_SELECTED_FUNCTION_MESSAGE = "์„ ํƒํ•  ์ˆ˜ ์—†๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค."; + private static final String CAN_NOT_PROCESS_EVENT_HANDLER_MESSAGE = "์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."; + + private final MenuEventManager menuEventManager; + + protected MenuView() { + this(MenuEventManager.builder()); + } + + protected MenuView(MenuEventManager menuEventManager) { + if (menuEventManager == null) { + throw new IllegalArgumentException(NOT_RECEIVED_EVENT_MANAGER_MESSAGE); + } + this.menuEventManager = menuEventManager; + } + + protected abstract Class getType(); + + @Override + public void show() { + Console.printHeader(this.title()); + List menuList = Menu.findAll(this.getType()); + for (Menu menu : menuList) { + Console.println(String.format(MENU_OUTPUT_FORMAT, menu.getCommand(), menu.getName())); + } + Console.println(); + } + + public Menu question() { + do { + Console.printHeader("์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์„ ํƒํ•˜์„ธ์š”."); + String command = Console.readline(); + try { + Menu menu = Menu.findByCommand(this.getType(), command) + .orElseThrow(() -> new IllegalArgumentException(CAN_NOT_SELECTED_FUNCTION_MESSAGE)); + Console.println(); + return menu; + } catch (IllegalArgumentException e) { + Console.println(); + Console.printError(e.getMessage()); + Console.println(); + } + } while (true); + } + + public void onEvent(Menu menu) { + Runnable handler = this.menuEventManager.select(menu) + .orElseThrow(() -> new IllegalArgumentException(CAN_NOT_PROCESS_EVENT_HANDLER_MESSAGE)); + handler.run(); + } +} +``` + +๋ฉ”๋‰ด ํ™”๋ฉด ๊ณตํ†ต ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file From 69d918c94542716090dc2314b18cb2ab9337eafe Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 10:50:37 +0900 Subject: [PATCH 32/45] =?UTF-8?q?feat:=209.=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80(=ED=99=94=EB=A9=B4)=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/PathViewController.java | 66 +++++++++++++++++++ .../subway/presentation/ViewController.java | 5 ++ .../subway/screen/view/path/PathMenu.java | 27 ++++++++ .../subway/screen/view/path/PathMenuView.java | 25 +++++++ 4 files changed, 123 insertions(+) create mode 100644 src/main/java/subway/presentation/PathViewController.java create mode 100644 src/main/java/subway/presentation/ViewController.java create mode 100644 src/main/java/subway/screen/view/path/PathMenu.java create mode 100644 src/main/java/subway/screen/view/path/PathMenuView.java diff --git a/src/main/java/subway/presentation/PathViewController.java b/src/main/java/subway/presentation/PathViewController.java new file mode 100644 index 000000000..b6504c429 --- /dev/null +++ b/src/main/java/subway/presentation/PathViewController.java @@ -0,0 +1,66 @@ +package subway.presentation; + +import subway.application.section.dto.ShortCostResponse; +import subway.screen.ui.Console; +import subway.screen.view.Menu; +import subway.screen.view.path.PathMenuView; + +public class PathViewController implements ViewController { + private final PathMenuView pathMenuView = new PathMenuView(this); + private final SectionController sectionController = new SectionController(); + + @Override + public void execute() { + do { + pathMenuView.show(); + Menu menu = pathMenuView.question(); + try { + pathMenuView.onEvent(menu); + return; + } catch (IllegalArgumentException e) { + Console.printError(e.getMessage()); + Console.println(); + } + } while (true); + } + + public void handleShortDistance() { + String sourceName = this.requestSourceName(); + String sinkName = this.requestSinkName(); + ShortCostResponse shortCostResponse = this.sectionController.computeShortDistance(sourceName, sinkName); + this.printShortCostResponse(shortCostResponse); + } + + public void handleShortTime() { + String sourceName = this.requestSourceName(); + String sinkName = this.requestSinkName(); + ShortCostResponse shortCostResponse = this.sectionController.computeShortTime(sourceName, sinkName); + this.printShortCostResponse(shortCostResponse); + } + + private String requestSourceName() { + Console.printHeader("์ถœ๋ฐœ์—ญ์„ ์ž…๋ ฅํ•˜์„ธ์š”"); + String sourceName = Console.readline(); + Console.println(); + return sourceName; + } + + private String requestSinkName() { + Console.printHeader("๋„์ฐฉ์—ญ์„ ์ž…๋ ฅํ•˜์„ธ์š”"); + String sinkName = Console.readline(); + Console.println(); + return sinkName; + } + + private void printShortCostResponse(ShortCostResponse shortCostResponse) { + Console.printHeader("์กฐํšŒ ๊ฒฐ๊ณผ"); + Console.printInfo("---"); + Console.printInfo(String.format("์ด ๊ฑฐ๋ฆฌ : %dkm", shortCostResponse.getTotalDistance())); + Console.printInfo(String.format("์ด ์†Œ์š” ์‹œ๊ฐ„ : %d๋ถ„", shortCostResponse.getTotalTime())); + Console.printInfo("---"); + for (String stationName : shortCostResponse.getStationNameList()) { + Console.printInfo(stationName); + } + Console.println(); + } +} diff --git a/src/main/java/subway/presentation/ViewController.java b/src/main/java/subway/presentation/ViewController.java new file mode 100644 index 000000000..365a0c4e9 --- /dev/null +++ b/src/main/java/subway/presentation/ViewController.java @@ -0,0 +1,5 @@ +package subway.presentation; + +public interface ViewController { + void execute(); +} diff --git a/src/main/java/subway/screen/view/path/PathMenu.java b/src/main/java/subway/screen/view/path/PathMenu.java new file mode 100644 index 000000000..c7f160db1 --- /dev/null +++ b/src/main/java/subway/screen/view/path/PathMenu.java @@ -0,0 +1,27 @@ +package subway.screen.view.path; + +import subway.screen.view.Menu; + +public enum PathMenu implements Menu { + SHORT_DISTANCE("1", "์ตœ๋‹จ ๊ฑฐ๋ฆฌ"), + SHORT_TIME("2", "์ตœ์†Œ ์‹œ๊ฐ„"), + BACK("B", "๋Œ์•„๊ฐ€๊ธฐ"); + + private final String command; + private final String name; + + PathMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } +} diff --git a/src/main/java/subway/screen/view/path/PathMenuView.java b/src/main/java/subway/screen/view/path/PathMenuView.java new file mode 100644 index 000000000..5ff4d048a --- /dev/null +++ b/src/main/java/subway/screen/view/path/PathMenuView.java @@ -0,0 +1,25 @@ +package subway.screen.view.path; + +import subway.presentation.PathViewController; +import subway.screen.view.Menu; +import subway.screen.view.MenuEventManager; +import subway.screen.view.MenuView; + +public class PathMenuView extends MenuView { + public PathMenuView(PathViewController pathViewController) { + super(MenuEventManager.builder() + .addEventListener(PathMenu.SHORT_DISTANCE, pathViewController::handleShortDistance) + .addEventListener(PathMenu.SHORT_TIME, pathViewController::handleShortTime) + .addEventListener(PathMenu.BACK)); + } + + @Override + public String title() { + return "๊ฒฝ๋กœ ๊ธฐ์ค€"; + } + + @Override + protected Class getType() { + return PathMenu.class; + } +} From 27a10e4512238602cec5d7ecf3098c4b452f3693 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 10:51:00 +0900 Subject: [PATCH 33/45] =?UTF-8?q?docs:=209.=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80(=ED=99=94=EB=A9=B4)=20=EA=B5=AC=ED=98=84=20-?= =?UTF-8?q?=20[solving=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 172 ++++++++++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index c5fae9353..2c40fc8f4 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -2925,4 +2925,174 @@ public abstract class MenuView implements View { } ``` -๋ฉ”๋‰ด ํ™”๋ฉด ๊ณตํ†ต ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file +๋ฉ”๋‰ด ํ™”๋ฉด ๊ณตํ†ต ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +## 9. ๊ฒฝ๋กœ ๊ธฐ์ค€(ํ™”๋ฉด) ๊ตฌํ˜„ + +```java +// PathMenu.java + +package subway.screen.view.path; + +import subway.screen.view.Menu; + +public enum PathMenu implements Menu { + SHORT_DISTANCE("1", "์ตœ๋‹จ ๊ฑฐ๋ฆฌ"), + SHORT_TIME("2", "์ตœ์†Œ ์‹œ๊ฐ„"), + BACK("B", "๋Œ์•„๊ฐ€๊ธฐ"); + + private final String command; + private final String name; + + PathMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } +} +``` + +```java +// MainMenuView + +package subway.screen.view.path; + +import subway.screen.view.Menu; +import subway.screen.view.MenuView; + +public class PathMenuView extends MenuView { + public PathMenuView() { + super(); + } + + @Override + public String title() { + return "๊ฒฝ๋กœ ๊ธฐ์ค€"; + } + + @Override + protected Class getType() { + return PathMenu.class; + } +} +``` + +๊ฒฝ๋กœ ๊ธฐ์ค€(ํ™”๋ฉด) ๊ตฌ์„ฑ. + +```java +// ViewController.java + +package subway.presentation; + +public interface ViewController { + void execute(); +} +``` + +ํ™”๋ฉด ์ œ์–ด ๊ธฐ๋ณธ ์ •์˜. + +```java +// PathViewController.java + +package subway.presentation; + +import subway.application.section.dto.ShortCostResponse; +import subway.screen.ui.Console; +import subway.screen.view.Menu; +import subway.screen.view.path.PathMenuView; + +public class PathViewController implements ViewController { + private final PathMenuView pathMenuView = new PathMenuView(this); + private final SectionController sectionController = new SectionController(); + + @Override + public void execute() { + do { + pathMenuView.show(); + Menu menu = pathMenuView.question(); + try { + pathMenuView.onEvent(menu); + return; + } catch (IllegalArgumentException e) { + Console.printError(e.getMessage()); + Console.println(); + } + } while (true); + } + + public void handleShortDistance() { + String sourceName = this.requestSourceName(); + String sinkName = this.requestSinkName(); + ShortCostResponse shortCostResponse = this.sectionController.computeShortDistance(sourceName, sinkName); + this.printShortCostResponse(shortCostResponse); + } + + public void handleShortTime() { + String sourceName = this.requestSourceName(); + String sinkName = this.requestSinkName(); + ShortCostResponse shortCostResponse = this.sectionController.computeShortTime(sourceName, sinkName); + this.printShortCostResponse(shortCostResponse); + } + + private String requestSourceName() { + Console.printHeader("์ถœ๋ฐœ์—ญ์„ ์ž…๋ ฅํ•˜์„ธ์š”"); + String sourceName = Console.readline(); + Console.println(); + return sourceName; + } + + private String requestSinkName() { + Console.printHeader("๋„์ฐฉ์—ญ์„ ์ž…๋ ฅํ•˜์„ธ์š”"); + String sinkName = Console.readline(); + Console.println(); + return sinkName; + } + + private void printShortCostResponse(ShortCostResponse shortCostResponse) { + Console.printHeader("์กฐํšŒ ๊ฒฐ๊ณผ"); + Console.printInfo("---"); + Console.printInfo(String.format("์ด ๊ฑฐ๋ฆฌ : %dkm", shortCostResponse.getTotalDistance())); + Console.printInfo(String.format("์ด ์†Œ์š” ์‹œ๊ฐ„ : %d๋ถ„", shortCostResponse.getTotalTime())); + Console.printInfo("---"); + for (String stationName : shortCostResponse.getStationNameList()) { + Console.printInfo(stationName); + } + Console.println(); + } +} +``` + +๊ฒฝ๋กœ ๊ธฐ์ค€(ํ™”๋ฉด) ์ œ์–ด ๊ตฌํ˜„. + +๋ฉ”๋‰ด ์„ ํƒ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๊ตฌํ˜„. + +```java +// MainMenuView + +package subway.screen.view.path; + +import subway.presentation.PathViewController; +import subway.screen.view.Menu; +import subway.screen.view.MenuEventManager; +import subway.screen.view.MenuView; + +public class PathMenuView extends MenuView { + public PathMenuView(PathViewController pathViewController) { + super(MenuEventManager.builder() + .addEventListener(PathMenu.SHORT_DISTANCE, pathViewController::handleShortDistance) + .addEventListener(PathMenu.SHORT_TIME, pathViewController::handleShortTime) + .addEventListener(PathMenu.BACK)); + } +} +``` + +์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋งคํ•‘. \ No newline at end of file From 84134a0ec6e0b167fd2b94041d389a9161cac49c Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 10:55:42 +0900 Subject: [PATCH 34/45] =?UTF-8?q?feat:=2010.=20=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/MainViewController.java | 35 +++++++++++++++++++ .../subway/screen/view/main/MainMenu.java | 25 +++++++++++++ .../subway/screen/view/main/MainMenuView.java | 24 +++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/main/java/subway/presentation/MainViewController.java create mode 100644 src/main/java/subway/screen/view/main/MainMenu.java create mode 100644 src/main/java/subway/screen/view/main/MainMenuView.java diff --git a/src/main/java/subway/presentation/MainViewController.java b/src/main/java/subway/presentation/MainViewController.java new file mode 100644 index 000000000..36584f5d4 --- /dev/null +++ b/src/main/java/subway/presentation/MainViewController.java @@ -0,0 +1,35 @@ +package subway.presentation; + +import subway.screen.ui.Console; +import subway.screen.view.Menu; +import subway.screen.view.main.MainMenuView; + +public class MainViewController implements ViewController { + private final MainMenuView mainMenuView = new MainMenuView(this); + + private boolean end; + + @Override + public void execute() { + this.end = false; + do { + mainMenuView.show(); + Menu menu = mainMenuView.question(); + try { + mainMenuView.onEvent(menu); + } catch (IllegalArgumentException e) { + Console.printError(e.getMessage()); + Console.println(); + } + } while (!this.end); + } + + public void handlePathSearch() { + PathViewController pathViewController = new PathViewController(); + pathViewController.execute(); + } + + public void handleEnd() { + this.end = true; + } +} diff --git a/src/main/java/subway/screen/view/main/MainMenu.java b/src/main/java/subway/screen/view/main/MainMenu.java new file mode 100644 index 000000000..ffcefde92 --- /dev/null +++ b/src/main/java/subway/screen/view/main/MainMenu.java @@ -0,0 +1,25 @@ +package subway.screen.view.main; + +import subway.screen.view.Menu; + +public enum MainMenu implements Menu { + PATH_SEARCH("1", "๊ฒฝ๋กœ ์กฐํšŒ"), END("Q", "์ข…๋ฃŒ"); + + private final String command; + private final String name; + + MainMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } +} diff --git a/src/main/java/subway/screen/view/main/MainMenuView.java b/src/main/java/subway/screen/view/main/MainMenuView.java new file mode 100644 index 000000000..94fe97c2f --- /dev/null +++ b/src/main/java/subway/screen/view/main/MainMenuView.java @@ -0,0 +1,24 @@ +package subway.screen.view.main; + +import subway.presentation.MainViewController; +import subway.screen.view.Menu; +import subway.screen.view.MenuEventManager; +import subway.screen.view.MenuView; + +public class MainMenuView extends MenuView { + public MainMenuView(MainViewController mainViewController) { + super(MenuEventManager.builder() + .addEventListener(MainMenu.PATH_SEARCH, mainViewController::handlePathSearch) + .addEventListener(MainMenu.END, mainViewController::handleEnd)); + } + + @Override + public String title() { + return "๋ฉ”์ธ ํ™”๋ฉด"; + } + + @Override + protected Class getType() { + return MainMenu.class; + } +} From 1895a74351aa948835f30b0e3ddf6beec6843aa4 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 10:55:58 +0900 Subject: [PATCH 35/45] =?UTF-8?q?docs:=2010.=20=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84=20-=20[solving=5Fproces?= =?UTF-8?q?s.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 124 +++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/.github/solving_process.md b/.github/solving_process.md index 2c40fc8f4..043b23459 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -3095,4 +3095,128 @@ public class PathMenuView extends MenuView { } ``` +์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋งคํ•‘. + +## 10. ๋ฉ”์ธ ํ™”๋ฉด ๊ตฌํ˜„ + +```java +// MainMenu.java + +package subway.screen.view.main; + +import subway.screen.view.Menu; + +public enum MainMenu implements Menu { + PATH_SEARCH("1", "๊ฒฝ๋กœ ์กฐํšŒ"), END("Q", "์ข…๋ฃŒ"); + + private final String command; + private final String name; + + MainMenu(String command, String name) { + this.command = command; + this.name = name; + } + + @Override + public String getCommand() { + return this.command; + } + + @Override + public String getName() { + return this.name; + } +} +``` + +```java +// MainMenuView.java + +package subway.screen.view.main; + +import subway.screen.view.Menu; +import subway.screen.view.MenuView; + +public class MainMenuView extends MenuView { + public MainMenuView() { + super(); + } + + @Override + public String title() { + return "๋ฉ”์ธ ํ™”๋ฉด"; + } + + @Override + protected Class getType() { + return MainMenu.class; + } +} +``` + +๋ฉ”์ธ ํ™”๋ฉด ๊ตฌ์„ฑ. + +```java +// MainViewController.java + +package subway.presentation; + +import subway.screen.ui.Console; +import subway.screen.view.Menu; +import subway.screen.view.main.MainMenuView; + +public class MainViewController implements ViewController { + private final MainMenuView mainMenuView = new MainMenuView(this); + + private boolean end; + + @Override + public void execute() { + this.end = false; + do { + mainMenuView.show(); + Menu menu = mainMenuView.question(); + try { + mainMenuView.onEvent(menu); + } catch (IllegalArgumentException e) { + Console.printError(e.getMessage()); + Console.println(); + } + } while (!this.end); + } + + public void handlePathSearch() { + PathViewController pathViewController = new PathViewController(); + pathViewController.execute(); + } + + public void handleEnd() { + this.end = true; + } +} +``` + +๋ฉ”์ธ ํ™”๋ฉด ์ œ์–ด ๊ตฌํ˜„. + +๋ฉ”๋‰ด ์„ ํƒ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๊ตฌํ˜„. + +```java +// MainMenuView.java + +package subway.screen.view.main; + +import subway.presentation.MainViewController; +import subway.screen.view.Menu; +import subway.screen.view.MenuEventManager; +import subway.screen.view.MenuView; + +public class MainMenuView extends MenuView { + public MainMenuView(MainViewController mainViewController) { + super(MenuEventManager.builder() + .addEventListener(MainMenu.PATH_SEARCH, mainViewController::handlePathSearch) + .addEventListener(MainMenu.END, mainViewController::handleEnd)); + } +} +``` + ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋งคํ•‘. \ No newline at end of file From b4c27bf546ccd45ee83e6334c1d5674340d83549 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 11:57:30 +0900 Subject: [PATCH 36/45] =?UTF-8?q?feat:=2011.=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../subway/infrastructure/FileParser.java | 47 ++++++++++++ .../subway/infrastructure/FileParserTest.java | 75 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 src/main/java/subway/infrastructure/FileParser.java create mode 100644 src/test/java/subway/infrastructure/FileParserTest.java diff --git a/src/main/java/subway/infrastructure/FileParser.java b/src/main/java/subway/infrastructure/FileParser.java new file mode 100644 index 000000000..8b77789b7 --- /dev/null +++ b/src/main/java/subway/infrastructure/FileParser.java @@ -0,0 +1,47 @@ +package subway.infrastructure; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public abstract class FileParser { + private static final String NOT_EXISTS_FILE_MESSAGE = "ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + private static final String NOT_FILE_TYPE_MESSAGE = "ํŒŒ์ผ ์œ ํ˜•์ด ์•„๋‹™๋‹ˆ๋‹ค."; + private static final String NOT_ALLOWED_FILE_EXTENSION_MESSAGE = "ํ—ˆ์šฉ๋œ ํŒŒ์ผ ํ™•์žฅ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."; + + protected final File file; + + public FileParser(String fileName) { + this(new File(Objects.requireNonNull(FileParser.class.getClassLoader().getResource(fileName)).getPath())); + } + + public FileParser(File file) { + this.validate(file); + this.file = file; + } + + private void validate(File file) { + if (file == null || !file.exists()) { + throw new IllegalArgumentException(NOT_EXISTS_FILE_MESSAGE); + } + if (!file.isFile()) { + throw new IllegalArgumentException(NOT_FILE_TYPE_MESSAGE); + } + if (!this.allowExtension(this.extractExtension(file.getName()))) { + throw new IllegalArgumentException(NOT_ALLOWED_FILE_EXTENSION_MESSAGE); + } + } + + private String extractExtension(String fileName) { + int index = fileName.lastIndexOf("."); + if (index > 0) { + return fileName.substring(index + 1); + } + return ""; + } + + public abstract boolean allowExtension(String extension); + + public abstract List> parser(); +} diff --git a/src/test/java/subway/infrastructure/FileParserTest.java b/src/test/java/subway/infrastructure/FileParserTest.java new file mode 100644 index 000000000..c0427802d --- /dev/null +++ b/src/test/java/subway/infrastructure/FileParserTest.java @@ -0,0 +1,75 @@ +package subway.infrastructure; + +import static org.assertj.core.api.Assertions.*; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class FileParserTest { + private File file; + private File directory; + + @BeforeEach + public void setup() { + this.directory = new File("./dummy"); + this.file = new File("./dummy.txt"); + try { + this.directory.mkdir(); + this.file.createNewFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static class TestFileParser extends FileParser { + public TestFileParser(File file) { + super(file); + } + + @Override + public boolean allowExtension(String extension) { + return "java".equals(extension); + } + + @Override + public List> parser() { + return null; + } + } + + @Test + public void constructor__NotExistsFileException() { + File none = new File("./none.txt"); + String message = "ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new TestFileParser(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + assertThatThrownBy(() -> new TestFileParser(none)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void constructor__NotReceivedFileTypeException() { + String message = "ํŒŒ์ผ ์œ ํ˜•์ด ์•„๋‹™๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new TestFileParser(this.directory)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void constructor__NotAllowedFileExtensionException() { + String message = "ํ—ˆ์šฉ๋œ ํŒŒ์ผ ํ™•์žฅ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new TestFileParser(this.file)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @AfterEach + public void init() { + this.file.delete(); + this.directory.delete(); + } +} From 297a49164f15801750061ce5a4a98bb385d343d0 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 13:18:48 +0900 Subject: [PATCH 37/45] =?UTF-8?q?docs:=2011.=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20-=20[solving=5Fprocess.md]=20=ED=92=80?= =?UTF-8?q?=EC=9D=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 138 ++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 043b23459..21a7e4189 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -3219,4 +3219,140 @@ public class MainMenuView extends MenuView { } ``` -์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋งคํ•‘. \ No newline at end of file +์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋งคํ•‘. + +## 11. ํŒŒ์ผ ๊ฒ€์ฆ + +```java +// FileParserTest.java + +package subway.infrastructure; + +import static org.assertj.core.api.Assertions.*; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class FileParserTest { + private File file; + private File directory; + + @BeforeEach + public void setup() { + this.directory = new File("./dummy"); + this.file = new File("./dummy.txt"); + try { + this.directory.mkdir(); + this.file.createNewFile(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static class TestFileParser extends FileParser { + public TestFileParser(File file) { + super(file); + } + + @Override + public boolean allowExtension(String extension) { + return "java".equals(extension); + } + + @Override + public List> parser() { + return null; + } + } + + @Test + public void constructor__NotExistsFileException() { + File none = new File("./none.txt"); + String message = "ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new TestFileParser(null)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + assertThatThrownBy(() -> new TestFileParser(none)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void constructor__NotReceivedFileTypeException() { + String message = "ํŒŒ์ผ ์œ ํ˜•์ด ์•„๋‹™๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new TestFileParser(this.directory)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @Test + public void constructor__NotAllowedFileExtensionException() { + String message = "ํ—ˆ์šฉ๋œ ํŒŒ์ผ ํ™•์žฅ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."; + assertThatThrownBy(() -> new TestFileParser(this.file)).isInstanceOf(IllegalArgumentException.class) + .hasMessage(message); + } + + @AfterEach + public void init() { + this.file.delete(); + this.directory.delete(); + } +} +``` + +```java +// FileParser.java + +package subway.infrastructure; + +import java.io.File; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public abstract class FileParser { + private static final String NOT_EXISTS_FILE_MESSAGE = "ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."; + private static final String NOT_FILE_TYPE_MESSAGE = "ํŒŒ์ผ ์œ ํ˜•์ด ์•„๋‹™๋‹ˆ๋‹ค."; + private static final String NOT_ALLOWED_FILE_EXTENSION_MESSAGE = "ํ—ˆ์šฉ๋œ ํŒŒ์ผ ํ™•์žฅ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."; + + protected final File file; + + public FileParser(String fileName) { + this(new File(Objects.requireNonNull(FileParser.class.getClassLoader().getResource(fileName)).getPath())); + } + + public FileParser(File file) { + this.validate(file); + this.file = file; + } + + private void validate(File file) { + if (file == null || !file.exists()) { + throw new IllegalArgumentException(NOT_EXISTS_FILE_MESSAGE); + } + if (!file.isFile()) { + throw new IllegalArgumentException(NOT_FILE_TYPE_MESSAGE); + } + if (!this.allowExtension(this.extractExtension(file.getName()))) { + throw new IllegalArgumentException(NOT_ALLOWED_FILE_EXTENSION_MESSAGE); + } + } + + private String extractExtension(String fileName) { + int index = fileName.lastIndexOf("."); + if (index > 0) { + return fileName.substring(index + 1); + } + return ""; + } + + public abstract boolean allowExtension(String extension); + + public abstract List> parser(); +} +``` + +ํŒŒ์ผ ๊ฒ€์ฆ ๊ณตํ†ต ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file From 69f60e06f011cded575900d91794d6dac3f9ddc9 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 14:16:00 +0900 Subject: [PATCH 38/45] feat: 12. Xml Parser --- .../subway/infrastructure/XmlFileParser.java | 115 ++++++++++++++++++ .../infrastructure/XmlFileParserTest.java | 57 +++++++++ 2 files changed, 172 insertions(+) create mode 100644 src/main/java/subway/infrastructure/XmlFileParser.java create mode 100644 src/test/java/subway/infrastructure/XmlFileParserTest.java diff --git a/src/main/java/subway/infrastructure/XmlFileParser.java b/src/main/java/subway/infrastructure/XmlFileParser.java new file mode 100644 index 000000000..5d65a6828 --- /dev/null +++ b/src/main/java/subway/infrastructure/XmlFileParser.java @@ -0,0 +1,115 @@ +package subway.infrastructure; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class XmlFileParser extends FileParser { + private static final int UNKNOWN_NODE_LIST = 0; + private static final int HAS_ELEMENT_NODE_LIST = 1; + private static final int HAS_TEXT_NODE_LIST = 2; + + private final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + public XmlFileParser(String fileName) { + super(fileName); + } + + public XmlFileParser(File file) { + super(file); + } + + @Override + public boolean allowExtension(String extension) { + return "xml".equals(extension); + } + + @Override + public List> parser() { + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(file); + document.getDocumentElement().normalize(); + Element root = document.getDocumentElement(); + return this.find(root); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private List> find(Element root) { + List> data = new ArrayList<>(); + NodeList nodeList = root.getChildNodes(); + for (int index = 0; index < nodeList.getLength(); index++) { + Node node = nodeList.item(index); + if (node.getNodeType() == Node.ELEMENT_NODE) { + data.add(this.serialize(node.getChildNodes())); + } + } + return data; + } + + private Map serialize(NodeList parentNodeList) { + Map data = new HashMap<>(); + for (int index = 0; index < parentNodeList.getLength(); index++) { + Node child = parentNodeList.item(index); + int childType = child.getNodeType(); + String childName = child.getNodeName(); + if (childType == Node.ELEMENT_NODE) { + data.put(childName, this.getNodeData(child)); + } + } + return data; + } + + private Object getNodeData(Node node) { + NodeList nodeList = node.getChildNodes(); + int nodeListType = this.getNodeListType(nodeList); + if (nodeListType == HAS_ELEMENT_NODE_LIST) { + return this.serialize(nodeList); + } else if (nodeListType == HAS_TEXT_NODE_LIST) { + return this.getTextValue(node); + } + return null; + } + + private int getNodeListType(NodeList nodeList) { + for (int index = 0; index < nodeList.getLength(); index++) { + Node node = nodeList.item(index); + int nodeType = node.getNodeType(); + String _nodeValue = node.getNodeValue(); + if (nodeType == Node.ELEMENT_NODE) { + return HAS_ELEMENT_NODE_LIST; + } else if (nodeType == Node.TEXT_NODE && this.hasTextValue(_nodeValue)) { + return HAS_TEXT_NODE_LIST; + } + } + return UNKNOWN_NODE_LIST; + } + + private String getTextValue(Node node) { + NodeList nodeList = node.getChildNodes(); + for (int index = 0; index < nodeList.getLength(); index++) { + Node child = nodeList.item(index); + String _childValue = child.getNodeValue(); + if (child.getNodeType() == Node.TEXT_NODE && this.hasTextValue(_childValue)) { + return _childValue.trim(); + } + } + return ""; + } + + private boolean hasTextValue(String value) { + return value != null && !value.trim().isEmpty(); + } +} diff --git a/src/test/java/subway/infrastructure/XmlFileParserTest.java b/src/test/java/subway/infrastructure/XmlFileParserTest.java new file mode 100644 index 000000000..4177b2c02 --- /dev/null +++ b/src/test/java/subway/infrastructure/XmlFileParserTest.java @@ -0,0 +1,57 @@ +package subway.infrastructure; + +import static org.assertj.core.api.Assertions.*; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class XmlFileParserTest { + private static final String content = "\n" + + "\n" + + " \n" + + " name\n" + + " \n" + + " name\n" + + " \n" + + " \n" + + "\n"; + private static File file; + + @BeforeAll + public static void setup() { + file = new File("file.xml"); + try { + file.createNewFile(); + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) { + bufferedWriter.write(content); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test + public void parser() { + XmlFileParser xmlFileParser = new XmlFileParser(file); + List> dataList = xmlFileParser.parser(); + assertThat(dataList).hasSize(1); + Map data = dataList.get(0); + assertThat(data.get("name")).isInstanceOf(String.class).isEqualTo("name"); + assertThat(data.get("job")).isInstanceOf(Map.class); + Map job = (Map)data.get("job"); + assertThat(job.get("name")).isInstanceOf(String.class).isEqualTo("name"); + } + + @AfterAll + public static void init() { + file.delete(); + } +} From 86820fc1a00c2960666ea809c9b58741789ea5c4 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 14:16:19 +0900 Subject: [PATCH 39/45] =?UTF-8?q?docs:=2012.=20Xml=20Parser=20-=20[solving?= =?UTF-8?q?=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 188 ++++++++++++++++++++++++++++++++++++- 1 file changed, 187 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 21a7e4189..5d18fa4f3 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -3355,4 +3355,190 @@ public abstract class FileParser { } ``` -ํŒŒ์ผ ๊ฒ€์ฆ ๊ณตํ†ต ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file +ํŒŒ์ผ ๊ฒ€์ฆ ๊ณตํ†ต ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +## 12. Xml Parser + +```java +// XmlFileParserTest.java + +package subway.infrastructure; + +import static org.assertj.core.api.Assertions.*; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class XmlFileParserTest { + private static final String content = "\n" + + "\n" + + " \n" + + " name\n" + + " \n" + + " name\n" + + " \n" + + " \n" + + "\n"; + private static File file; + + @BeforeAll + public static void setup() { + file = new File("file.xml"); + try { + file.createNewFile(); + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) { + bufferedWriter.write(content); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Test + public void parser() { + XmlFileParser xmlFileParser = new XmlFileParser(file); + List> dataList = xmlFileParser.parser(); + assertThat(dataList).hasSize(1); + Map data = dataList.get(0); + assertThat(data.get("name")).isInstanceOf(String.class).isEqualTo("name"); + assertThat(data.get("job")).isInstanceOf(Map.class); + Map job = (Map)data.get("job"); + assertThat(job.get("name")).isInstanceOf(String.class).isEqualTo("name"); + } + + @AfterAll + public static void init() { + file.delete(); + } +} +``` + +```java +// XmlFileParser.java + +package subway.infrastructure; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +public class XmlFileParser extends FileParser { + private static final int UNKNOWN_NODE_LIST = 0; + private static final int HAS_ELEMENT_NODE_LIST = 1; + private static final int HAS_TEXT_NODE_LIST = 2; + + private final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + public XmlFileParser(String fileName) { + super(fileName); + } + + public XmlFileParser(File file) { + super(file); + } + + @Override + public boolean allowExtension(String extension) { + return "xml".equals(extension); + } + + @Override + public List> parser() { + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(file); + document.getDocumentElement().normalize(); + Element root = document.getDocumentElement(); + return this.find(root); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private List> find(Element root) { + List> data = new ArrayList<>(); + NodeList nodeList = root.getChildNodes(); + for (int index = 0; index < nodeList.getLength(); index++) { + Node node = nodeList.item(index); + if (node.getNodeType() == Node.ELEMENT_NODE) { + data.add(this.serialize(node.getChildNodes())); + } + } + return data; + } + + private Map serialize(NodeList parentNodeList) { + Map data = new HashMap<>(); + for (int index = 0; index < parentNodeList.getLength(); index++) { + Node child = parentNodeList.item(index); + int childType = child.getNodeType(); + String childName = child.getNodeName(); + if (childType == Node.ELEMENT_NODE) { + data.put(childName, this.getNodeData(child)); + } + } + return data; + } + + private Object getNodeData(Node node) { + NodeList nodeList = node.getChildNodes(); + int nodeListType = this.getNodeListType(nodeList); + if (nodeListType == HAS_ELEMENT_NODE_LIST) { + return this.serialize(nodeList); + } else if (nodeListType == HAS_TEXT_NODE_LIST) { + return this.getTextValue(node); + } + return null; + } + + private int getNodeListType(NodeList nodeList) { + for (int index = 0; index < nodeList.getLength(); index++) { + Node node = nodeList.item(index); + int nodeType = node.getNodeType(); + String _nodeValue = node.getNodeValue(); + if (nodeType == Node.ELEMENT_NODE) { + return HAS_ELEMENT_NODE_LIST; + } else if (nodeType == Node.TEXT_NODE && this.hasTextValue(_nodeValue)) { + return HAS_TEXT_NODE_LIST; + } + } + return UNKNOWN_NODE_LIST; + } + + private String getTextValue(Node node) { + NodeList nodeList = node.getChildNodes(); + for (int index = 0; index < nodeList.getLength(); index++) { + Node child = nodeList.item(index); + String _childValue = child.getNodeValue(); + if (child.getNodeType() == Node.TEXT_NODE && this.hasTextValue(_childValue)) { + return _childValue.trim(); + } + } + return ""; + } + + private boolean hasTextValue(String value) { + return value != null && !value.trim().isEmpty(); + } +} +``` + +Xml Parser ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file From 358bdf75fc7e6baa535ca6c813edd59455e9589a Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 14:19:22 +0900 Subject: [PATCH 40/45] =?UTF-8?q?resource:=2013.=20=EC=B4=88=EA=B8=B0=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/line.xml | 12 +++ src/main/resources/section.xml | 188 +++++++++++++++++++++++++++++++++ src/main/resources/station.xml | 24 +++++ 3 files changed, 224 insertions(+) create mode 100644 src/main/resources/line.xml create mode 100644 src/main/resources/section.xml create mode 100644 src/main/resources/station.xml diff --git a/src/main/resources/line.xml b/src/main/resources/line.xml new file mode 100644 index 000000000..d5b666d7e --- /dev/null +++ b/src/main/resources/line.xml @@ -0,0 +1,12 @@ + + + + 2ํ˜ธ์„  + + + 3ํ˜ธ์„  + + + ์‹ ๋ถ„๋‹น์„  + + \ No newline at end of file diff --git a/src/main/resources/section.xml b/src/main/resources/section.xml new file mode 100644 index 000000000..5cbce3f01 --- /dev/null +++ b/src/main/resources/section.xml @@ -0,0 +1,188 @@ + + + +
+ + 2ํ˜ธ์„  + + + ๊ต๋Œ€์—ญ + + + ๊ฐ•๋‚จ์—ญ + + 2 + +
+
+ + 2ํ˜ธ์„  + + + ๊ฐ•๋‚จ์—ญ + + + ๊ต๋Œ€์—ญ + + 2 + +
+
+ + 2ํ˜ธ์„  + + + ๊ฐ•๋‚จ์—ญ + + + ์—ญ์‚ผ์—ญ + + 2 + +
+
+ + 2ํ˜ธ์„  + + + ์—ญ์‚ผ์—ญ + + + ๊ฐ•๋‚จ์—ญ + + 2 + +
+ +
+ + 3ํ˜ธ์„  + + + ๊ต๋Œ€์—ญ + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + 3 + +
+
+ + 3ํ˜ธ์„  + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + + ๊ต๋Œ€์—ญ + + 3 + +
+
+ + 3ํ˜ธ์„  + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + + ์–‘์žฌ์—ญ + + 6 + +
+
+ + 3ํ˜ธ์„  + + + ์–‘์žฌ์—ญ + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + 6 + +
+
+ + 3ํ˜ธ์„  + + + ์–‘์žฌ์—ญ + + + ๋งค๋ด‰์—ญ + + 1 + +
+
+ + 3ํ˜ธ์„  + + + ๋งค๋ด‰์—ญ + + + ์–‘์žฌ์—ญ + + 1 + +
+ +
+ + ์‹ ๋ถ„๋‹น์„  + + + ๊ฐ•๋‚จ์—ญ + + + ์–‘์žฌ์—ญ + + 2 + +
+
+ + ์‹ ๋ถ„๋‹น์„  + + + ์–‘์žฌ์—ญ + + + ๊ฐ•๋‚จ์—ญ + + 2 + +
+
+ + ์‹ ๋ถ„๋‹น์„  + + + ์–‘์žฌ์—ญ + + + ์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ์—ญ + + 10 + +
+
+ + ์‹ ๋ถ„๋‹น์„  + + + ์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ์—ญ + + + ์–‘์žฌ์—ญ + + 10 + +
+
\ No newline at end of file diff --git a/src/main/resources/station.xml b/src/main/resources/station.xml new file mode 100644 index 000000000..d9ae4c9a1 --- /dev/null +++ b/src/main/resources/station.xml @@ -0,0 +1,24 @@ + + + + ๊ต๋Œ€์—ญ + + + ๊ฐ•๋‚จ์—ญ + + + ์—ญ์‚ผ์—ญ + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + + ์–‘์žฌ์—ญ + + + ์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ์—ญ + + + ๋งค๋ด‰์—ญ + + \ No newline at end of file From ec1be410b85f96e84c96cb0bec0095b6a7b0d486 Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 14:19:34 +0900 Subject: [PATCH 41/45] =?UTF-8?q?docs:=2013.=20=EC=B4=88=EA=B8=B0=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=95=EC=9D=98=20-=20[solving?= =?UTF-8?q?=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 243 ++++++++++++++++++++++++++++++++++++- 1 file changed, 242 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 5d18fa4f3..08426eb91 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -3541,4 +3541,245 @@ public class XmlFileParser extends FileParser { } ``` -Xml Parser ๊ธฐ๋Šฅ ๊ตฌํ˜„. \ No newline at end of file +Xml Parser ๊ธฐ๋Šฅ ๊ตฌํ˜„. + +## 13. ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ์ •์˜ + +```xml + + + + 2ํ˜ธ์„  + + + 3ํ˜ธ์„  + + + ์‹ ๋ถ„๋‹น์„  + + +``` + +Line(๋…ธ์„ ) ๋ฐ์ดํ„ฐ ์ •์˜. + +```xml + + + + ๊ต๋Œ€์—ญ + + + ๊ฐ•๋‚จ์—ญ + + + ์—ญ์‚ผ์—ญ + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + + ์–‘์žฌ์—ญ + + + ์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ์—ญ + + + ๋งค๋ด‰์—ญ + + +``` + +Station(์—ญ) ๋ฐ์ดํ„ฐ ์ •์˜. + +```xml + + + +
+ + 2ํ˜ธ์„  + + + ๊ต๋Œ€์—ญ + + + ๊ฐ•๋‚จ์—ญ + + 2 + +
+
+ + 2ํ˜ธ์„  + + + ๊ฐ•๋‚จ์—ญ + + + ๊ต๋Œ€์—ญ + + 2 + +
+
+ + 2ํ˜ธ์„  + + + ๊ฐ•๋‚จ์—ญ + + + ์—ญ์‚ผ์—ญ + + 2 + +
+
+ + 2ํ˜ธ์„  + + + ์—ญ์‚ผ์—ญ + + + ๊ฐ•๋‚จ์—ญ + + 2 + +
+ +
+ + 3ํ˜ธ์„  + + + ๊ต๋Œ€์—ญ + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + 3 + +
+
+ + 3ํ˜ธ์„  + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + + ๊ต๋Œ€์—ญ + + 3 + +
+
+ + 3ํ˜ธ์„  + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + + ์–‘์žฌ์—ญ + + 6 + +
+
+ + 3ํ˜ธ์„  + + + ์–‘์žฌ์—ญ + + + ๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„์—ญ + + 6 + +
+
+ + 3ํ˜ธ์„  + + + ์–‘์žฌ์—ญ + + + ๋งค๋ด‰์—ญ + + 1 + +
+
+ + 3ํ˜ธ์„  + + + ๋งค๋ด‰์—ญ + + + ์–‘์žฌ์—ญ + + 1 + +
+ +
+ + ์‹ ๋ถ„๋‹น์„  + + + ๊ฐ•๋‚จ์—ญ + + + ์–‘์žฌ์—ญ + + 2 + +
+
+ + ์‹ ๋ถ„๋‹น์„  + + + ์–‘์žฌ์—ญ + + + ๊ฐ•๋‚จ์—ญ + + 2 + +
+
+ + ์‹ ๋ถ„๋‹น์„  + + + ์–‘์žฌ์—ญ + + + ์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ์—ญ + + 10 + +
+
+ + ์‹ ๋ถ„๋‹น์„  + + + ์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ์—ญ + + + ์–‘์žฌ์—ญ + + 10 + +
+
+``` + +Section(๊ตฌ๊ฐ„) ๋ฐ์ดํ„ฐ ์ •์˜. \ No newline at end of file From 6097a25c3616077540bbc5d772f65bcb13819caf Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 14:21:41 +0900 Subject: [PATCH 42/45] =?UTF-8?q?feat:=2014.=20=EC=9D=B8=ED=8A=B8=EB=A1=9C?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/IntroViewController.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/main/java/subway/presentation/IntroViewController.java diff --git a/src/main/java/subway/presentation/IntroViewController.java b/src/main/java/subway/presentation/IntroViewController.java new file mode 100644 index 000000000..31b2ed232 --- /dev/null +++ b/src/main/java/subway/presentation/IntroViewController.java @@ -0,0 +1,60 @@ +package subway.presentation; + +import java.util.List; +import java.util.Map; + +import subway.infrastructure.FileParser; +import subway.infrastructure.XmlFileParser; + +public class IntroViewController implements ViewController { + private final MainViewController mainViewController = new MainViewController(); + private final LineController lineController = new LineController(); + private final StationController stationController = new StationController(); + private final SectionController sectionController = new SectionController(); + + @Override + public void execute() { + this.setup(); + mainViewController.execute(); + } + + private void setup() { + this.loadLineData(); + this.loadStationData(); + this.loadSectionData(); + } + + private void loadLineData() { + FileParser fileParser = new XmlFileParser("line.xml"); + List> dataList = fileParser.parser(); + for (Map data : dataList) { + String lineName = data.get("name").toString(); + this.lineController.addLine(lineName); + } + } + + private void loadStationData() { + FileParser fileParser = new XmlFileParser("station.xml"); + List> dataList = fileParser.parser(); + for (Map data : dataList) { + String stationName = data.get("name").toString(); + this.stationController.addStation(stationName); + } + } + + private void loadSectionData() { + FileParser fileParser = new XmlFileParser("section.xml"); + List> dataList = fileParser.parser(); + for (Map data : dataList) { + Map line = (Map)data.get("line"); + String lineName = line.get("name").toString(); + Map source = (Map)data.get("source"); + String sourceName = source.get("name").toString(); + Map sink = (Map)data.get("sink"); + String sinkName = sink.get("name").toString(); + String distance = data.get("distance").toString(); + String time = data.get("time").toString(); + this.sectionController.addSection(lineName, sourceName, sinkName, distance, time); + } + } +} From 43db714676efdf8db9c64e7655519fa73dcf606a Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 14:21:54 +0900 Subject: [PATCH 43/45] =?UTF-8?q?docs:=2014.=20=EC=9D=B8=ED=8A=B8=EB=A1=9C?= =?UTF-8?q?=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84=20-=20[solving=5Fpro?= =?UTF-8?q?cess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 71 +++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 08426eb91..0b24237a3 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -3782,4 +3782,73 @@ Station(์—ญ) ๋ฐ์ดํ„ฐ ์ •์˜. ``` -Section(๊ตฌ๊ฐ„) ๋ฐ์ดํ„ฐ ์ •์˜. \ No newline at end of file +Section(๊ตฌ๊ฐ„) ๋ฐ์ดํ„ฐ ์ •์˜. + +## 14. ์ธํŠธ๋กœ ํ™”๋ฉด ๊ตฌํ˜„ + +```java +// IntroViewController.java + +package subway.presentation; + +import java.util.List; +import java.util.Map; + +import subway.infrastructure.FileParser; +import subway.infrastructure.XmlFileParser; + +public class IntroViewController implements ViewController { + private final MainViewController mainViewController = new MainViewController(); + private final LineController lineController = new LineController(); + private final StationController stationController = new StationController(); + private final SectionController sectionController = new SectionController(); + + @Override + public void execute() { + this.setup(); + mainViewController.execute(); + } + + private void setup() { + this.loadLineData(); + this.loadStationData(); + this.loadSectionData(); + } + + private void loadLineData() { + FileParser fileParser = new XmlFileParser("line.xml"); + List> dataList = fileParser.parser(); + for (Map data : dataList) { + String lineName = data.get("name").toString(); + this.lineController.addLine(lineName); + } + } + + private void loadStationData() { + FileParser fileParser = new XmlFileParser("station.xml"); + List> dataList = fileParser.parser(); + for (Map data : dataList) { + String stationName = data.get("name").toString(); + this.stationController.addStation(stationName); + } + } + + private void loadSectionData() { + FileParser fileParser = new XmlFileParser("section.xml"); + List> dataList = fileParser.parser(); + for (Map data : dataList) { + Map line = (Map)data.get("line"); + String lineName = line.get("name").toString(); + Map source = (Map)data.get("source"); + String sourceName = source.get("name").toString(); + Map sink = (Map)data.get("sink"); + String sinkName = sink.get("name").toString(); + String distance = data.get("distance").toString(); + String time = data.get("time").toString(); + this.sectionController.addSection(lineName, sourceName, sinkName, distance, time); + } + } +} +``` + +์ธํŠธ๋กœ ํ™”๋ฉด ์ œ์–ด ๊ตฌํ˜„. \ No newline at end of file From 4b28d4dedcf0745b38590e923bd0d7776862a1ab Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 14:37:03 +0900 Subject: [PATCH 44/45] =?UTF-8?q?feat:=2015.=20=EC=95=A0=ED=94=8C=EB=A6=AC?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=85=98=20=EC=8B=A4=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/subway/Application.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/subway/Application.java b/src/main/java/subway/Application.java index 0bcf786cc..84be1382c 100644 --- a/src/main/java/subway/Application.java +++ b/src/main/java/subway/Application.java @@ -1,10 +1,10 @@ package subway; -import java.util.Scanner; +import subway.presentation.IntroViewController; public class Application { public static void main(String[] args) { - final Scanner scanner = new Scanner(System.in); - // TODO: ํ”„๋กœ๊ทธ๋žจ ๊ตฌํ˜„ + IntroViewController introViewController = new IntroViewController(); + introViewController.execute(); } -} +} \ No newline at end of file From d0472a83188cc4e35550590f99ae65fd7349b3ee Mon Sep 17 00:00:00 2001 From: jaehyeonjung0613 Date: Thu, 13 Feb 2025 14:37:12 +0900 Subject: [PATCH 45/45] =?UTF-8?q?docs:=2015.=20=EC=95=A0=ED=94=8C=EB=A6=AC?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=85=98=20=EC=8B=A4=ED=96=89=20-=20[solving?= =?UTF-8?q?=5Fprocess.md]=20=ED=92=80=EC=9D=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/solving_process.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/solving_process.md b/.github/solving_process.md index 0b24237a3..7d6aa8807 100644 --- a/.github/solving_process.md +++ b/.github/solving_process.md @@ -3851,4 +3851,23 @@ public class IntroViewController implements ViewController { } ``` -์ธํŠธ๋กœ ํ™”๋ฉด ์ œ์–ด ๊ตฌํ˜„. \ No newline at end of file +์ธํŠธ๋กœ ํ™”๋ฉด ์ œ์–ด ๊ตฌํ˜„. + +## 15. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌํ˜„ + +```java +// Application.java + +package subway; + +import subway.presentation.IntroViewController; + +public class Application { + public static void main(String[] args) { + IntroViewController introViewController = new IntroViewController(); + introViewController.execute(); + } +} +``` + +์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ ์ธํŠธ๋กœ ํ™”๋ฉด ํ˜ธ์ถœ ๊ตฌํ˜„. \ No newline at end of file