-
Notifications
You must be signed in to change notification settings - Fork 272
step3 Section과 Sections 구현 및 테스트 완료 #826
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
base: nocomet
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,116 @@ | ||||||
| package nextstep.subway.domain; | ||||||
|
|
||||||
| import javax.persistence.*; | ||||||
|
|
||||||
| @Entity | ||||||
| public class Section extends BaseEntity { | ||||||
| @Id | ||||||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||
| private Long id; | ||||||
|
|
||||||
| @ManyToOne(fetch = FetchType.LAZY) | ||||||
| @JoinColumn(name = "up_station_id", foreignKey = @ForeignKey(name = "fk_section_to_up_station")) | ||||||
| private Station upStation; | ||||||
|
|
||||||
| @ManyToOne(fetch = FetchType.LAZY) | ||||||
| @JoinColumn(name = "down_station_id", foreignKey = @ForeignKey(name = "fk_section_to_down_station")) | ||||||
| private Station downStation; | ||||||
|
|
||||||
| @Column(name = "distance") | ||||||
|
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.
Suggested change
변수명과 동일하다면 name을 따로 지정하지 않아도 됩니다 ㅎㅎ |
||||||
| private int distance; | ||||||
|
|
||||||
| @ManyToOne(fetch = FetchType.LAZY) | ||||||
| @JoinColumn(name = "line_id", nullable = false) | ||||||
| private Line line; | ||||||
|
|
||||||
| public Section() { | ||||||
| } | ||||||
|
|
||||||
| public Section(Station upStation, Station downStation, int distance, Line line) { | ||||||
| this.upStation = upStation; | ||||||
| this.downStation = downStation; | ||||||
| this.distance = distance; | ||||||
| this.line = line; | ||||||
| } | ||||||
|
|
||||||
| public Station getUpStation() { | ||||||
| return upStation; | ||||||
| } | ||||||
|
|
||||||
| public Station getDownStation() { | ||||||
| return downStation; | ||||||
| } | ||||||
|
|
||||||
| public void arrangeFirstSection(Section newSection) { | ||||||
| this.downStation = newSection.upStation; | ||||||
| } | ||||||
|
|
||||||
| public void arrangeEndSection(Section newSection) { | ||||||
| this.upStation = newSection.getDownStation(); | ||||||
| } | ||||||
|
|
||||||
| public void arrangeInterSection(Section newSection) { | ||||||
| this.upStation = newSection.downStation; | ||||||
| this.distance -= newSection.distance; | ||||||
| } | ||||||
|
|
||||||
| public boolean canAddFirstSection(Section newSection) { | ||||||
| if (isNotValidNewSection(newSection)) { | ||||||
|
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.
Suggested change
두 방식은 어떠한 차이가 있을까요? |
||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| if (!isFirstSection()) { | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| return newSection.downStation.getId().equals(this.downStation.getId()); | ||||||
| } | ||||||
|
|
||||||
| public boolean canAddEndSection(Section newSection) { | ||||||
| if (isNotValidNewSection(newSection)) { | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| if (!isEndSection()) { | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| return newSection.upStation.getId().equals(this.upStation.getId()); | ||||||
| } | ||||||
|
|
||||||
| public boolean canAddInterSection(Section section) { | ||||||
| if (!isInterSection()) { | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| // upStation이 같아야 inter section의 후보가 될 수 있다. | ||||||
| return this.upStation.getId().equals(section.upStation.getId()); | ||||||
| } | ||||||
|
|
||||||
| private boolean isFirstSection() { | ||||||
| return this.upStation == null && this.downStation != null; | ||||||
| } | ||||||
|
|
||||||
| private boolean isEndSection() { | ||||||
| return this.upStation != null && this.downStation == null; | ||||||
| } | ||||||
|
|
||||||
| private boolean isInterSection() { | ||||||
| return !isFirstSection() && !isEndSection(); | ||||||
| } | ||||||
|
|
||||||
| public boolean isSameSection(Section newSection) { | ||||||
| return isInterSection() | ||||||
|
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.
|
||||||
| && this.upStation.getId().equals(newSection.getUpStation().getId()) | ||||||
| && this.downStation.getId().equals(newSection.getDownStation().getId()); | ||||||
| } | ||||||
|
|
||||||
| private boolean isNotValidNewSection(Section newSection) { | ||||||
| // newSection의 up, down station은 모두 null이 아니어야 한다. | ||||||
| return newSection.getUpStation() == null || newSection.getDownStation() == null; | ||||||
| } | ||||||
|
|
||||||
| public boolean isShorterThen(Section newSection) { | ||||||
| return this.distance < newSection.distance; | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,128 @@ | ||||||
| package nextstep.subway.domain; | ||||||
|
|
||||||
| import nextstep.subway.error.exception.SectionInvalidException; | ||||||
|
|
||||||
| import javax.persistence.CascadeType; | ||||||
| import javax.persistence.Embeddable; | ||||||
| import javax.persistence.OneToMany; | ||||||
| import java.util.ArrayList; | ||||||
| import java.util.List; | ||||||
| import java.util.Optional; | ||||||
| import java.util.stream.Collectors; | ||||||
|
|
||||||
| @Embeddable | ||||||
| public class Sections { | ||||||
| @OneToMany(mappedBy = "line", cascade = CascadeType.ALL, orphanRemoval = true) | ||||||
| private List<Section> sections; | ||||||
|
|
||||||
| protected Sections() { | ||||||
| } | ||||||
|
|
||||||
| public Sections(Line line, Section section) { | ||||||
| this.sections = new ArrayList<>(); | ||||||
| sections.add(new Section(null, section.getUpStation(), 0, line)); | ||||||
| sections.add(new Section(section.getDownStation(), null, 0, line)); | ||||||
| sections.add(section); | ||||||
| } | ||||||
|
|
||||||
| public void add(Section newSection) { | ||||||
| checkAlreadyExist(newSection); | ||||||
| if (addIfFirstSection(newSection)) { | ||||||
| return ; | ||||||
|
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.
Suggested change
공백을 추가해주신 이유가 있을까요? |
||||||
| } | ||||||
| if (addIfEndSection(newSection)) { | ||||||
| return ; | ||||||
| } | ||||||
| addIfIntersection(newSection); | ||||||
| } | ||||||
|
|
||||||
| private boolean addIfFirstSection(Section newSection) { | ||||||
|
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. 해당 메서드는 변경과 조회의 역할 두 가지 모두 하고 있는데요. |
||||||
| Section firstSection = getFirstSection() | ||||||
| .orElseThrow(() -> new SectionInvalidException("first section이 없는 라인입니다.")); | ||||||
| if (firstSection.canAddFirstSection(newSection)) { | ||||||
| firstSection.arrangeFirstSection(newSection); | ||||||
| sections.add(newSection); | ||||||
| return true; | ||||||
| } | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| private boolean addIfEndSection(Section newSection) { | ||||||
| List<Section> sectionsInOrder = getSectionsInOrder(); | ||||||
| Section endSection = sectionsInOrder.get(sectionsInOrder.size() - 1); | ||||||
| if (endSection.canAddEndSection(newSection)) { | ||||||
| endSection.arrangeEndSection(newSection); | ||||||
| sections.add(newSection); | ||||||
| return true; | ||||||
| } | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| private void addIfIntersection(Section newSection) { | ||||||
| Section upperSection = getTargetUpperSection(newSection).orElseThrow(() | ||||||
| -> new SectionInvalidException("상행역과 하행역 둘 다 하나도 포함되어 있지 않습니다.")); | ||||||
| if (upperSection.isShorterThen(newSection)) { | ||||||
| throw new SectionInvalidException("distance가 기존 구간의 보다 큰 길이 입니다."); | ||||||
| } | ||||||
| sections.add(newSection); | ||||||
| upperSection.arrangeInterSection(newSection); | ||||||
| } | ||||||
|
|
||||||
| private Optional<Section> getTargetUpperSection(Section newSection) { | ||||||
| return sections.stream() | ||||||
| .filter(s -> s.canAddInterSection(newSection)) | ||||||
| .findFirst(); | ||||||
| } | ||||||
|
|
||||||
| public List<Station> getStationsInOrder() { | ||||||
| // section을 downStation을 기준으로 변경 | ||||||
| return getSectionsInOrder().stream() | ||||||
| .filter(s -> s.getDownStation() != null) | ||||||
| .map(Section::getDownStation) | ||||||
| .collect(Collectors.toList()); | ||||||
| } | ||||||
|
|
||||||
| public List<Section> getSectionsInOrder() { | ||||||
| // 출발지점 찾기 | ||||||
| Optional<Section> preSection = getFirstSection(); | ||||||
|
|
||||||
| // section 에 있는 station 순서대로 찾기 | ||||||
| List<Section> result = new ArrayList<>(); | ||||||
| while (preSection.isPresent()) { | ||||||
| Section section = preSection.get(); | ||||||
| result.add(section); | ||||||
| preSection = sections.stream() | ||||||
| .filter(candidate -> isNextSection(section, candidate)) | ||||||
| .findFirst(); | ||||||
| } | ||||||
| return result; | ||||||
| } | ||||||
|
|
||||||
| private Optional<Section> getFirstSection() { | ||||||
| return sections.stream() | ||||||
| .filter(s -> s.getUpStation() == null) | ||||||
| .findFirst(); | ||||||
| } | ||||||
|
|
||||||
| private boolean isNextSection(Section section, Section candidateSection) { | ||||||
| if (section.getDownStation() == null) { | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| if (candidateSection.getUpStation() == null) { | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| return candidateSection.getUpStation().getId().equals(section.getDownStation().getId()); | ||||||
| } | ||||||
|
|
||||||
| private void checkAlreadyExist(Section section) { | ||||||
| if (hasSection(section)) { | ||||||
| throw new SectionInvalidException("이미 존재하는 section 입니다."); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| private boolean hasSection(Section newSection) { | ||||||
| return sections.stream().anyMatch(s -> s.isSameSection(newSection)); | ||||||
| } | ||||||
| } | ||||||
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.
Line의 생성과 initSections를 분리해주신 이유가 있을까요?