-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BE] 가까운 지하철 역을 2개 보여준다. #575
base: dev-be
Are you sure you want to change the base?
Changes from all commits
2746434
1e66dcd
616f925
f587db4
b71bcd0
9ceab17
34b5532
fc33c05
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,48 @@ | ||
package com.bang_ggood.station.dto; | ||
|
||
import com.bang_ggood.global.exception.BangggoodException; | ||
import com.bang_ggood.global.exception.ExceptionCode; | ||
import com.bang_ggood.station.domain.SubwayStation; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public record SubwayStationResponse(String stationName, String stationLine, Integer walkingTime) { | ||
public class SubwayStationResponse { | ||
|
||
private final String stationName; | ||
private final List<String> stationLine; | ||
private Integer walkingTime; | ||
|
||
public SubwayStationResponse(String stationName, List<String> stationLine, Integer walkingTime) { | ||
this.stationName = stationName; | ||
this.stationLine = stationLine; | ||
this.walkingTime = walkingTime; | ||
} | ||
|
||
public static SubwayStationResponse of(SubwayStation station, Integer walkingTime) { | ||
return new SubwayStationResponse(station.getName(), station.getLine(), walkingTime); | ||
List<String> stationLine = new ArrayList<>(); | ||
stationLine.add(station.getLine()); | ||
return new SubwayStationResponse(station.getName(), stationLine, walkingTime); | ||
} | ||
|
||
public SubwayStationResponse merge(SubwayStationResponse response) { | ||
if (!stationName.equals(response.stationName)) { | ||
throw new BangggoodException(ExceptionCode.STATION_NAME_NOT_SAME); | ||
} | ||
|
||
stationLine.addAll(response.stationLine); | ||
walkingTime = Math.min(walkingTime, response.walkingTime); | ||
return this; | ||
} | ||
|
||
public String getStationName() { | ||
return stationName; | ||
} | ||
|
||
public List<String> getStationLine() { | ||
return stationLine; | ||
} | ||
|
||
public Integer getWalkingTime() { | ||
return walkingTime; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,24 +8,36 @@ | |
import org.springframework.stereotype.Service; | ||
import java.util.Comparator; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.stream.Collectors; | ||
|
||
@Service | ||
public class SubwayStationService { | ||
|
||
private static final int METER_PER_DEGREE = 111_320; | ||
private static final double AVERAGE_WALKING_SPEED = 1.3 * 60; // meter per minute | ||
// meter per second * minute unit * decreasing speed on open street | ||
private static final double AVERAGE_WALKING_SPEED = 1.3 * 60 * 0.4; | ||
private static final int MAX_NESTING_STATION_NUMBER = 4; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 중첩된 지하철역 수가 4인 이유가 있나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 대한민국 내 환승역 최대 중첩수가 4 입니다! |
||
private static final int REQUESTED_STATION_NUMBER = 2; | ||
private static final List<SubwayStation> SUBWAY_STATIONS = SubwayReader.readSubwayStationData(); | ||
|
||
public SubwayStationResponse readNearestStation(double latitude, double longitude) { | ||
return SUBWAY_STATIONS.stream() | ||
public List<SubwayStationResponse> readNearestStation(double latitude, double longitude) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 스트림이 길어서 가독성이 좀 떨어진다고 생각하는데, 인지 단위로 한번씩 끊는 것은 어떤가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 반영했습니다! |
||
Map<String, Optional<SubwayStationResponse>> responseMap = SUBWAY_STATIONS.stream() | ||
.map(station -> { | ||
double dx = (station.getLatitude() - latitude) * METER_PER_DEGREE; | ||
double dy = | ||
(station.getLongitude() - longitude) * METER_PER_DEGREE * Math.cos(station.getLatitude()); | ||
double distance = Math.sqrt(dx * dx + dy * dy); | ||
double distance = station.calculateDistance(latitude, longitude); | ||
return SubwayStationResponse.of(station, (int) Math.round(distance / AVERAGE_WALKING_SPEED)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 거리 계산 로직을 메서드 분리하면 좋을 것 같아요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 반영했습니다!
Comment on lines
+27
to
28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SubwayStation 클래스에 walkingTime 계산을 요청할 수도 있지 않을까요? |
||
}) | ||
.min(Comparator.comparing(SubwayStationResponse::walkingTime)) | ||
.orElseThrow(() -> new BangggoodException(ExceptionCode.STATION_NOT_FOUND)); | ||
.sorted(Comparator.comparing(SubwayStationResponse::getWalkingTime)) | ||
.limit(MAX_NESTING_STATION_NUMBER * REQUESTED_STATION_NUMBER) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분은 어떤 의미의 코드인가요?? |
||
.collect(Collectors.groupingBy( | ||
SubwayStationResponse::getStationName, | ||
Collectors.reducing(SubwayStationResponse::merge) | ||
)); | ||
Comment on lines
+32
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분만 조금 더 개선하면 이해하기 쉬울 것 같아요! |
||
|
||
return responseMap.values().stream() | ||
.map(optional -> optional.orElseThrow(() -> new BangggoodException(ExceptionCode.STATION_NOT_FOUND))) | ||
.sorted(Comparator.comparing(SubwayStationResponse::getWalkingTime)) | ||
.limit(REQUESTED_STATION_NUMBER) | ||
.toList(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,66 @@ | ||
package com.bang_ggood.station; | ||
|
||
import com.bang_ggood.IntegrationTestSupport; | ||
import com.bang_ggood.station.dto.SubwayStationResponse; | ||
import com.bang_ggood.station.service.SubwayStationService; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import java.util.List; | ||
import java.util.stream.Stream; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertAll; | ||
|
||
public class SubwayStationServiceTest extends IntegrationTestSupport { | ||
|
||
@Autowired | ||
SubwayStationService subwayStationService; | ||
|
||
@DisplayName("가까운 지하철 2개 조회 성공") | ||
@ParameterizedTest | ||
@MethodSource("provideStationData") | ||
void readNearestStation(double latitude, double longitude, Station nearestStation, Station nextNearestStation) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트 코드를 맨 위로 올리는 것은 어떤가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 반영했습니다! |
||
// given & when | ||
List<SubwayStationResponse> responses = subwayStationService.readNearestStation(latitude, longitude); | ||
assertThat(responses).hasSize(2); | ||
SubwayStationResponse nearest = responses.get(0); | ||
SubwayStationResponse nextNearest = responses.get(1); | ||
|
||
// then | ||
assertAll(() -> { | ||
assertThat(nearest.getStationName()).isEqualTo(nearestStation.name); | ||
assertThat(nearest.getStationLine()).containsAll(nearestStation.lines); | ||
assertThat(nextNearest.getStationName()).isEqualTo(nextNearestStation.name); | ||
assertThat(nextNearest.getStationLine()).containsAll(nextNearestStation.lines); | ||
} | ||
); | ||
} | ||
|
||
// check data in "https://apis.map.kakao.com/web/sample/addMapClickEventWithMarker/" | ||
private static Stream<Arguments> provideStationData() { | ||
return Stream.of( | ||
Arguments.of(37.50495731889611, 126.7550884277559, "상동"), | ||
Arguments.of(37.48352733443973, 126.80085909322227, "소사"), | ||
Arguments.of(37.47909015564278, 126.9517354974442, "서울대입구(관악구청)"), | ||
Arguments.of(37.516248619935034, 127.10303565244502, "잠실(송파구청)") | ||
Arguments.of(37.517406150696104, 127.10333134512422, | ||
new Station("잠실(송파구청)", List.of("2호선", "8호선")), | ||
new Station("잠실나루", List.of("2호선"))), | ||
Arguments.of(37.50808977595056, 127.04649615866747, | ||
new Station("선정릉", List.of("9호선", "분당선")), | ||
new Station("선릉", List.of("2호선", "분당선"))), | ||
Arguments.of(37.538999998345446, 126.97201837726666, | ||
new Station("남영", List.of("1호선")), | ||
new Station("삼각지", List.of("4호선", "6호선"))) | ||
); | ||
} | ||
|
||
@DisplayName("가까운 지하철 조회 성공") | ||
@ParameterizedTest | ||
@MethodSource("provideStationData") | ||
void readNearestStation(double latitude, double longitude, String nearestStationName) { | ||
// given & when | ||
String stationName = subwayStationService.readNearestStation(latitude, longitude).stationName(); | ||
private static class Station { | ||
String name; | ||
List<String> lines; | ||
|
||
// then | ||
assertThat(stationName).isEqualTo(nearestStationName); | ||
public Station(String name, List<String> lines) { | ||
this.name = name; | ||
this.lines = lines; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
어차피 1개만 받는 것 같은데 왜 List를 선택하셨나요??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge() 메서드를 통해 다른 Response와 합치기 위함입니다.