-
Notifications
You must be signed in to change notification settings - Fork 247
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
수강신청 Step2 - 수강신청(도메인 모델) #393
base: parkje0927
Are you sure you want to change the base?
Changes from all commits
ed45989
d35aaa7
4dc982e
3a2d7ca
8f41fa5
67809a4
acb28f3
3ea9ab2
67eb363
f316f0a
884fe7d
127a5eb
a17da2c
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,6 +1,10 @@ | ||
package nextstep.courses.domain; | ||
|
||
import nextstep.sessions.domain.Session; | ||
import nextstep.sessions.domain.Sessions; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
|
||
public class Course { | ||
private Long id; | ||
|
@@ -9,6 +13,10 @@ public class Course { | |
|
||
private Long creatorId; | ||
|
||
private int cardinalNumber; | ||
|
||
private Sessions sessions; | ||
|
||
private LocalDateTime createdAt; | ||
|
||
private LocalDateTime updatedAt; | ||
|
@@ -17,7 +25,18 @@ public Course() { | |
} | ||
|
||
public Course(String title, Long creatorId) { | ||
this(0L, title, creatorId, LocalDateTime.now(), null); | ||
this(0L, title, creatorId, 1, null, LocalDateTime.now(), null); | ||
} | ||
|
||
public Course(Long id, String title, Long creatorId, int cardinalNumber, Sessions sessions, | ||
LocalDateTime createdAt, LocalDateTime updatedAt) { | ||
this.id = id; | ||
this.title = title; | ||
this.creatorId = creatorId; | ||
this.cardinalNumber = cardinalNumber; | ||
this.sessions = sessions; | ||
this.createdAt = createdAt; | ||
this.updatedAt = updatedAt; | ||
} | ||
|
||
public Course(Long id, String title, Long creatorId, LocalDateTime createdAt, LocalDateTime updatedAt) { | ||
|
@@ -40,12 +59,18 @@ public LocalDateTime getCreatedAt() { | |
return createdAt; | ||
} | ||
|
||
public List<Session> getPossibleSessionList() { | ||
return this.sessions.getPossibleSessionList(); | ||
} | ||
|
||
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. 새로운 Session을 추가하는 addSession(Session session)과 같은 메서드도 추가하는 것은 어떨까? |
||
@Override | ||
public String toString() { | ||
return "Course{" + | ||
"id=" + id + | ||
", title='" + title + '\'' + | ||
", creatorId=" + creatorId + | ||
", cardinalNumber=" + cardinalNumber + | ||
", sessions=" + sessions + | ||
", createdAt=" + createdAt + | ||
", updatedAt=" + updatedAt + | ||
'}'; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package nextstep.courses.service; | ||
|
||
import nextstep.courses.domain.Course; | ||
import nextstep.courses.infrastructure.JdbcCourseRepository; | ||
|
||
public class CourseService { | ||
|
||
private final JdbcCourseRepository jdbcCourseRepository; | ||
|
||
public CourseService(JdbcCourseRepository jdbcCourseRepository) { | ||
this.jdbcCourseRepository = jdbcCourseRepository; | ||
} | ||
|
||
public Course findByCardinalNumber(int cardinalNumber) { | ||
return jdbcCourseRepository.findByCardinalNumber(cardinalNumber); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
### step2 수강 신청(도메인 모델) | ||
|
||
- [x] 과정(Course)은 기수 단위로 운영하고, 여러 개의 강의(Session)를 가진다. | ||
- [X] 강의는 시작일과 종료일을 가진다. | ||
- [X] 강의는 강의 커버 이미지 정보를 가진다. | ||
- [X] 이미지 크기는 1MB 이하 | ||
- [X] 이미지 타입은 gif, jpg, jpeg, png, svg 만 허용 | ||
- [X] 이미지의 width 는 300 픽셀, height 은 200 픽셀 이상이어야 하고 비율은 3:2 | ||
- [X] 강의는 무료 강의와 유료 강의로 나뉜다. | ||
- [X] 무료 강의는 최대 수강 인원 제한 X | ||
- [X] 유료 강의는 강의 최대 수강 인원 초과 X | ||
- [X] 유료 강의는 수강생이 결제한 금액과 수강료가 일치할 때 수강 신청 가능 | ||
- [X] 강의 상태는 준비중, 모집중, 종료 3가지 상태 | ||
- [X] 강의 수강 신청은 강의 상태가 모집중일 때만 가능 | ||
- [X] 유료 강의의 경우 결제는 이미 완료한 것으로 가정, 이후 과정을 구현 | ||
- [X] 결제를 완료한 결제 정보는 payments 모듈을 통해 관리되며, 결제 정보는 Payment 객체에 담겨 반환 | ||
- [X] 도메인 모델 TDD 로 구현 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package nextstep.enrolment; | ||
|
||
import nextstep.courses.infrastructure.JdbcCourseRepository; | ||
import nextstep.courses.service.CourseService; | ||
import nextstep.enrolment.controller.EnrolmentController; | ||
import nextstep.enrolment.facade.EnrolmentFacade; | ||
import nextstep.payments.service.PaymentService; | ||
import nextstep.sessions.dto.SessionResponse; | ||
import nextstep.sessions.dto.SessionsResponse; | ||
import nextstep.sessions.infrastructure.JdbcSessionRepository; | ||
import nextstep.sessions.service.SessionService; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
|
||
public class EnrolmentMain { | ||
|
||
public static void main(String[] args) { | ||
EnrolmentFacade enrolmentFacade = new EnrolmentFacade( | ||
new CourseService(new JdbcCourseRepository(new JdbcTemplate())), | ||
new SessionService(new JdbcSessionRepository(new JdbcTemplate())), | ||
new PaymentService() | ||
); | ||
EnrolmentController enrolmentController = new EnrolmentController(enrolmentFacade); | ||
|
||
//수강 신청 전에 현재 오픈된 기수의 과정을 볼 수 있는 로직 | ||
SessionsResponse sessionsResponse = enrolmentController.findPossibleSessionList(17); | ||
//특정 강의에 대한 세부 내용을 확인하는 로직 | ||
SessionResponse sessionInfo = enrolmentController.findSessionInfo(1L); | ||
//수강 신청 | ||
Long nsUserId = 1L; | ||
enrolmentController.enrollCourse(sessionInfo.id(), nsUserId); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package nextstep.enrolment.controller; | ||
|
||
import nextstep.courses.domain.Course; | ||
import nextstep.enrolment.facade.EnrolmentFacade; | ||
import nextstep.payments.domain.Payment; | ||
import nextstep.sessions.domain.Session; | ||
import nextstep.sessions.dto.SessionResponse; | ||
import nextstep.sessions.dto.SessionsResponse; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.stream.Collectors; | ||
|
||
public class EnrolmentController { | ||
|
||
private final EnrolmentFacade enrolmentFacade; | ||
|
||
public EnrolmentController(EnrolmentFacade enrolmentFacade) { | ||
this.enrolmentFacade = enrolmentFacade; | ||
} | ||
|
||
public SessionsResponse findPossibleSessionList(int cardinalNumber) { | ||
Course course = enrolmentFacade.findCourseByCardinalNumber(cardinalNumber); | ||
return new SessionsResponse(course.getPossibleSessionList().stream() | ||
.map(SessionResponse::of) | ||
.collect(Collectors.toList())); | ||
} | ||
|
||
public SessionResponse findSessionInfo(long sessionId) { | ||
Session session = enrolmentFacade.findSessionById(sessionId); | ||
return SessionResponse.of(session); | ||
} | ||
|
||
public void enrollCourse(Long sessionId, Long nsUserId) { | ||
Session session = enrolmentFacade.findSessionById(sessionId); | ||
if (!session.isRecruitingStatus()) { | ||
throw new IllegalArgumentException("수강 신청이 불가능한 강의 입니다."); | ||
} | ||
|
||
List<Payment> payments = enrolmentFacade.findPaymentsBySessionId(sessionId); | ||
Payment payment = payments.stream().filter(p -> Objects.equals(p.nsUserId(), nsUserId)) | ||
.findAny() | ||
.orElse(null); | ||
|
||
if (Objects.nonNull(payment) && !session.isPossibleToRegister(payment.amount(), payments.size())) { | ||
//수강 신청 불가 | ||
throw new IllegalArgumentException("수강 신청이 불가능합니다."); | ||
} | ||
|
||
//수강 신청 | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package nextstep.enrolment.facade; | ||
|
||
import nextstep.courses.domain.Course; | ||
import nextstep.courses.service.CourseService; | ||
import nextstep.payments.domain.Payment; | ||
import nextstep.payments.service.PaymentService; | ||
import nextstep.sessions.domain.Session; | ||
import nextstep.sessions.service.SessionService; | ||
|
||
import java.util.List; | ||
|
||
public class EnrolmentFacade { | ||
|
||
private final CourseService courseService; | ||
private final SessionService sessionService; | ||
private final PaymentService paymentService; | ||
|
||
public EnrolmentFacade(CourseService courseService, | ||
SessionService sessionService, | ||
PaymentService paymentService) { | ||
this.courseService = courseService; | ||
this.sessionService = sessionService; | ||
this.paymentService = paymentService; | ||
} | ||
|
||
public Course findCourseByCardinalNumber(int cardinalNumber) { | ||
return courseService.findByCardinalNumber(cardinalNumber); | ||
} | ||
|
||
public Session findSessionById(Long sessionId) { | ||
return sessionService.findById(sessionId); | ||
} | ||
|
||
public List<Payment> findPaymentsBySessionId(Long sessionId) { | ||
return paymentService.findBySessionId(sessionId); | ||
} | ||
|
||
public Payment findPaymentBySessionIdAndNsUserId(Long sessionId, Long nsUserId) { | ||
return paymentService.findBySessionIdAndNsUserId(sessionId, nsUserId); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package nextstep.images.domain; | ||
|
||
import java.util.EnumSet; | ||
import java.util.Objects; | ||
|
||
public class Image { | ||
|
||
private Long id; | ||
|
||
private ImageType imageType; | ||
|
||
private int size; | ||
|
||
private int width; | ||
|
||
private int height; | ||
Comment on lines
+12
to
+16
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. 원시값 포장, 관련 있는 필드 값을 객체로 분리하는 차원에서 ImageFileSize, ImageSize와 같은 객체를 분리하는 것은 의미가 있을까? |
||
|
||
public Image(Long id, ImageType imageType, int size, int width, int height) { | ||
checkImageSize(size); | ||
checkImageType(imageType); | ||
checkImageWidthAndHeight(width, height); | ||
this.id = id; | ||
this.imageType = imageType; | ||
this.size = size; | ||
this.width = width; | ||
this.height = height; | ||
} | ||
|
||
private void checkImageSize(int size) { | ||
if (size == 0) { | ||
throw new IllegalArgumentException("강의는 강의 커버 이미지 정보가 필요합니다."); | ||
} | ||
|
||
if (size > 1024 * 1024) { // 1MB | ||
throw new IllegalArgumentException("이미지 크기는 1MB 이하여야 합니다."); | ||
} | ||
} | ||
|
||
private void checkImageType(ImageType imageType) { | ||
if (Objects.isNull(imageType) || !EnumSet.allOf(ImageType.class).contains(imageType)) { | ||
throw new IllegalArgumentException("이미지 타입은 gif, jpg, jpeg, png, svg 만 가능합니다."); | ||
} | ||
} | ||
|
||
private void checkImageWidthAndHeight(int width, int height) { | ||
if (width == 0 || height == 0) { | ||
throw new IllegalArgumentException("강의는 강의 커버 이미지 정보가 필요합니다."); | ||
} | ||
|
||
if (width < 300 || height < 200) { | ||
throw new IllegalArgumentException("이미지 가로는 300 픽셀, 세로는 200 픽셀 이상이어야 합니다."); | ||
} | ||
|
||
if (2 * width != 3 * height) { | ||
throw new IllegalArgumentException("가로와 세로의 비율은 3:2여야 합니다"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package nextstep.images.domain; | ||
|
||
public enum ImageType { | ||
|
||
GIF, | ||
JPG, | ||
JPEG, | ||
PNG, | ||
SVG; | ||
|
||
ImageType() { | ||
|
||
} | ||
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. 이미지 파일이 유효한 파일인지에 대한 체크 로직을 이 객체에 구현하는 것은 어떨까? |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package nextstep.sessions.domain; | ||
|
||
public class FreeSessionType implements SessionType { | ||
|
||
private Long amount; | ||
private int maxCapacity; | ||
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. amount, maxCapacity 인스턴스 변수로 초기화하고 아무 곳에서도 사용하지 않고 있다. |
||
|
||
public FreeSessionType() { | ||
this.amount = 0L; | ||
this.maxCapacity = Integer.MAX_VALUE; | ||
} | ||
|
||
@Override | ||
public boolean isPossibleToRegister(Long paidAmount, int enrolledStudents) { | ||
return true; | ||
} | ||
} |
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.
주생성자를 생성자에 마지막에 구현하는 것이 관례