Skip to content
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

3단계 - 구간 추가 기능 과제 PR 요청 드립니다! #1013

Open
wants to merge 12 commits into
base: taewonh
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,42 @@
- 인수 조건을 검증하는 인수 테스트 작성
- 인수 테스트를 충족하는 기능 구현
- 인수 테스트의 결과가 다른 인수 테스트에 영향을 끼치지 않도록 격리
- 인수 테스트의 재사용성, 가독성, 빠른 테스트 파악을 위한 리팩토링
- 인수 테스트의 재사용성, 가독성, 빠른 테스트 파악을 위한 리팩토링

## Step3. 구간 추가 기능

### 기능 요구사항
- 지하철 구간 추가 도메인 기능 구현
- [X] 새 구간 등록
- [X] 역 사이에 새로운 역 등록
- [X] 기능 구현
- [X] 테스트 코드 작성
- [X] 새로운 역을 상행 종점으로 등록
- [X] 기능 구현
- [X] 테스트 코드 작성
- [X] 새로운 역을 하행 종점으로 등록
- [X] 기능 구현
- [X] 테스트 코드 작성
- [X] 새 구간 등록 불가능
- [X] 역 사이에 새로운 역을 등록하는 경우 기존 역 사이 길이보다 크거나 같으면 등록 불가
- [X] 기능 구현
- [X] 테스트 코드 작성
- [X] 상행역과 하행역이 이미 노선에 모두 등록되어 있다면 추가 불가능
- [X] 기능 구현
- [X] 테스트 코드 작성
- [X] 상행역과 하행역 둘 중 하나도 포함되어 있지 않다면 추가 불가능
- [X] 기능 구현
- [X] 테스트 코드 작성
- [X] 요구사항을 정의한 인수 조건 조출
- [X] 인수 조건을 검증하는 인수 테스트 작성
- [X] 예외 케이스에 대한 검증 포함

### 프로그래밍 요구사항
- 인수 테스트 주도 개발 프로세스에 맞춰서 기능 구현
- 요구사항 설명을 참고하여 인수 조건 정의
- 인수 조건을 검증하는 인수 테스트 작성
- 인수 테스트를 충족하는 기능 구현
- 인수 조건은 인수 테스트 메서드 상단에 주석으로 작성
- 뼈대 코드의 인수 테스트 참고
- 인수 테스트의 결과가 다른 인수 테스트에 영향을 끼치지 않도록 격리
- 인수 테스트의 재사용성과, 가독성, 그리고 빠른 테스트 의도 파악을 위해 리팩토링
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package nextstep.subway.line;

class CreateLineDto {
class CreateLineRequest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

빈 생성자가 없어 일부 테스트에서 오류가 발생합니다.
아마 실제로 실행을 하더라도 이 클래스를 사용하는 곳에선 전부 오류가 날거에요.

@RequestBody 가 어떤 방식으로 생성되는지를 공부해보시면 도움이 됩니다.


private String name;

Expand All @@ -12,7 +12,7 @@ class CreateLineDto {

private long distance;

public CreateLineDto(String name, String color, long upStationId, long downStationId, long distance) {
public CreateLineRequest(String name, String color, long upStationId, long downStationId, long distance) {
this.name = name;
this.color = color;
this.upStationId = upStationId;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/nextstep/subway/line/Line.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public String getColor() {
}

public List<Map<String, Object>> getStations() {
return sections.getStations();
return sections.getStationsResponse();
}

public void update(Line updateLine) {
Expand Down
15 changes: 11 additions & 4 deletions src/main/java/nextstep/subway/line/LineController.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package nextstep.subway.line;

import nextstep.subway.section.CreateSectionRequest;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -17,8 +18,8 @@ public LineController(LineService lineService) {
}

@PostMapping("/lines")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 클래스에서 /lines 가 공통으로 사용됩니다.
클래스 레벨의 @RequestMapping 으로 묶어주는건 어떨까요?

public ResponseEntity<LineResponse> createLine(@RequestBody CreateLineDto dto) {
LineResponse response = lineService.register(dto);
public ResponseEntity<LineResponse> createLine(@RequestBody CreateLineRequest request) {
LineResponse response = lineService.register(request);
return ResponseEntity.created(URI.create("/lines/" + response.getId())).body(response);
}

Expand All @@ -33,8 +34,8 @@ public ResponseEntity<LineResponse> showLine(@PathVariable("id") long id) {
}

@PutMapping("/lines/{id}")
public ResponseEntity<Void> updateLine(@PathVariable("id") long id, @RequestBody UpdateLineDto dto) {
lineService.update(id, dto);
public ResponseEntity<Void> updateLine(@PathVariable("id") long id, @RequestBody UpdateLineRequest request) {
lineService.update(id, request);
return ResponseEntity.ok().build();
}

Expand All @@ -43,4 +44,10 @@ public ResponseEntity<Void> deleteLine(@PathVariable("id") long id) {
lineService.delete(id);
return ResponseEntity.noContent().build();
}

@PostMapping("/lines/{lineId}/sections")
public ResponseEntity<LineResponse> createSection(@RequestBody CreateSectionRequest request, @PathVariable("lineId") long lineId) {
LineResponse response = lineService.registerSection(lineId, request);
return ResponseEntity.created(URI.create("/lines/" + response.getId())).body(response);
}
}
27 changes: 20 additions & 7 deletions src/main/java/nextstep/subway/line/LineService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import nextstep.subway.section.Distance;
import nextstep.subway.section.Section;
import nextstep.subway.section.CreateSectionRequest;
import nextstep.subway.station.Station;
import nextstep.subway.station.StationRepository;
import org.springframework.stereotype.Service;
Expand All @@ -23,20 +24,32 @@ public LineService(LineRepository lineRepository, StationRepository stationRepos
}

@Transactional
public LineResponse register(CreateLineDto dto) {
Station upStation = findStationById(dto.getUpStationId());
Station downStation = findStationById(dto.getDownStationId());
Distance distance = new Distance(dto.getDistance());
public LineResponse registerSection(long id, CreateSectionRequest request) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 메소드도 단위 테스트를 추가하는건 어떤가요?
로직이 그리 어렵진 않지만 작동 여부 자체는 테스트가 필요해보여요.

Line line = lineRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 노선입니다."));
Station upStation = findStationById(request.getUpStationId());
Station downStation = findStationById(request.getDownStationId());
Distance distance = new Distance(request.getDistance());
Section section = new Section(upStation, downStation, distance);
line.addSection(section);
return LineResponse.of(line);
}

@Transactional
public LineResponse register(CreateLineRequest request) {
Line line = request.toLine();
Station upStation = findStationById(request.getUpStationId());
Station downStation = findStationById(request.getDownStationId());
Distance distance = new Distance(request.getDistance());
Section section = new Section(upStation, downStation, distance);
Line line = dto.toLine();
line.addSection(section);
return LineResponse.of(lineRepository.save(line));
}

@Transactional
public void update(long id, UpdateLineDto dto) {
public void update(long id, UpdateLineRequest request) {
Line line = findLineById(id);
line.update(dto.toLine());
line.update(request.toLine());
}

@Transactional(readOnly = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package nextstep.subway.line;

class UpdateLineDto {
class UpdateLineRequest {
private String name;

private String color;
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/nextstep/subway/section/CreateSectionRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package nextstep.subway.section;

public class CreateSectionRequest {

private long upStationId;
private long downStationId;
private long distance;

public long getUpStationId() {
return upStationId;
}

public long getDownStationId() {
return downStationId;
}

public long getDistance() {
return distance;
}
}
30 changes: 30 additions & 0 deletions src/main/java/nextstep/subway/section/Distance.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,37 @@ public class Distance {

protected Distance() { }

public Distance(Distance distance) {
this.distance = distance.distance;
}

public Distance(Long distance) {
this.distance = distance;
}

public Distance add(Distance distance) {
this.distance += distance.distance;
return this;
}

public Distance subtract(Distance distance) {
this.distance -= distance.distance;
return this;
}

public Boolean isZero() {
return distance == 0;
}

public Boolean isNegative() {
return distance < 0;
}

public Long get() {
return distance;
}

public int compare(Distance distance) {
return Long.compare(this.distance, distance.distance);
}
}
70 changes: 70 additions & 0 deletions src/main/java/nextstep/subway/section/Section.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class Section {
@Embedded
private Distance distance;

private int sequence = 1;

protected Section() { }

public Section(Station upStation, Station downStation, Distance distance) {
Expand All @@ -46,4 +48,72 @@ public Station getUpStation() {
public Station getDownStation() {
return downStation;
}

public Distance getDistance() {
return distance;
}

public void increaseSequence() {
this.sequence += 1;
}

public void increaseSequence(int add) {
this.sequence = add + 1;
}

public int getSequence() {
return sequence;
}

public boolean isExtendDownStation(Section section) {
return this.downStation.equals(section.getUpStation());
}

public boolean isExtendUpStation(Section section) {
return this.upStation.equals(section.getDownStation());
}

public boolean isEqualUpStation(Section section) {
return this.upStation.equals(section.getUpStation());
}

public boolean isEqualDownStation(Section section) {
return this.downStation.equals(section.getDownStation());
}

public void replace(Section newSection, Distance totalSectionDistance) {
Distance excludeSectionDistance = totalSectionDistance.subtract(distance);
newSection.distance = newSection.distance.subtract(excludeSectionDistance);
newSection.upStation = upStation;
newSection.sequence = sequence;
upStation = newSection.downStation;
distance = distance.subtract(newSection.distance);
}
Comment on lines +84 to +91
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용되지 않는 메소드는 삭제해주세요.


public void syncUpStation(Section other, Distance distance) {
this.upStation = other.upStation;
this.distance = new Distance(other.distance).add(distance);
this.sequence = other.sequence;
other.upStation = this.downStation;
other.distance = other.distance.subtract(this.distance);
}

public void syncDownStation(Section other, Distance distance) {
this.downStation = other.downStation;
this.distance = new Distance(other.distance).add(distance);
this.sequence = other.sequence + 1;
other.downStation = this.upStation;
other.distance = other.distance.subtract(this.distance);
}

@Override
public String toString() {
return "Section{" +
"id=" + id +
", sequence=" + sequence +
", upStation=" + upStation.getName() +
", downStation=" + downStation.getName() +
", distance=" + distance.get() +
'}';
}
}
Loading