From b6b81219e4cff146b2660fcf72c8be4c9acbcdcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Sun, 7 Dec 2025 19:12:44 +0900 Subject: [PATCH 01/34] =?UTF-8?q?refactor=20:=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=A0=9C=EC=96=B4=EC=9E=90=20=EB=B3=80=EA=B2=BD,=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=20=EC=A4=80=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/qna/domain/Answer.java | 2 +- src/main/java/nextstep/qna/domain/Question.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/nextstep/qna/domain/Answer.java b/src/main/java/nextstep/qna/domain/Answer.java index 5590ede7f..77ace4781 100644 --- a/src/main/java/nextstep/qna/domain/Answer.java +++ b/src/main/java/nextstep/qna/domain/Answer.java @@ -60,7 +60,7 @@ private void isHaveAuthority(NsUser loginUser) throws CannotDeleteException { } } - public boolean isNotOwner(NsUser writer) { + private boolean isNotOwner(NsUser writer) { return !this.writer.equals(writer); } diff --git a/src/main/java/nextstep/qna/domain/Question.java b/src/main/java/nextstep/qna/domain/Question.java index ad3759a21..8b8d14e4e 100644 --- a/src/main/java/nextstep/qna/domain/Question.java +++ b/src/main/java/nextstep/qna/domain/Question.java @@ -4,7 +4,7 @@ import nextstep.qna.CannotDeleteException; import nextstep.users.domain.NsUser; -public class Question extends Base{ +public class Question extends Base { private Long id; private String title; From 2ba990b6383304d49da0f19990f8a2d35afa027b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Sun, 7 Dec 2025 19:13:26 +0900 Subject: [PATCH 02/34] =?UTF-8?q?doc=20:=20Question=EC=9D=98=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=EC=9D=98=20=EA=B0=9D=EC=B2=B4=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=ED=95=84=EC=9A=94=EC=84=B1=20=EA=B4=80=EB=A0=A8=20=EC=9D=98?= =?UTF-8?q?=EA=B2=AC=20=EB=A9=94=EB=AA=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 677ded833..50e02827d 100644 --- a/README.md +++ b/README.md @@ -67,4 +67,12 @@ - [x] : `Answer` 에 대한 삭제 테스트 필요하자않은가? 이유작성 - 이유 : 필요하다 Answer 을 수동적으로 바라보았기에 비즈니스 로직에 대한 테스트 코드가 생략되었다. - [ ] : `Answers` 에서 한땀한땀 삭제하는건 `Answer` 에 대한 수동적으로 바라보는 느낌아닌가? 이유 작성 - - 이유 : 맞다 또한 검증에 대해서도 모두 수행하는것은 바람직하지 않음, 검증은 `Answer` 내부에서 해야함 \ No newline at end of file + - 이유 : 맞다 또한 검증에 대해서도 모두 수행하는것은 바람직하지 않음, 검증은 `Answer` 내부에서 해야함 + +## 3차 피드백 + +- [x] : `Question` 의 `title`, `contents` 필드를 별도로 `QuestionBody` 로 분리하는 것이 의미 있을까? + - 생각컨데 분리는 의마가 없다고 본다. + - 그 이유는 : `title`, `contents` 로 분리를 하면은 값을 보관해주는 역할에 불과한 점 + - 분리한 객체만의 특별한 도메인 규칙이나 행동이 없는 점 + - 때문이다. From 1b35cca27ab89f5ed357c2c6513aae9c9748a4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Sun, 7 Dec 2025 19:54:14 +0900 Subject: [PATCH 03/34] =?UTF-8?q?fix=20:=20=EC=BB=B4=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/qna/domain/Answers.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/nextstep/qna/domain/Answers.java b/src/main/java/nextstep/qna/domain/Answers.java index 2aded442b..34643c7ef 100644 --- a/src/main/java/nextstep/qna/domain/Answers.java +++ b/src/main/java/nextstep/qna/domain/Answers.java @@ -46,11 +46,6 @@ public List addInDeleteHistory() { .collect(Collectors.toList()); } - private boolean isNotAllMatch(NsUser loginUser) { - return this.answers.stream() - .anyMatch(answer -> !answer.isNotOwner(loginUser)); - } - @Override public boolean equals(Object o) { if(o == null || getClass() != o.getClass()) { From 74bdefd028f750c5012b02bc38aa7295b4a9d749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Sun, 7 Dec 2025 20:46:25 +0900 Subject: [PATCH 04/34] =?UTF-8?q?feat=20:=20=EA=B0=95=EC=9D=98=20=EC=8B=9C?= =?UTF-8?q?=EC=9E=91=EC=9D=BC=20=EC=A2=85=EB=A3=8C=EC=9D=BC=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=20=EA=B5=AC=ED=98=84=20=EB=B0=8F?= =?UTF-8?q?=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../courses/CanNotCreateException.java | 8 ++++ .../nextstep/courses/domain/Duration.java | 40 +++++++++++++++++++ .../nextstep/courses/domain/DurationTest.java | 32 +++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 src/main/java/nextstep/courses/CanNotCreateException.java create mode 100644 src/main/java/nextstep/courses/domain/Duration.java create mode 100644 src/test/java/nextstep/courses/domain/DurationTest.java diff --git a/src/main/java/nextstep/courses/CanNotCreateException.java b/src/main/java/nextstep/courses/CanNotCreateException.java new file mode 100644 index 000000000..c5f261c3f --- /dev/null +++ b/src/main/java/nextstep/courses/CanNotCreateException.java @@ -0,0 +1,8 @@ +package nextstep.courses; + +public class CanNotCreateException extends Exception { + + public CanNotCreateException(String message) { + super(message); + } +} diff --git a/src/main/java/nextstep/courses/domain/Duration.java b/src/main/java/nextstep/courses/domain/Duration.java new file mode 100644 index 000000000..90990c8bb --- /dev/null +++ b/src/main/java/nextstep/courses/domain/Duration.java @@ -0,0 +1,40 @@ +package nextstep.courses.domain; + +import java.time.LocalDate; +import nextstep.courses.CanNotCreateException; + +public class Duration { + + private final LocalDate startDate; + private final LocalDate endDate; + + public Duration(String startDate, String endDate) { + this.startDate = LocalDate.parse(startDate); + this.endDate = LocalDate.parse(endDate); + } + + public Duration(LocalDate startDate, LocalDate endDate) throws CanNotCreateException { + validate(startDate, endDate); + this.startDate = startDate; + this.endDate = endDate; + } + + private void validate(LocalDate startDate, LocalDate endDate) throws CanNotCreateException { + if(isBeforeDateThenCurrentDate(startDate, endDate)) { + throw new CanNotCreateException("강의 날짜는 오늘에서 다음날에 존재해야 한다"); + } + if(isEndDateEarly(startDate, endDate)) { + throw new CanNotCreateException("강의 종료일이 시작일보다 앞에 있을 수 없다"); + } + + } + + private static boolean isEndDateEarly(LocalDate startDate, LocalDate endDate) { + return endDate.isBefore(startDate); + } + + private static boolean isBeforeDateThenCurrentDate(LocalDate startDate, LocalDate endDate) { + LocalDate currentDate = LocalDate.now(); + return startDate.isBefore(currentDate) || endDate.isBefore(currentDate); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/DurationTest.java b/src/test/java/nextstep/courses/domain/DurationTest.java new file mode 100644 index 000000000..1c7ea0e68 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/DurationTest.java @@ -0,0 +1,32 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.time.LocalDate; +import nextstep.courses.CanNotCreateException; +import org.junit.jupiter.api.Test; + +class DurationTest { + + @Test + void 강의의_시작과_종료일은_오늘보다_앞에있으면_에러전파() { + LocalDate startDate = LocalDate.now().minusDays(2); + LocalDate endDate = LocalDate.now().minusDays(1); + + assertThatThrownBy(() -> { + new Duration(startDate, endDate); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("강의 날짜는 오늘에서 다음날에 존재해야 한다"); + } + + @Test + void 강의_종료일이_시작일보다_앞에있으면_에러전파() { + LocalDate startDate = LocalDate.now().plusDays(2); + LocalDate endDate = LocalDate.now().plusDays(1); + + assertThatThrownBy(() -> { + new Duration(startDate, endDate); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("강의 종료일이 시작일보다 앞에 있을 수 없다"); + } +} \ No newline at end of file From 1bce7082c6c62092b59c421d4ef9af158732170d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Sun, 7 Dec 2025 22:28:57 +0900 Subject: [PATCH 05/34] =?UTF-8?q?feat=20:=20=EA=B0=95=EC=9D=98=20=EC=BB=A4?= =?UTF-8?q?=EB=B2=84=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EC=A0=95=EA=B7=9C=EC=8B=9D=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 --- .../nextstep/courses/domain/CoverImage.java | 47 +++++++++++++++++++ .../courses/domain/CoverImageType.java | 28 +++++++++++ .../courses/domain/CoverImageTest.java | 42 +++++++++++++++++ .../courses/domain/CoverImageTypeTest.java | 17 +++++++ 4 files changed, 134 insertions(+) create mode 100644 src/main/java/nextstep/courses/domain/CoverImage.java create mode 100644 src/main/java/nextstep/courses/domain/CoverImageType.java create mode 100644 src/test/java/nextstep/courses/domain/CoverImageTest.java create mode 100644 src/test/java/nextstep/courses/domain/CoverImageTypeTest.java diff --git a/src/main/java/nextstep/courses/domain/CoverImage.java b/src/main/java/nextstep/courses/domain/CoverImage.java new file mode 100644 index 000000000..55fdf9a20 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/CoverImage.java @@ -0,0 +1,47 @@ +package nextstep.courses.domain; + +import nextstep.courses.CanNotCreateException; + +public class CoverImage { + + public static final double COVER_IMAGE_RATIO = 1.5; + public static final int ONE_MEGA_BYTE = 1_000_000; // 1mb 는 1_000_000 byte 로 가정 + private final int size; // byte + private final CoverImageType type; + private final double width; + private final double height; + private final double ratio; + + public CoverImage(int size, String type, double width, double height) throws CanNotCreateException { + this(size, CoverImageType.valueOfIgnoreCase(type), width, height); + } + + public CoverImage(int size, CoverImageType type, double width, double height) throws CanNotCreateException { + validate(size, width, height); + this.size = size; + this.type = type; + this.width = width; + this.height = height; + this.ratio = width / height; + } + + private void validate(int size, double width, double height) throws CanNotCreateException { + if(size < ONE_MEGA_BYTE) { + throw new CanNotCreateException("커버 이미지의 크기는 1MB 이상이어야 한다"); + } + + if(width < 300) { + throw new CanNotCreateException("이미지의 너비(width)는 300px 이상이어야 한다"); + } + + if(height < 200) { + throw new CanNotCreateException("이미지의 높이(height)는 200px 이상이어야 한다"); + } + + if(width / height != COVER_IMAGE_RATIO) { + throw new CanNotCreateException("이미지의 너비(width)와 높이(height)의 비율은 3:2 이어야 한다"); + } + + } + +} diff --git a/src/main/java/nextstep/courses/domain/CoverImageType.java b/src/main/java/nextstep/courses/domain/CoverImageType.java new file mode 100644 index 000000000..0575b8803 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/CoverImageType.java @@ -0,0 +1,28 @@ +package nextstep.courses.domain; + +import nextstep.courses.CanNotCreateException; + +public enum CoverImageType { + GIF("gif"), + JPG("jpg"), + JPEG("jpeg"), + PNG("png"), + SVG("svg"); + + CoverImageType(String type) {} + + static CoverImageType valueOfIgnoreCase(String type) throws CanNotCreateException { + validate(type); + return Enum.valueOf(CoverImageType.class, type); + } + + private static void validate(String type) throws CanNotCreateException { + if(isNotCoverImageType(type)) { + throw new CanNotCreateException("커버 이미지의 타입은 gif, jpg(jpeg), png, svg 만 가능하다"); + } + } + + private static boolean isNotCoverImageType(String type) { + return !(type.equals("gif") || type.equals("jpg") || type.equals("jpeg") || type.equals("png") || type.equals("svg")); + } +} diff --git a/src/test/java/nextstep/courses/domain/CoverImageTest.java b/src/test/java/nextstep/courses/domain/CoverImageTest.java new file mode 100644 index 000000000..05c8db949 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/CoverImageTest.java @@ -0,0 +1,42 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import nextstep.courses.CanNotCreateException; +import org.junit.jupiter.api.Test; + +class CoverImageTest { + + @Test + void 커버이미지_크기는_1mb이상이면_에러전파() { + assertThatThrownBy(() -> { + new CoverImage(900_000, CoverImageType.JPEG, 300, 200); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("커버 이미지의 크기는 1MB 이상이어야 한다"); + } + + @Test + void 커버이미지의_정해진_크기_이하이면_에러전파() { + assertThatThrownBy(() -> { + new CoverImage(1_500_000, CoverImageType.JPEG, 299, 200); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("이미지의 너비(width)는 300px 이상이어야 한다"); + } + + @Test + void 커버이미지의_정해진_비율이_아니면_에러전파() { + assertThatThrownBy(() -> { + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 199); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("이미지의 높이(height)는 200px 이상이어야 한다"); + } + + @Test + void 커버이미지의_너비와_높이_비율은_3대2가_아니면_에러전파() { + assertThatThrownBy(() -> { + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 300); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("이미지의 너비(width)와 높이(height)의 비율은 3:2 이어야 한다"); + } + +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/CoverImageTypeTest.java b/src/test/java/nextstep/courses/domain/CoverImageTypeTest.java new file mode 100644 index 000000000..649a7008e --- /dev/null +++ b/src/test/java/nextstep/courses/domain/CoverImageTypeTest.java @@ -0,0 +1,17 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import nextstep.courses.CanNotCreateException; +import org.junit.jupiter.api.Test; + +class CoverImageTypeTest { + + @Test + void 커버이미지의_정해진타입이_아니면_에러전파() { + assertThatThrownBy(() -> { + CoverImageType.valueOfIgnoreCase("BMP"); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("커버 이미지의 타입은 gif, jpg(jpeg), png, svg 만 가능하다"); + } +} \ No newline at end of file From d54677ce0e5195aafbd3a6a61023cc33222dc71c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Sun, 7 Dec 2025 23:46:22 +0900 Subject: [PATCH 06/34] =?UTF-8?q?feat=20:=20=EA=B0=95=EC=9D=98=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C=20=EB=B0=8F?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextstep/courses/domain/SessionStatus.java | 15 +++++++++++++++ .../courses/domain/SessionStatusType.java | 5 +++++ .../courses/domain/SessionStatusTest.java | 15 +++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 src/main/java/nextstep/courses/domain/SessionStatus.java create mode 100644 src/main/java/nextstep/courses/domain/SessionStatusType.java create mode 100644 src/test/java/nextstep/courses/domain/SessionStatusTest.java diff --git a/src/main/java/nextstep/courses/domain/SessionStatus.java b/src/main/java/nextstep/courses/domain/SessionStatus.java new file mode 100644 index 000000000..4b0f7aa35 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionStatus.java @@ -0,0 +1,15 @@ +package nextstep.courses.domain; + +public class SessionStatus { + + private final SessionStatusType sessionStatusType; + + public SessionStatus(SessionStatusType sessionStatusType) { + this.sessionStatusType = sessionStatusType; + } + + public boolean isApplyStatus() { + return this.sessionStatusType == SessionStatusType.RECRUITING; + } + +} diff --git a/src/main/java/nextstep/courses/domain/SessionStatusType.java b/src/main/java/nextstep/courses/domain/SessionStatusType.java new file mode 100644 index 000000000..8cb783472 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionStatusType.java @@ -0,0 +1,5 @@ +package nextstep.courses.domain; + +public enum SessionStatusType { + PREPARATION, RECRUITING, END +} diff --git a/src/test/java/nextstep/courses/domain/SessionStatusTest.java b/src/test/java/nextstep/courses/domain/SessionStatusTest.java new file mode 100644 index 000000000..a05bcc98f --- /dev/null +++ b/src/test/java/nextstep/courses/domain/SessionStatusTest.java @@ -0,0 +1,15 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class SessionStatusTest { + + @Test + void 강의_상태가_모집중이_아닌데_신청하면_flase() { + SessionStatus sessionStatus = new SessionStatus(SessionStatusType.PREPARATION); + assertThat(sessionStatus.isApplyStatus()).isFalse(); + } + +} \ No newline at end of file From 5bbcbfb2b28ba16c00eb4b7b515362e7448ef8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Mon, 8 Dec 2025 01:13:56 +0900 Subject: [PATCH 07/34] =?UTF-8?q?feat=20:=20=EB=AC=B4=EB=A3=8C,=20?= =?UTF-8?q?=EC=9C=A0=EB=A3=8C=20=EA=B0=95=EC=9D=98=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=9D=BC=20=EA=B0=95=EC=9D=98=20=EC=8B=A0=EC=B2=AD=20=EB=B0=8F?= =?UTF-8?q?=20=EC=A0=95=EC=9B=90=20=EC=A7=80=EB=B6=88=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextstep/courses/CanNotJoinException.java | 8 ++ .../java/nextstep/courses/domain/Provide.java | 73 +++++++++++++++++++ .../nextstep/courses/domain/ProvideType.java | 11 +++ .../nextstep/courses/domain/ProvideTest.java | 64 ++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 src/main/java/nextstep/courses/CanNotJoinException.java create mode 100644 src/main/java/nextstep/courses/domain/Provide.java create mode 100644 src/main/java/nextstep/courses/domain/ProvideType.java create mode 100644 src/test/java/nextstep/courses/domain/ProvideTest.java diff --git a/src/main/java/nextstep/courses/CanNotJoinException.java b/src/main/java/nextstep/courses/CanNotJoinException.java new file mode 100644 index 000000000..b3782ebbc --- /dev/null +++ b/src/main/java/nextstep/courses/CanNotJoinException.java @@ -0,0 +1,8 @@ +package nextstep.courses; + +public class CanNotJoinException extends Exception { + + public CanNotJoinException(String message) { + super(message); + } +} diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java new file mode 100644 index 000000000..7c2592426 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -0,0 +1,73 @@ +package nextstep.courses.domain; + +import java.util.Objects; +import nextstep.courses.CanNotCreateException; +import nextstep.courses.CanNotJoinException; + +public class Provide { + + private final ProvideType type; + private int enrolledCount; + private final int tuitionFee; + + public Provide(ProvideType type, int enrolledCount) throws CanNotCreateException { + this(type, enrolledCount, 0); + } + + public Provide(ProvideType type, int enrolledCount, int tuitionFee) throws CanNotCreateException { + valdate(type, tuitionFee); + this.type = type; + this.enrolledCount = enrolledCount; + this.tuitionFee = tuitionFee; + } + + private void valdate(ProvideType type, int money) throws CanNotCreateException { + if(isFreeAndNonZeroMoney(type, money)) { + throw new CanNotCreateException("무료 강의에는 수강료는 0 이어야 한다"); + } + + if(isPaidAndZeroMoney(type, money)) { + throw new CanNotCreateException("유료 강의에는 수강료는 1 이상이다"); + } + } + + private boolean isFreeAndNonZeroMoney(ProvideType type, int money) { + return type == ProvideType.FREE && money != 0; + } + + private boolean isPaidAndZeroMoney(ProvideType type, int money) { + return type == ProvideType.PAID && money == 0; + } + + public void apply(int pay, int maxEnrollment) throws CanNotJoinException { + isCorrectPay(pay); + isAvailableEnroll(maxEnrollment); + this.enrolledCount += 1; + } + + private void isCorrectPay(int pay) throws CanNotJoinException { + if(this.tuitionFee != pay) { + throw new CanNotJoinException("지불한 금액과 수강료 금액이 다르다"); + } + } + + private void isAvailableEnroll(int maxEnrollment) throws CanNotJoinException { + if(this.enrolledCount >= maxEnrollment) { + throw new CanNotJoinException("이미 정원을 초과했다"); + } + } + + @Override + public boolean equals(Object o) { + if(o == null || getClass() != o.getClass()) { + return false; + } + Provide provide = (Provide) o; + return enrolledCount == provide.enrolledCount && tuitionFee == provide.tuitionFee && type == provide.type; + } + + @Override + public int hashCode() { + return Objects.hash(type, enrolledCount, tuitionFee); + } +} diff --git a/src/main/java/nextstep/courses/domain/ProvideType.java b/src/main/java/nextstep/courses/domain/ProvideType.java new file mode 100644 index 000000000..d3c964d55 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/ProvideType.java @@ -0,0 +1,11 @@ +package nextstep.courses.domain; + +public enum ProvideType { + PAID("paid", true), + FREE("free", false); + + private String provideType; + private boolean isExistTuitionFee; + + ProvideType(String provideType, boolean isExistTuitionFee) {} +} diff --git a/src/test/java/nextstep/courses/domain/ProvideTest.java b/src/test/java/nextstep/courses/domain/ProvideTest.java new file mode 100644 index 000000000..d8c507c17 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/ProvideTest.java @@ -0,0 +1,64 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import nextstep.courses.CanNotCreateException; +import nextstep.courses.CanNotJoinException; +import org.junit.jupiter.api.Test; + +class ProvideTest { + + @Test + void 무료인데_수강료가_있으면_에러전파() { + assertThatThrownBy(() -> { + new Provide(ProvideType.FREE, 0, 10); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("무료 강의에는 수강료는 0 이어야 한다"); + } + + @Test + void 유료인데_수강료가_없으면_에러전파() { + assertThatThrownBy(() -> { + new Provide(ProvideType.PAID, 0, 0); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("유료 강의에는 수강료는 1 이상이다"); + } + + @Test + void 유료강의에_수강신청한다() throws Exception { + Provide provide = new Provide(ProvideType.PAID, 0, 10); + provide.apply(10, 10); + + Provide expected = new Provide(ProvideType.PAID, 1, 10); + assertThat(provide).isEqualTo(expected); + } + + @Test + void 유료인데_수강료와_지불금액이_다르면_에러전파() throws Exception { + Provide provide = new Provide(ProvideType.PAID, 0, 10); + assertThatThrownBy(() -> { + provide.apply(9, 10); + }).isInstanceOf(CanNotJoinException.class) + .hasMessage("지불한 금액과 수강료 금액이 다르다"); + } + + @Test + void 무료인데_수강료_납부하면_에러전파() throws Exception { + Provide provide = new Provide(ProvideType.FREE, 0); + assertThatThrownBy(() -> { + provide.apply(10, 10); + }).isInstanceOf(CanNotJoinException.class) + .hasMessage("지불한 금액과 수강료 금액이 다르다"); + } + + @Test + void 수강신청_인원이_초과하면_에러전파() throws Exception { + Provide provide = new Provide(ProvideType.PAID, 5, 10); + assertThatThrownBy(() -> { + provide.apply(10, 5); + }).isInstanceOf(CanNotJoinException.class) + .hasMessage("이미 정원을 초과했다"); + } + +} \ No newline at end of file From 72f9e84e6590f83abd542fbf19d7f0f60e829ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Mon, 8 Dec 2025 01:28:56 +0900 Subject: [PATCH 08/34] =?UTF-8?q?refactor=20:=20enum=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EA=B3=B5=ED=86=B5=EB=90=9C=20enumerate=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/courses/domain/CoverImage.java | 1 + src/main/java/nextstep/courses/domain/Provide.java | 1 + src/main/java/nextstep/courses/domain/SessionStatus.java | 2 ++ .../courses/{domain => enumerate}/CoverImageType.java | 4 ++-- .../nextstep/courses/{domain => enumerate}/ProvideType.java | 2 +- .../courses/{domain => enumerate}/SessionStatusType.java | 2 +- src/test/java/nextstep/courses/domain/CoverImageTest.java | 1 + src/test/java/nextstep/courses/domain/ProvideTest.java | 1 + src/test/java/nextstep/courses/domain/SessionStatusTest.java | 1 + .../courses/{domain => enumberate}/CoverImageTypeTest.java | 3 ++- 10 files changed, 13 insertions(+), 5 deletions(-) rename src/main/java/nextstep/courses/{domain => enumerate}/CoverImageType.java (85%) rename src/main/java/nextstep/courses/{domain => enumerate}/ProvideType.java (86%) rename src/main/java/nextstep/courses/{domain => enumerate}/SessionStatusType.java (65%) rename src/test/java/nextstep/courses/{domain => enumberate}/CoverImageTypeTest.java (85%) diff --git a/src/main/java/nextstep/courses/domain/CoverImage.java b/src/main/java/nextstep/courses/domain/CoverImage.java index 55fdf9a20..b4fcdd619 100644 --- a/src/main/java/nextstep/courses/domain/CoverImage.java +++ b/src/main/java/nextstep/courses/domain/CoverImage.java @@ -1,6 +1,7 @@ package nextstep.courses.domain; import nextstep.courses.CanNotCreateException; +import nextstep.courses.enumerate.CoverImageType; public class CoverImage { diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java index 7c2592426..3ee134ff1 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -3,6 +3,7 @@ import java.util.Objects; import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; +import nextstep.courses.enumerate.ProvideType; public class Provide { diff --git a/src/main/java/nextstep/courses/domain/SessionStatus.java b/src/main/java/nextstep/courses/domain/SessionStatus.java index 4b0f7aa35..0bb995ff3 100644 --- a/src/main/java/nextstep/courses/domain/SessionStatus.java +++ b/src/main/java/nextstep/courses/domain/SessionStatus.java @@ -1,5 +1,7 @@ package nextstep.courses.domain; +import nextstep.courses.enumerate.SessionStatusType; + public class SessionStatus { private final SessionStatusType sessionStatusType; diff --git a/src/main/java/nextstep/courses/domain/CoverImageType.java b/src/main/java/nextstep/courses/enumerate/CoverImageType.java similarity index 85% rename from src/main/java/nextstep/courses/domain/CoverImageType.java rename to src/main/java/nextstep/courses/enumerate/CoverImageType.java index 0575b8803..81524ad1b 100644 --- a/src/main/java/nextstep/courses/domain/CoverImageType.java +++ b/src/main/java/nextstep/courses/enumerate/CoverImageType.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.enumerate; import nextstep.courses.CanNotCreateException; @@ -11,7 +11,7 @@ public enum CoverImageType { CoverImageType(String type) {} - static CoverImageType valueOfIgnoreCase(String type) throws CanNotCreateException { + public static CoverImageType valueOfIgnoreCase(String type) throws CanNotCreateException { validate(type); return Enum.valueOf(CoverImageType.class, type); } diff --git a/src/main/java/nextstep/courses/domain/ProvideType.java b/src/main/java/nextstep/courses/enumerate/ProvideType.java similarity index 86% rename from src/main/java/nextstep/courses/domain/ProvideType.java rename to src/main/java/nextstep/courses/enumerate/ProvideType.java index d3c964d55..7d68a3895 100644 --- a/src/main/java/nextstep/courses/domain/ProvideType.java +++ b/src/main/java/nextstep/courses/enumerate/ProvideType.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.enumerate; public enum ProvideType { PAID("paid", true), diff --git a/src/main/java/nextstep/courses/domain/SessionStatusType.java b/src/main/java/nextstep/courses/enumerate/SessionStatusType.java similarity index 65% rename from src/main/java/nextstep/courses/domain/SessionStatusType.java rename to src/main/java/nextstep/courses/enumerate/SessionStatusType.java index 8cb783472..8904938bd 100644 --- a/src/main/java/nextstep/courses/domain/SessionStatusType.java +++ b/src/main/java/nextstep/courses/enumerate/SessionStatusType.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.enumerate; public enum SessionStatusType { PREPARATION, RECRUITING, END diff --git a/src/test/java/nextstep/courses/domain/CoverImageTest.java b/src/test/java/nextstep/courses/domain/CoverImageTest.java index 05c8db949..856638104 100644 --- a/src/test/java/nextstep/courses/domain/CoverImageTest.java +++ b/src/test/java/nextstep/courses/domain/CoverImageTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; +import nextstep.courses.enumerate.CoverImageType; import org.junit.jupiter.api.Test; class CoverImageTest { diff --git a/src/test/java/nextstep/courses/domain/ProvideTest.java b/src/test/java/nextstep/courses/domain/ProvideTest.java index d8c507c17..60ad072b3 100644 --- a/src/test/java/nextstep/courses/domain/ProvideTest.java +++ b/src/test/java/nextstep/courses/domain/ProvideTest.java @@ -5,6 +5,7 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; +import nextstep.courses.enumerate.ProvideType; import org.junit.jupiter.api.Test; class ProvideTest { diff --git a/src/test/java/nextstep/courses/domain/SessionStatusTest.java b/src/test/java/nextstep/courses/domain/SessionStatusTest.java index a05bcc98f..3df263e8f 100644 --- a/src/test/java/nextstep/courses/domain/SessionStatusTest.java +++ b/src/test/java/nextstep/courses/domain/SessionStatusTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import nextstep.courses.enumerate.SessionStatusType; import org.junit.jupiter.api.Test; class SessionStatusTest { diff --git a/src/test/java/nextstep/courses/domain/CoverImageTypeTest.java b/src/test/java/nextstep/courses/enumberate/CoverImageTypeTest.java similarity index 85% rename from src/test/java/nextstep/courses/domain/CoverImageTypeTest.java rename to src/test/java/nextstep/courses/enumberate/CoverImageTypeTest.java index 649a7008e..e87ffea5d 100644 --- a/src/test/java/nextstep/courses/domain/CoverImageTypeTest.java +++ b/src/test/java/nextstep/courses/enumberate/CoverImageTypeTest.java @@ -1,8 +1,9 @@ -package nextstep.courses.domain; +package nextstep.courses.enumberate; import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; +import nextstep.courses.enumerate.CoverImageType; import org.junit.jupiter.api.Test; class CoverImageTypeTest { From 1c06b0433a3e2a64ad54356f6188678b848be3c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Mon, 8 Dec 2025 22:51:13 +0900 Subject: [PATCH 09/34] =?UTF-8?q?refactor=20:=20=EC=A0=95=EC=B1=85?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=20ProvidePolicy=20?= =?UTF-8?q?=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=98=EA=B3=A0,=20Provide=20?= =?UTF-8?q?=EC=97=90=20=EC=9D=BC=EB=B6=80=20=ED=95=84=EB=93=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 --- .../java/nextstep/courses/domain/Provide.java | 68 +++++-------------- .../courses/domain/ProvidePolicy.java | 67 ++++++++++++++++++ .../courses/domain/ProvidePolicyTest.java | 60 ++++++++++++++++ .../nextstep/courses/domain/ProvideTest.java | 49 ++++--------- 4 files changed, 159 insertions(+), 85 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/ProvidePolicy.java create mode 100644 src/test/java/nextstep/courses/domain/ProvidePolicyTest.java diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java index 3ee134ff1..11b7172bb 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -1,6 +1,5 @@ package nextstep.courses.domain; -import java.util.Objects; import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.ProvideType; @@ -8,67 +7,34 @@ public class Provide { private final ProvideType type; - private int enrolledCount; - private final int tuitionFee; + private final ProvidePolicy policy; - public Provide(ProvideType type, int enrolledCount) throws CanNotCreateException { - this(type, enrolledCount, 0); - } - - public Provide(ProvideType type, int enrolledCount, int tuitionFee) throws CanNotCreateException { - valdate(type, tuitionFee); + public Provide(ProvideType type, ProvidePolicy policy) throws CanNotCreateException { + validate(type, policy); this.type = type; - this.enrolledCount = enrolledCount; - this.tuitionFee = tuitionFee; + this.policy = policy; } - private void valdate(ProvideType type, int money) throws CanNotCreateException { - if(isFreeAndNonZeroMoney(type, money)) { - throw new CanNotCreateException("무료 강의에는 수강료는 0 이어야 한다"); + private void validate(ProvideType type, ProvidePolicy policy) throws CanNotCreateException { + if(policy.isNotCorrectBetween(type)) { + throw new CanNotCreateException("강의타입과 정책이 일치하지 않습니다"); } - - if(isPaidAndZeroMoney(type, money)) { - throw new CanNotCreateException("유료 강의에는 수강료는 1 이상이다"); - } - } - - private boolean isFreeAndNonZeroMoney(ProvideType type, int money) { - return type == ProvideType.FREE && money != 0; - } - - private boolean isPaidAndZeroMoney(ProvideType type, int money) { - return type == ProvideType.PAID && money == 0; } - public void apply(int pay, int maxEnrollment) throws CanNotJoinException { - isCorrectPay(pay); - isAvailableEnroll(maxEnrollment); - this.enrolledCount += 1; - } - - private void isCorrectPay(int pay) throws CanNotJoinException { - if(this.tuitionFee != pay) { - throw new CanNotJoinException("지불한 금액과 수강료 금액이 다르다"); - } - } - - private void isAvailableEnroll(int maxEnrollment) throws CanNotJoinException { - if(this.enrolledCount >= maxEnrollment) { - throw new CanNotJoinException("이미 정원을 초과했다"); + public boolean applyPaid(int enrolledCount, int pay) throws CanNotJoinException { + if(this.type == ProvideType.FREE) { + throw new CanNotJoinException("무료 강의는 결제할 수 없다"); } + policy.isAvailableEnroll(enrolledCount); + policy.isCorrectPay(pay); + return true; } - @Override - public boolean equals(Object o) { - if(o == null || getClass() != o.getClass()) { - return false; + public boolean applyFree() throws CanNotJoinException { + if(this.type == ProvideType.FREE) { + throw new CanNotJoinException("무료강의는 결제할 수 없다"); } - Provide provide = (Provide) o; - return enrolledCount == provide.enrolledCount && tuitionFee == provide.tuitionFee && type == provide.type; + return true; } - @Override - public int hashCode() { - return Objects.hash(type, enrolledCount, tuitionFee); - } } diff --git a/src/main/java/nextstep/courses/domain/ProvidePolicy.java b/src/main/java/nextstep/courses/domain/ProvidePolicy.java new file mode 100644 index 000000000..5c313408a --- /dev/null +++ b/src/main/java/nextstep/courses/domain/ProvidePolicy.java @@ -0,0 +1,67 @@ +package nextstep.courses.domain; + +import nextstep.courses.CanNotCreateException; +import nextstep.courses.CanNotJoinException; +import nextstep.courses.enumerate.ProvideType; + +public class ProvidePolicy { + + private final Integer maxEnrollment; + private final Integer tuitionFee; + + public ProvidePolicy() throws CanNotCreateException { + this(null, null); + } + + public ProvidePolicy(Integer maxEnrollment, Integer tuitionFee) throws CanNotCreateException { + validate(maxEnrollment, tuitionFee); + this.maxEnrollment = maxEnrollment; + this.tuitionFee = tuitionFee; + } + + private void validate(Integer maxEnrollment, Integer tuitionFee) throws CanNotCreateException { + if(IsMaxEnrollmentOnlyNull(maxEnrollment, tuitionFee)) { + throw new CanNotCreateException("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); + } + if(isTuitionFeeOnlyNull(maxEnrollment, tuitionFee)) { + throw new CanNotCreateException("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); + } + } + + private static boolean isTuitionFeeOnlyNull(Integer maxEnrollment, Integer tuitionFee) { + return maxEnrollment != null && tuitionFee == null; + } + + private static boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Integer tuitionFee) { + return maxEnrollment == null && tuitionFee != null; + } + + public void isCorrectPay(int pay) throws CanNotJoinException { + if(this.tuitionFee == null) { + throw new CanNotJoinException("무료 강의는 지불할 수 없다"); + } + if(this.tuitionFee != pay) { + throw new CanNotJoinException("지불한 금액과 수강료 금액이 다르다"); + } + } + + public void isAvailableEnroll(int enrolledCount) throws CanNotJoinException { + if(this.maxEnrollment == null) { + throw new CanNotJoinException("무료강의는 정원이 없다"); + } + + if(this.maxEnrollment <= enrolledCount) { + throw new CanNotJoinException("이미 정원을 초과했다"); + } + } + + public boolean isNotCorrectBetween(ProvideType type) { + if(type == ProvideType.FREE) { + return !(this.maxEnrollment == null && this.tuitionFee == null); + } + if(type == ProvideType.PAID) { + return !(this.maxEnrollment != null && this.tuitionFee != null); + } + return true; + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java new file mode 100644 index 000000000..c1dfe2c71 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java @@ -0,0 +1,60 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import nextstep.courses.CanNotCreateException; +import nextstep.courses.CanNotJoinException; +import org.junit.jupiter.api.Test; + +class ProvidePolicyTest { + + @Test + void maxEnrollment와tuitionFee_두개중_하나만_null이면_에러전파() { + + assertThatThrownBy(() -> { + new ProvidePolicy(10, null); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); + + assertThatThrownBy(() -> { + new ProvidePolicy(null, 10); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); + } + + @Test + void 유료인데_수강료와_지불금액이_다르면_에러전파() throws Exception { + ProvidePolicy providePolicy = new ProvidePolicy(10, 10); + assertThatThrownBy(() -> { + providePolicy.isCorrectPay(11); + }).isInstanceOf(CanNotJoinException.class) + .hasMessage("지불한 금액과 수강료 금액이 다르다"); + } + + @Test + void 무료인데_수강료_납부하면_에러전파() throws Exception { + ProvidePolicy providePolicy = new ProvidePolicy(); + assertThatThrownBy(() -> { + providePolicy.isCorrectPay(10); + }).isInstanceOf(CanNotJoinException.class) + .hasMessage("무료 강의는 지불할 수 없다"); + } + + @Test + void 수강신청_인원이_초과하면_에러전파() throws Exception { + ProvidePolicy providePolicy = new ProvidePolicy(10, 10); + assertThatThrownBy(() -> { + providePolicy.isAvailableEnroll(10); + }).isInstanceOf(CanNotJoinException.class) + .hasMessage("이미 정원을 초과했다"); + } + + @Test + void 무료강의인데_수강신청_시_정원체크하면_에러전파() throws Exception { + ProvidePolicy providePolicy = new ProvidePolicy(); + assertThatThrownBy(() -> { + providePolicy.isAvailableEnroll(10); + }).isInstanceOf(CanNotJoinException.class) + .hasMessage("무료강의는 정원이 없다"); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/ProvideTest.java b/src/test/java/nextstep/courses/domain/ProvideTest.java index 60ad072b3..8a36b5931 100644 --- a/src/test/java/nextstep/courses/domain/ProvideTest.java +++ b/src/test/java/nextstep/courses/domain/ProvideTest.java @@ -11,55 +11,36 @@ class ProvideTest { @Test - void 무료인데_수강료가_있으면_에러전파() { + void 무료강의인데_수강료가있으면_에러전파() throws CanNotCreateException { assertThatThrownBy(() -> { - new Provide(ProvideType.FREE, 0, 10); + new Provide(ProvideType.FREE, new ProvidePolicy(10, 10)); }).isInstanceOf(CanNotCreateException.class) - .hasMessage("무료 강의에는 수강료는 0 이어야 한다"); - } - - @Test - void 유료인데_수강료가_없으면_에러전파() { - assertThatThrownBy(() -> { - new Provide(ProvideType.PAID, 0, 0); - }).isInstanceOf(CanNotCreateException.class) - .hasMessage("유료 강의에는 수강료는 1 이상이다"); + .hasMessage("강의타입과 정책이 일치하지 않습니다"); } @Test void 유료강의에_수강신청한다() throws Exception { - Provide provide = new Provide(ProvideType.PAID, 0, 10); - provide.apply(10, 10); - - Provide expected = new Provide(ProvideType.PAID, 1, 10); - assertThat(provide).isEqualTo(expected); - } - - @Test - void 유료인데_수강료와_지불금액이_다르면_에러전파() throws Exception { - Provide provide = new Provide(ProvideType.PAID, 0, 10); - assertThatThrownBy(() -> { - provide.apply(9, 10); - }).isInstanceOf(CanNotJoinException.class) - .hasMessage("지불한 금액과 수강료 금액이 다르다"); + Provide provide = new Provide(ProvideType.PAID, new ProvidePolicy(10, 5)); + assertThat(provide.applyPaid(8, 5)) + .isTrue(); } @Test - void 무료인데_수강료_납부하면_에러전파() throws Exception { - Provide provide = new Provide(ProvideType.FREE, 0); + void 무료강의에_지불_후_수강신청한다() throws Exception { + Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); assertThatThrownBy(() -> { - provide.apply(10, 10); + assertThat(provide.applyPaid(8, 5)); }).isInstanceOf(CanNotJoinException.class) - .hasMessage("지불한 금액과 수강료 금액이 다르다"); + .hasMessage("무료 강의는 결제할 수 없다"); } @Test - void 수강신청_인원이_초과하면_에러전파() throws Exception { - Provide provide = new Provide(ProvideType.PAID, 5, 10); + void 무료강의에_지불_없이_수강신청한다() throws Exception { + Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); assertThatThrownBy(() -> { - provide.apply(10, 5); + assertThat(provide.applyFree()); }).isInstanceOf(CanNotJoinException.class) - .hasMessage("이미 정원을 초과했다"); + .hasMessage("무료강의는 결제할 수 없다"); } - + } \ No newline at end of file From 0bbac87190442da6bc270a902903438e3fe42e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 00:28:39 +0900 Subject: [PATCH 10/34] =?UTF-8?q?feat=20:=20session=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=20=EA=B0=9C=EB=B0=9C=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C,=20=EC=88=98=EA=B0=95=EC=8B=A0=EC=B2=AD=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B0=9C=EB=B0=9C=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Base.java | 18 +++++ .../java/nextstep/courses/domain/Provide.java | 14 +++- .../java/nextstep/courses/domain/Session.java | 49 +++++++++++++ .../nextstep/courses/domain/SessionBody.java | 24 +++++++ .../nextstep/courses/domain/ProvideTest.java | 13 ++-- .../courses/domain/SessionBodyTest.java | 23 ++++++ .../nextstep/courses/domain/SessionTest.java | 72 +++++++++++++++++++ 7 files changed, 205 insertions(+), 8 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/Base.java create mode 100644 src/main/java/nextstep/courses/domain/Session.java create mode 100644 src/main/java/nextstep/courses/domain/SessionBody.java create mode 100644 src/test/java/nextstep/courses/domain/SessionBodyTest.java create mode 100644 src/test/java/nextstep/courses/domain/SessionTest.java diff --git a/src/main/java/nextstep/courses/domain/Base.java b/src/main/java/nextstep/courses/domain/Base.java new file mode 100644 index 000000000..0adb13722 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/Base.java @@ -0,0 +1,18 @@ +package nextstep.courses.domain; + +import java.time.LocalDateTime; + +public class Base { + + protected LocalDateTime createdDate; + protected LocalDateTime updatedDate; + + public Base() { + this(LocalDateTime.now(), null); + } + + public Base(LocalDateTime createdDate, LocalDateTime updatedDate) { + this.createdDate = createdDate; + this.updatedDate = updatedDate; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java index 11b7172bb..29dc09fdb 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -9,6 +9,10 @@ public class Provide { private final ProvideType type; private final ProvidePolicy policy; + public Provide(ProvideType type) throws CanNotCreateException { + this(type, new ProvidePolicy()); + } + public Provide(ProvideType type, ProvidePolicy policy) throws CanNotCreateException { validate(type, policy); this.type = type; @@ -23,7 +27,7 @@ private void validate(ProvideType type, ProvidePolicy policy) throws CanNotCreat public boolean applyPaid(int enrolledCount, int pay) throws CanNotJoinException { if(this.type == ProvideType.FREE) { - throw new CanNotJoinException("무료 강의는 결제할 수 없다"); + throw new CanNotJoinException("유료 강의는 결제를 해야한다"); } policy.isAvailableEnroll(enrolledCount); policy.isCorrectPay(pay); @@ -31,10 +35,14 @@ public boolean applyPaid(int enrolledCount, int pay) throws CanNotJoinException } public boolean applyFree() throws CanNotJoinException { - if(this.type == ProvideType.FREE) { - throw new CanNotJoinException("무료강의는 결제할 수 없다"); + if(this.type == ProvideType.PAID) { + throw new CanNotJoinException("무료 강의는 결제할 수 없다"); } return true; } + public boolean isFreeType() { + return this.type == ProvideType.FREE; + } + } diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java new file mode 100644 index 000000000..ba84dec24 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -0,0 +1,49 @@ +package nextstep.courses.domain; + +import java.time.LocalDateTime; +import nextstep.courses.CanNotJoinException; +import nextstep.courses.enumerate.SessionStatusType; + +public class Session extends Base { + + private final Long id; + private final String creatorId; + private final SessionBody body; + private final Duration duration; + private final CoverImage coverImage; + private final SessionStatus status; + private final Provide provide; + private int enrolledCount; + + public Session(String creatorId, SessionBody body, Duration duration, CoverImage coverImage, Provide provide) { + this(0L, creatorId, body, duration, coverImage, new SessionStatus(SessionStatusType.PREPARATION), provide, 0, LocalDateTime.now(), null); + } + + public Session(Long id, String creatorId, SessionBody body, Duration duration, CoverImage coverImage, SessionStatus status, Provide provide, int enrolledCount, LocalDateTime createdDate, LocalDateTime updatedDate) { + super(createdDate, updatedDate); + this.id = id; + this.creatorId = creatorId; + this.body = body; + this.duration = duration; + this.coverImage = coverImage; + this.status = status; + this.provide = provide; + this.enrolledCount = enrolledCount; + } + + public boolean applyFreeSession() throws CanNotJoinException { + if(provide.applyFree()) { + enrolledCount++; + return true; + } + return false; + } + + public boolean applyPaidSession(int amount) throws CanNotJoinException { + if(provide.applyPaid(this.enrolledCount, amount)) { + enrolledCount++; + return true; + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/SessionBody.java b/src/main/java/nextstep/courses/domain/SessionBody.java new file mode 100644 index 000000000..6e2f0adf6 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionBody.java @@ -0,0 +1,24 @@ +package nextstep.courses.domain; + +import nextstep.courses.CanNotCreateException; + +public class SessionBody { + + private final String title; + private final String content; + + public SessionBody(String title, String content) throws CanNotCreateException { + validate(title, content); + this.title = title; + this.content = content; + } + + private void validate(String title, String content) throws CanNotCreateException { + if(title == null) { + throw new CanNotCreateException("제목에 내용이 없다"); + } + if(content == null) { + throw new CanNotCreateException("컨텐츠에 내용이 없다"); + } + } +} diff --git a/src/test/java/nextstep/courses/domain/ProvideTest.java b/src/test/java/nextstep/courses/domain/ProvideTest.java index 8a36b5931..78b438d6e 100644 --- a/src/test/java/nextstep/courses/domain/ProvideTest.java +++ b/src/test/java/nextstep/courses/domain/ProvideTest.java @@ -31,16 +31,19 @@ class ProvideTest { assertThatThrownBy(() -> { assertThat(provide.applyPaid(8, 5)); }).isInstanceOf(CanNotJoinException.class) - .hasMessage("무료 강의는 결제할 수 없다"); + .hasMessage("유료 강의는 결제를 해야한다"); } @Test void 무료강의에_지불_없이_수강신청한다() throws Exception { Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); - assertThatThrownBy(() -> { - assertThat(provide.applyFree()); - }).isInstanceOf(CanNotJoinException.class) - .hasMessage("무료강의는 결제할 수 없다"); + assertThat(provide.applyFree()).isTrue(); + } + + @Test + void 무료강의이면_false를_전달한다() throws CanNotCreateException { + Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); + assertThat(provide.isFreeType()).isTrue(); } } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/SessionBodyTest.java b/src/test/java/nextstep/courses/domain/SessionBodyTest.java new file mode 100644 index 000000000..4528f0faf --- /dev/null +++ b/src/test/java/nextstep/courses/domain/SessionBodyTest.java @@ -0,0 +1,23 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import nextstep.courses.CanNotCreateException; +import org.junit.jupiter.api.Test; + +class SessionBodyTest { + + @Test + void session_body의_제목과_본문은_null이면_에러전파() { + assertThatThrownBy(() -> { + new SessionBody(null, "content"); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("제목에 내용이 없다"); + + assertThatThrownBy(() -> { + new SessionBody("title", null); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("컨텐츠에 내용이 없다"); + } + +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java new file mode 100644 index 000000000..7e38d92b0 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -0,0 +1,72 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; +import nextstep.courses.enumerate.CoverImageType; +import nextstep.courses.enumerate.ProvideType; +import org.junit.jupiter.api.Test; + +class SessionTest { + + public static final Session freeSession; + public static final Session paidSession; + + static { + try { + freeSession = new Session( + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new Provide(ProvideType.FREE) + ); + paidSession = new Session( + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new Provide(ProvideType.PAID, new ProvidePolicy(10, 10)) + ); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + + @Test + void 무료_session을_생성한다() throws Exception { + new Session( + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new Provide(ProvideType.FREE) + ); + } + + @Test + void 유료_session을_생성한다() throws Exception { + new Session( + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new Provide(ProvideType.PAID, new ProvidePolicy(10, 10)) + ); + } + + @Test + void 무료_session을_수강신청한다() throws Exception { + assertThat(freeSession.applyFreeSession()) + .isTrue(); + } + + @Test + void 유료_session을_수강신청한다() throws Exception { + assertThat(paidSession.applyPaidSession(10)) + .isTrue(); + + } + +} \ No newline at end of file From ec294959232f19c8ab5fde6e2d70eb9fe5dc25a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 00:44:12 +0900 Subject: [PATCH 11/34] =?UTF-8?q?refactor=20:=20apply=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B0=98=ED=99=98=20=EA=B0=92?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=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 --- .../java/nextstep/courses/domain/Provide.java | 10 ++-------- .../java/nextstep/courses/domain/Session.java | 18 ++++++------------ .../nextstep/courses/domain/ProvideTest.java | 18 +++++++----------- .../nextstep/courses/domain/SessionTest.java | 11 +++++------ 4 files changed, 20 insertions(+), 37 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java index 29dc09fdb..ef87afa5d 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -25,24 +25,18 @@ private void validate(ProvideType type, ProvidePolicy policy) throws CanNotCreat } } - public boolean applyPaid(int enrolledCount, int pay) throws CanNotJoinException { + public void applyPaid(int enrolledCount, int pay) throws CanNotJoinException { if(this.type == ProvideType.FREE) { throw new CanNotJoinException("유료 강의는 결제를 해야한다"); } policy.isAvailableEnroll(enrolledCount); policy.isCorrectPay(pay); - return true; } - public boolean applyFree() throws CanNotJoinException { + public void applyFree() throws CanNotJoinException { if(this.type == ProvideType.PAID) { throw new CanNotJoinException("무료 강의는 결제할 수 없다"); } - return true; - } - - public boolean isFreeType() { - return this.type == ProvideType.FREE; } } diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index ba84dec24..3d0309d99 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -31,19 +31,13 @@ public Session(Long id, String creatorId, SessionBody body, Duration duration, C this.enrolledCount = enrolledCount; } - public boolean applyFreeSession() throws CanNotJoinException { - if(provide.applyFree()) { - enrolledCount++; - return true; - } - return false; + public void applyFreeSession() throws CanNotJoinException { + provide.applyFree(); + enrolledCount++; } - public boolean applyPaidSession(int amount) throws CanNotJoinException { - if(provide.applyPaid(this.enrolledCount, amount)) { - enrolledCount++; - return true; - } - return false; + public void applyPaidSession(int amount) throws CanNotJoinException { + provide.applyPaid(this.enrolledCount, amount); + enrolledCount++; } } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/ProvideTest.java b/src/test/java/nextstep/courses/domain/ProvideTest.java index 78b438d6e..3584315da 100644 --- a/src/test/java/nextstep/courses/domain/ProvideTest.java +++ b/src/test/java/nextstep/courses/domain/ProvideTest.java @@ -1,6 +1,6 @@ package nextstep.courses.domain; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; @@ -21,15 +21,17 @@ class ProvideTest { @Test void 유료강의에_수강신청한다() throws Exception { Provide provide = new Provide(ProvideType.PAID, new ProvidePolicy(10, 5)); - assertThat(provide.applyPaid(8, 5)) - .isTrue(); + + assertThatNoException().isThrownBy(() -> { + provide.applyPaid(8, 5); + }); } @Test void 무료강의에_지불_후_수강신청한다() throws Exception { Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); assertThatThrownBy(() -> { - assertThat(provide.applyPaid(8, 5)); + provide.applyPaid(8, 5); }).isInstanceOf(CanNotJoinException.class) .hasMessage("유료 강의는 결제를 해야한다"); } @@ -37,13 +39,7 @@ class ProvideTest { @Test void 무료강의에_지불_없이_수강신청한다() throws Exception { Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); - assertThat(provide.applyFree()).isTrue(); + assertThatNoException().isThrownBy(provide::applyFree); } - @Test - void 무료강의이면_false를_전달한다() throws CanNotCreateException { - Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); - assertThat(provide.isFreeType()).isTrue(); - } - } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 7e38d92b0..94ac62abf 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -1,6 +1,6 @@ package nextstep.courses.domain; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; import java.time.LocalDate; import nextstep.courses.enumerate.CoverImageType; @@ -58,15 +58,14 @@ class SessionTest { @Test void 무료_session을_수강신청한다() throws Exception { - assertThat(freeSession.applyFreeSession()) - .isTrue(); + assertThatNoException().isThrownBy(freeSession::applyFreeSession); } @Test void 유료_session을_수강신청한다() throws Exception { - assertThat(paidSession.applyPaidSession(10)) - .isTrue(); - + assertThatNoException().isThrownBy(() -> { + paidSession.applyPaidSession(10); + }); } } \ No newline at end of file From 5cb93985dc2f88d3221cc45c8531de524878bcaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 01:11:07 +0900 Subject: [PATCH 12/34] =?UTF-8?q?fix=20:=20=EA=B0=95=EC=9D=98=20=EB=AA=A8?= =?UTF-8?q?=EC=9E=85=20=EC=A4=91=20=EC=83=81=ED=83=9C=EC=97=90=20=EC=8B=A0?= =?UTF-8?q?=EC=B2=AD=20=EA=B0=80=EB=8A=A5=ED=95=98=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/courses/domain/Session.java | 2 ++ src/main/java/nextstep/courses/domain/SessionStatus.java | 7 +++++-- .../java/nextstep/courses/domain/SessionStatusTest.java | 7 +++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 3d0309d99..586f165fa 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -32,11 +32,13 @@ public Session(Long id, String creatorId, SessionBody body, Duration duration, C } public void applyFreeSession() throws CanNotJoinException { + status.isApplyStatus(); provide.applyFree(); enrolledCount++; } public void applyPaidSession(int amount) throws CanNotJoinException { + status.isApplyStatus(); provide.applyPaid(this.enrolledCount, amount); enrolledCount++; } diff --git a/src/main/java/nextstep/courses/domain/SessionStatus.java b/src/main/java/nextstep/courses/domain/SessionStatus.java index 0bb995ff3..cb1a258e0 100644 --- a/src/main/java/nextstep/courses/domain/SessionStatus.java +++ b/src/main/java/nextstep/courses/domain/SessionStatus.java @@ -1,5 +1,6 @@ package nextstep.courses.domain; +import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.SessionStatusType; public class SessionStatus { @@ -10,8 +11,10 @@ public SessionStatus(SessionStatusType sessionStatusType) { this.sessionStatusType = sessionStatusType; } - public boolean isApplyStatus() { - return this.sessionStatusType == SessionStatusType.RECRUITING; + public void isApplyStatus() throws CanNotJoinException { + if(this.sessionStatusType != SessionStatusType.RECRUITING) { + throw new CanNotJoinException("모집 중 일때만 신청 가능합니다"); + } } } diff --git a/src/test/java/nextstep/courses/domain/SessionStatusTest.java b/src/test/java/nextstep/courses/domain/SessionStatusTest.java index 3df263e8f..a787f846d 100644 --- a/src/test/java/nextstep/courses/domain/SessionStatusTest.java +++ b/src/test/java/nextstep/courses/domain/SessionStatusTest.java @@ -1,7 +1,8 @@ package nextstep.courses.domain; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.SessionStatusType; import org.junit.jupiter.api.Test; @@ -10,7 +11,9 @@ class SessionStatusTest { @Test void 강의_상태가_모집중이_아닌데_신청하면_flase() { SessionStatus sessionStatus = new SessionStatus(SessionStatusType.PREPARATION); - assertThat(sessionStatus.isApplyStatus()).isFalse(); + assertThatThrownBy(sessionStatus::isApplyStatus) + .isInstanceOf(CanNotJoinException.class) + .hasMessage("모집 중 일때만 신청 가능합니다"); } } \ No newline at end of file From ff4179f4be011c0e86abf285bf0f420a91bb5214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 01:21:25 +0900 Subject: [PATCH 13/34] =?UTF-8?q?test=20:=20=EA=B9=A8=EC=A7=84=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B3=A0=EC=B9=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextstep/courses/domain/SessionTest.java | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 94ac62abf..4f5c93059 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -3,8 +3,10 @@ import static org.assertj.core.api.Assertions.assertThatNoException; import java.time.LocalDate; +import java.time.LocalDateTime; import nextstep.courses.enumerate.CoverImageType; import nextstep.courses.enumerate.ProvideType; +import nextstep.courses.enumerate.SessionStatusType; import org.junit.jupiter.api.Test; class SessionTest { @@ -15,18 +17,29 @@ class SessionTest { static { try { freeSession = new Session( + 1L, "1", new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Provide(ProvideType.FREE) + new SessionStatus(SessionStatusType.RECRUITING), + new Provide(ProvideType.FREE), + 5, + LocalDateTime.now(), + null ); + paidSession = new Session( + 2L, "1", new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Provide(ProvideType.PAID, new ProvidePolicy(10, 10)) + new SessionStatus(SessionStatusType.RECRUITING), + new Provide(ProvideType.PAID, new ProvidePolicy(10, 10)), + 5, + LocalDateTime.now(), + null ); } catch(Exception e) { throw new RuntimeException(e); @@ -36,24 +49,28 @@ class SessionTest { @Test void 무료_session을_생성한다() throws Exception { - new Session( - "1", - new SessionBody("title", "content"), - new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Provide(ProvideType.FREE) - ); + assertThatNoException().isThrownBy(() -> { + new Session( + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new Provide(ProvideType.FREE) + ); + }); } @Test void 유료_session을_생성한다() throws Exception { - new Session( - "1", - new SessionBody("title", "content"), - new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Provide(ProvideType.PAID, new ProvidePolicy(10, 10)) - ); + assertThatNoException().isThrownBy(() -> { + new Session( + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new Provide(ProvideType.PAID, new ProvidePolicy(10, 10)) + ); + }); } @Test From ea85e9c4791a369088c3654f78f080c19825b600 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 01:39:15 +0900 Subject: [PATCH 14/34] =?UTF-8?q?refactor=201.=20amount,=20pay=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9E=90=EB=A3=8C=ED=98=95=20int=20=EC=97=90?= =?UTF-8?q?=EC=84=9C=20Long=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD=202.=20?= =?UTF-8?q?Session=20=EC=97=90=20session=20=EC=B0=BE=EB=8A=94=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/courses/domain/Provide.java | 2 +- .../java/nextstep/courses/domain/ProvidePolicy.java | 12 ++++++------ src/main/java/nextstep/courses/domain/Session.java | 7 ++++++- .../nextstep/courses/domain/ProvidePolicyTest.java | 10 +++++----- .../java/nextstep/courses/domain/ProvideTest.java | 8 ++++---- .../java/nextstep/courses/domain/SessionTest.java | 6 +++--- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java index ef87afa5d..a5cb0c69e 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -25,7 +25,7 @@ private void validate(ProvideType type, ProvidePolicy policy) throws CanNotCreat } } - public void applyPaid(int enrolledCount, int pay) throws CanNotJoinException { + public void applyPaid(int enrolledCount, Long pay) throws CanNotJoinException { if(this.type == ProvideType.FREE) { throw new CanNotJoinException("유료 강의는 결제를 해야한다"); } diff --git a/src/main/java/nextstep/courses/domain/ProvidePolicy.java b/src/main/java/nextstep/courses/domain/ProvidePolicy.java index 5c313408a..d963436f5 100644 --- a/src/main/java/nextstep/courses/domain/ProvidePolicy.java +++ b/src/main/java/nextstep/courses/domain/ProvidePolicy.java @@ -7,19 +7,19 @@ public class ProvidePolicy { private final Integer maxEnrollment; - private final Integer tuitionFee; + private final Long tuitionFee; public ProvidePolicy() throws CanNotCreateException { this(null, null); } - public ProvidePolicy(Integer maxEnrollment, Integer tuitionFee) throws CanNotCreateException { + public ProvidePolicy(Integer maxEnrollment, Long tuitionFee) throws CanNotCreateException { validate(maxEnrollment, tuitionFee); this.maxEnrollment = maxEnrollment; this.tuitionFee = tuitionFee; } - private void validate(Integer maxEnrollment, Integer tuitionFee) throws CanNotCreateException { + private void validate(Integer maxEnrollment, Long tuitionFee) throws CanNotCreateException { if(IsMaxEnrollmentOnlyNull(maxEnrollment, tuitionFee)) { throw new CanNotCreateException("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); } @@ -28,15 +28,15 @@ private void validate(Integer maxEnrollment, Integer tuitionFee) throws CanNotCr } } - private static boolean isTuitionFeeOnlyNull(Integer maxEnrollment, Integer tuitionFee) { + private static boolean isTuitionFeeOnlyNull(Integer maxEnrollment, Long tuitionFee) { return maxEnrollment != null && tuitionFee == null; } - private static boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Integer tuitionFee) { + private static boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Long tuitionFee) { return maxEnrollment == null && tuitionFee != null; } - public void isCorrectPay(int pay) throws CanNotJoinException { + public void isCorrectPay(Long pay) throws CanNotJoinException { if(this.tuitionFee == null) { throw new CanNotJoinException("무료 강의는 지불할 수 없다"); } diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 586f165fa..a3011d430 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -1,6 +1,7 @@ package nextstep.courses.domain; import java.time.LocalDateTime; +import java.util.Objects; import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.SessionStatusType; @@ -37,9 +38,13 @@ public void applyFreeSession() throws CanNotJoinException { enrolledCount++; } - public void applyPaidSession(int amount) throws CanNotJoinException { + public void applyPaidSession(Long amount) throws CanNotJoinException { status.isApplyStatus(); provide.applyPaid(this.enrolledCount, amount); enrolledCount++; } + + public boolean isSameSessionId(Long id) { + return Objects.equals(this.id, id); + } } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java index c1dfe2c71..cc82e8051 100644 --- a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java +++ b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java @@ -17,16 +17,16 @@ class ProvidePolicyTest { .hasMessage("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); assertThatThrownBy(() -> { - new ProvidePolicy(null, 10); + new ProvidePolicy(null, 10L); }).isInstanceOf(CanNotCreateException.class) .hasMessage("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); } @Test void 유료인데_수강료와_지불금액이_다르면_에러전파() throws Exception { - ProvidePolicy providePolicy = new ProvidePolicy(10, 10); + ProvidePolicy providePolicy = new ProvidePolicy(10, 10L); assertThatThrownBy(() -> { - providePolicy.isCorrectPay(11); + providePolicy.isCorrectPay(11L); }).isInstanceOf(CanNotJoinException.class) .hasMessage("지불한 금액과 수강료 금액이 다르다"); } @@ -35,14 +35,14 @@ class ProvidePolicyTest { void 무료인데_수강료_납부하면_에러전파() throws Exception { ProvidePolicy providePolicy = new ProvidePolicy(); assertThatThrownBy(() -> { - providePolicy.isCorrectPay(10); + providePolicy.isCorrectPay(10L); }).isInstanceOf(CanNotJoinException.class) .hasMessage("무료 강의는 지불할 수 없다"); } @Test void 수강신청_인원이_초과하면_에러전파() throws Exception { - ProvidePolicy providePolicy = new ProvidePolicy(10, 10); + ProvidePolicy providePolicy = new ProvidePolicy(10, 10L); assertThatThrownBy(() -> { providePolicy.isAvailableEnroll(10); }).isInstanceOf(CanNotJoinException.class) diff --git a/src/test/java/nextstep/courses/domain/ProvideTest.java b/src/test/java/nextstep/courses/domain/ProvideTest.java index 3584315da..407c12dbc 100644 --- a/src/test/java/nextstep/courses/domain/ProvideTest.java +++ b/src/test/java/nextstep/courses/domain/ProvideTest.java @@ -13,17 +13,17 @@ class ProvideTest { @Test void 무료강의인데_수강료가있으면_에러전파() throws CanNotCreateException { assertThatThrownBy(() -> { - new Provide(ProvideType.FREE, new ProvidePolicy(10, 10)); + new Provide(ProvideType.FREE, new ProvidePolicy(10, 10L)); }).isInstanceOf(CanNotCreateException.class) .hasMessage("강의타입과 정책이 일치하지 않습니다"); } @Test void 유료강의에_수강신청한다() throws Exception { - Provide provide = new Provide(ProvideType.PAID, new ProvidePolicy(10, 5)); + Provide provide = new Provide(ProvideType.PAID, new ProvidePolicy(10, 5L)); assertThatNoException().isThrownBy(() -> { - provide.applyPaid(8, 5); + provide.applyPaid(8, 5L); }); } @@ -31,7 +31,7 @@ class ProvideTest { void 무료강의에_지불_후_수강신청한다() throws Exception { Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); assertThatThrownBy(() -> { - provide.applyPaid(8, 5); + provide.applyPaid(8, 5L); }).isInstanceOf(CanNotJoinException.class) .hasMessage("유료 강의는 결제를 해야한다"); } diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 4f5c93059..77ea12293 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -36,7 +36,7 @@ class SessionTest { new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), new SessionStatus(SessionStatusType.RECRUITING), - new Provide(ProvideType.PAID, new ProvidePolicy(10, 10)), + new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)), 5, LocalDateTime.now(), null @@ -68,7 +68,7 @@ class SessionTest { new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Provide(ProvideType.PAID, new ProvidePolicy(10, 10)) + new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)) ); }); } @@ -81,7 +81,7 @@ class SessionTest { @Test void 유료_session을_수강신청한다() throws Exception { assertThatNoException().isThrownBy(() -> { - paidSession.applyPaidSession(10); + paidSession.applyPaidSession(10L); }); } From 7771c41d9bf46fb3a4f021b8e534c2ceb0b7ece4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 01:43:39 +0900 Subject: [PATCH 15/34] =?UTF-8?q?feat=20:=20Course=20=EC=97=90=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=A0=84=ED=8C=8C=20=EB=B0=8F=20=EC=88=98=EA=B0=95?= =?UTF-8?q?=EC=8B=A0=EC=B2=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Course.java | 78 ++++++++++++------- .../nextstep/courses/domain/CourseTest.java | 77 ++++++++++++++++++ 2 files changed, 129 insertions(+), 26 deletions(-) create mode 100644 src/test/java/nextstep/courses/domain/CourseTest.java diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index 0f6971604..8ca73f1ce 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -1,31 +1,35 @@ package nextstep.courses.domain; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import nextstep.courses.CanNotJoinException; -public class Course { - private Long id; - - private String title; - - private Long creatorId; - - private LocalDateTime createdAt; - - private LocalDateTime updatedAt; - - public Course() { - } - +public class Course extends Base { + + private final Long id; + private final String title; + private final Long creatorId; + private final List sessions; + public Course(String title, Long creatorId) { - this(0L, title, creatorId, LocalDateTime.now(), null); + this(0L, title, creatorId, new ArrayList<>(), LocalDateTime.now(), null); } - + + public Course(String title, Long creatorId, List sessions) { + this(0L, title, creatorId, sessions, LocalDateTime.now(), null); + } + public Course(Long id, String title, Long creatorId, LocalDateTime createdAt, LocalDateTime updatedAt) { + this(0L, title, creatorId, new ArrayList<>(), LocalDateTime.now(), null); + } + + public Course(Long id, String title, Long creatorId, List sessions, LocalDateTime createdAt, LocalDateTime updatedAt) { + super(createdAt, updatedAt); this.id = id; this.title = title; this.creatorId = creatorId; - this.createdAt = createdAt; - this.updatedAt = updatedAt; + this.sessions = sessions; } public String getTitle() { @@ -37,17 +41,39 @@ public Long getCreatorId() { } public LocalDateTime getCreatedAt() { - return createdAt; + return super.createdDate; } - + + public List getSessions() { + return sessions; + } + @Override public String toString() { return "Course{" + - "id=" + id + - ", title='" + title + '\'' + - ", creatorId=" + creatorId + - ", createdAt=" + createdAt + - ", updatedAt=" + updatedAt + - '}'; + "id=" + id + + ", title='" + title + '\'' + + ", creatorId=" + creatorId + + ", sessions=" + sessions + + '}'; + } + + public void apply(long sessionId, Long amount) throws CanNotJoinException { + Session session = findToApplySession(sessionId); + if(amount == null) { + session.applyFreeSession(); + return; + } + session.applyPaidSession(amount); + } + + private Session findToApplySession(long sessionId) throws CanNotJoinException { + for(Session session: sessions) { + if(session.isSameSessionId(sessionId)) { + return session; + } + } + throw new CanNotJoinException("신청하려는 강의가 존재하지 않습니다"); } + } diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java new file mode 100644 index 000000000..76292a438 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -0,0 +1,77 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import nextstep.courses.CanNotJoinException; +import nextstep.courses.enumerate.CoverImageType; +import nextstep.courses.enumerate.ProvideType; +import nextstep.courses.enumerate.SessionStatusType; +import org.junit.jupiter.api.Test; + +class CourseTest { + + public static final Session freeSession; + public static final Session paidSession; + + static { + try { + freeSession = new Session( + 1L, + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new SessionStatus(SessionStatusType.RECRUITING), + new Provide(ProvideType.FREE), + 5, + LocalDateTime.now(), + null + ); + + paidSession = new Session( + 2L, + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new SessionStatus(SessionStatusType.RECRUITING), + new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)), + 5, + LocalDateTime.now(), + null + ); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + @Test + void 수강신청하는_session이_없으면_예외전파() { + Course course = new Course("title", 1L, List.of(freeSession, paidSession)); + assertThatThrownBy(() -> { + course.apply(3L, null); + }).isInstanceOf(CanNotJoinException.class) + .hasMessage("신청하려는 강의가 존재하지 않습니다"); + } + + @Test + void 무료강의_수강신청() { + Course course = new Course("title", 1L, List.of(freeSession, paidSession)); + assertThatNoException().isThrownBy(() -> { + course.apply(1L, null); + }); + } + + @Test + void 유료강의_수강신청() { + Course course = new Course("title", 1L, List.of(freeSession, paidSession)); + assertThatNoException().isThrownBy(() -> { + course.apply(2L, 10L); + }); + } + +} \ No newline at end of file From 4d2a1b9f615ef66f31a9d69d5367139fc7f065e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 10:34:57 +0900 Subject: [PATCH 16/34] =?UTF-8?q?refactor=20:=20=EC=88=98=EA=B0=95?= =?UTF-8?q?=EC=8B=A0=EC=B2=AD=20=EC=88=98=EA=B0=95=EC=83=9D=20=EC=88=98?= =?UTF-8?q?=EA=B0=80=20=EC=95=84=EB=8B=88=EB=9D=BC=20=EC=8B=A0=EC=B2=AD=20?= =?UTF-8?q?=EC=9E=90=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EB=B0=9B?= =?UTF-8?q?=EA=B2=8C=EB=81=94=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Course.java | 6 ++--- .../java/nextstep/courses/domain/Session.java | 24 ++++++++++++------- .../nextstep/courses/domain/CourseTest.java | 11 +++++---- .../nextstep/courses/domain/SessionTest.java | 12 ++++++---- 4 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index 8ca73f1ce..00e4f2e81 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -58,13 +58,13 @@ public String toString() { '}'; } - public void apply(long sessionId, Long amount) throws CanNotJoinException { + public void apply(long userId, long sessionId, Long amount) throws CanNotJoinException { Session session = findToApplySession(sessionId); if(amount == null) { - session.applyFreeSession(); + session.applyFreeSession(userId); return; } - session.applyPaidSession(amount); + session.applyPaidSession(userId, amount); } private Session findToApplySession(long sessionId) throws CanNotJoinException { diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index a3011d430..844061ade 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -1,6 +1,8 @@ package nextstep.courses.domain; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.SessionStatusType; @@ -14,13 +16,13 @@ public class Session extends Base { private final CoverImage coverImage; private final SessionStatus status; private final Provide provide; - private int enrolledCount; + private final List enrolledUsers; public Session(String creatorId, SessionBody body, Duration duration, CoverImage coverImage, Provide provide) { - this(0L, creatorId, body, duration, coverImage, new SessionStatus(SessionStatusType.PREPARATION), provide, 0, LocalDateTime.now(), null); + this(0L, creatorId, body, duration, coverImage, new SessionStatus(SessionStatusType.PREPARATION), provide, List.of(), LocalDateTime.now(), null); } - public Session(Long id, String creatorId, SessionBody body, Duration duration, CoverImage coverImage, SessionStatus status, Provide provide, int enrolledCount, LocalDateTime createdDate, LocalDateTime updatedDate) { + public Session(Long id, String creatorId, SessionBody body, Duration duration, CoverImage coverImage, SessionStatus status, Provide provide, List enrolledUsers, LocalDateTime createdDate, LocalDateTime updatedDate) { super(createdDate, updatedDate); this.id = id; this.creatorId = creatorId; @@ -29,22 +31,26 @@ public Session(Long id, String creatorId, SessionBody body, Duration duration, C this.coverImage = coverImage; this.status = status; this.provide = provide; - this.enrolledCount = enrolledCount; + this.enrolledUsers = new ArrayList<>(enrolledUsers); } - public void applyFreeSession() throws CanNotJoinException { + public void applyFreeSession(Long userId) throws CanNotJoinException { status.isApplyStatus(); provide.applyFree(); - enrolledCount++; + registerUserId(userId); } - public void applyPaidSession(Long amount) throws CanNotJoinException { + public void applyPaidSession(Long userId, Long amount) throws CanNotJoinException { status.isApplyStatus(); - provide.applyPaid(this.enrolledCount, amount); - enrolledCount++; + provide.applyPaid(this.enrolledUsers.size(), amount); + registerUserId(userId); } public boolean isSameSessionId(Long id) { return Objects.equals(this.id, id); } + + private void registerUserId(Long userId) { + this.enrolledUsers.add(userId); + } } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 76292a438..6e87b7cf1 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -10,6 +10,7 @@ import nextstep.courses.enumerate.CoverImageType; import nextstep.courses.enumerate.ProvideType; import nextstep.courses.enumerate.SessionStatusType; +import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; class CourseTest { @@ -27,7 +28,7 @@ class CourseTest { new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), new SessionStatus(SessionStatusType.RECRUITING), new Provide(ProvideType.FREE), - 5, + List.of(1L, 2L, 3L, 4L, 5L), LocalDateTime.now(), null ); @@ -40,7 +41,7 @@ class CourseTest { new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), new SessionStatus(SessionStatusType.RECRUITING), new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)), - 5, + List.of(1L, 2L, 3L, 4L, 5L), LocalDateTime.now(), null ); @@ -53,7 +54,7 @@ class CourseTest { void 수강신청하는_session이_없으면_예외전파() { Course course = new Course("title", 1L, List.of(freeSession, paidSession)); assertThatThrownBy(() -> { - course.apply(3L, null); + course.apply(NsUserTest.JAVAJIGI.getId(), 3L, null); }).isInstanceOf(CanNotJoinException.class) .hasMessage("신청하려는 강의가 존재하지 않습니다"); } @@ -62,7 +63,7 @@ class CourseTest { void 무료강의_수강신청() { Course course = new Course("title", 1L, List.of(freeSession, paidSession)); assertThatNoException().isThrownBy(() -> { - course.apply(1L, null); + course.apply(NsUserTest.JAVAJIGI.getId(), 1L, null); }); } @@ -70,7 +71,7 @@ class CourseTest { void 유료강의_수강신청() { Course course = new Course("title", 1L, List.of(freeSession, paidSession)); assertThatNoException().isThrownBy(() -> { - course.apply(2L, 10L); + course.apply(NsUserTest.SANJIGI.getId(), 2L, 10L); }); } diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 77ea12293..8ac9f20ac 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -4,9 +4,11 @@ import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.List; import nextstep.courses.enumerate.CoverImageType; import nextstep.courses.enumerate.ProvideType; import nextstep.courses.enumerate.SessionStatusType; +import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; class SessionTest { @@ -24,7 +26,7 @@ class SessionTest { new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), new SessionStatus(SessionStatusType.RECRUITING), new Provide(ProvideType.FREE), - 5, + List.of(11L, 12L, 13L, 14L, 15L), LocalDateTime.now(), null ); @@ -37,7 +39,7 @@ class SessionTest { new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), new SessionStatus(SessionStatusType.RECRUITING), new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)), - 5, + List.of(11L, 12L, 13L, 14L, 15L), LocalDateTime.now(), null ); @@ -75,13 +77,15 @@ class SessionTest { @Test void 무료_session을_수강신청한다() throws Exception { - assertThatNoException().isThrownBy(freeSession::applyFreeSession); + assertThatNoException().isThrownBy(() -> { + freeSession.applyFreeSession(NsUserTest.JAVAJIGI.getId()); + }); } @Test void 유료_session을_수강신청한다() throws Exception { assertThatNoException().isThrownBy(() -> { - paidSession.applyPaidSession(10L); + paidSession.applyPaidSession(NsUserTest.JAVAJIGI.getId(), 10L); }); } From 8ed18655a3661ff5c65f627cea5aa0b5eaab744e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 20:12:12 +0900 Subject: [PATCH 17/34] =?UTF-8?q?feat=20:=20=EA=B2=B0=EC=A0=9C=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EB=B6=99=EC=9D=B4=EA=B3=A0,=20=ED=95=AD=EC=83=81?= =?UTF-8?q?=20=EA=B2=B0=EC=A0=9C=EB=90=9C=EA=B2=83=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Course.java | 12 ++++++-- .../java/nextstep/courses/domain/Provide.java | 8 +++-- .../courses/domain/ProvidePolicy.java | 5 ++-- .../java/nextstep/courses/domain/Session.java | 9 ++++-- .../courses/service/CourseService.java | 29 +++++++++++++++++++ .../nextstep/payments/domain/Payment.java | 9 ++++++ .../nextstep/courses/domain/CourseTest.java | 10 ++++++- .../courses/domain/ProvidePolicyTest.java | 12 ++++---- .../nextstep/courses/domain/ProvideTest.java | 5 ++-- .../nextstep/courses/domain/SessionTest.java | 3 +- 10 files changed, 83 insertions(+), 19 deletions(-) create mode 100644 src/main/java/nextstep/courses/service/CourseService.java diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index 00e4f2e81..5216c5f5b 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import nextstep.courses.CanNotJoinException; +import nextstep.payments.domain.Payment; public class Course extends Base { @@ -58,13 +59,13 @@ public String toString() { '}'; } - public void apply(long userId, long sessionId, Long amount) throws CanNotJoinException { + public void apply(long userId, long sessionId, Payment payment) throws CanNotJoinException { Session session = findToApplySession(sessionId); - if(amount == null) { + if(payment == null) { session.applyFreeSession(userId); return; } - session.applyPaidSession(userId, amount); + session.applyPaidSession(userId, payment); } private Session findToApplySession(long sessionId) throws CanNotJoinException { @@ -76,4 +77,9 @@ private Session findToApplySession(long sessionId) throws CanNotJoinException { throw new CanNotJoinException("신청하려는 강의가 존재하지 않습니다"); } + public boolean isPaidSession(Long sessionId) throws CanNotJoinException { + Session session = findToApplySession(sessionId); + return session.isPaidSession(); + } + } diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java index a5cb0c69e..a10f75288 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -3,6 +3,7 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.ProvideType; +import nextstep.payments.domain.Payment; public class Provide { @@ -25,12 +26,12 @@ private void validate(ProvideType type, ProvidePolicy policy) throws CanNotCreat } } - public void applyPaid(int enrolledCount, Long pay) throws CanNotJoinException { + public void applyPaid(int enrolledCount, Payment payment) throws CanNotJoinException { if(this.type == ProvideType.FREE) { throw new CanNotJoinException("유료 강의는 결제를 해야한다"); } policy.isAvailableEnroll(enrolledCount); - policy.isCorrectPay(pay); + policy.isCorrectPay(payment); } public void applyFree() throws CanNotJoinException { @@ -39,4 +40,7 @@ public void applyFree() throws CanNotJoinException { } } + public boolean isPaid() { + return this.type == ProvideType.PAID; + } } diff --git a/src/main/java/nextstep/courses/domain/ProvidePolicy.java b/src/main/java/nextstep/courses/domain/ProvidePolicy.java index d963436f5..13b4401fc 100644 --- a/src/main/java/nextstep/courses/domain/ProvidePolicy.java +++ b/src/main/java/nextstep/courses/domain/ProvidePolicy.java @@ -3,6 +3,7 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.ProvideType; +import nextstep.payments.domain.Payment; public class ProvidePolicy { @@ -36,11 +37,11 @@ private static boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Long tuiti return maxEnrollment == null && tuitionFee != null; } - public void isCorrectPay(Long pay) throws CanNotJoinException { + public void isCorrectPay(Payment payment) throws CanNotJoinException { if(this.tuitionFee == null) { throw new CanNotJoinException("무료 강의는 지불할 수 없다"); } - if(this.tuitionFee != pay) { + if(payment.isNotSameAmount(this.tuitionFee)) { throw new CanNotJoinException("지불한 금액과 수강료 금액이 다르다"); } } diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 844061ade..0af285adb 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -6,6 +6,7 @@ import java.util.Objects; import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.SessionStatusType; +import nextstep.payments.domain.Payment; public class Session extends Base { @@ -40,9 +41,9 @@ public void applyFreeSession(Long userId) throws CanNotJoinException { registerUserId(userId); } - public void applyPaidSession(Long userId, Long amount) throws CanNotJoinException { + public void applyPaidSession(Long userId, Payment payment) throws CanNotJoinException { status.isApplyStatus(); - provide.applyPaid(this.enrolledUsers.size(), amount); + provide.applyPaid(this.enrolledUsers.size(), payment); registerUserId(userId); } @@ -53,4 +54,8 @@ public boolean isSameSessionId(Long id) { private void registerUserId(Long userId) { this.enrolledUsers.add(userId); } + + public boolean isPaidSession() { + return provide.isPaid(); + } } \ No newline at end of file diff --git a/src/main/java/nextstep/courses/service/CourseService.java b/src/main/java/nextstep/courses/service/CourseService.java new file mode 100644 index 000000000..ec8bb2353 --- /dev/null +++ b/src/main/java/nextstep/courses/service/CourseService.java @@ -0,0 +1,29 @@ +package nextstep.courses.service; + +import javax.annotation.Resource; +import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.Course; +import nextstep.courses.domain.CourseRepository; +import nextstep.payments.domain.Payment; +import nextstep.payments.service.PaymentService; +import nextstep.users.domain.NsUser; +import org.springframework.transaction.annotation.Transactional; + +public class CourseService { + + @Resource(name = "courseRepository") + private CourseRepository courseRepository; + + @Transactional + public void apply(NsUser loginUser, long courseId, long sessionId) throws CanNotJoinException { + Course course = courseRepository.findById(courseId); + + Payment payment = null; + if(course.isPaidSession(sessionId)) { + payment = new PaymentService().payment("id"); + } + course.apply(loginUser.getId(), sessionId, payment); + courseRepository.save(course); + } + +} diff --git a/src/main/java/nextstep/payments/domain/Payment.java b/src/main/java/nextstep/payments/domain/Payment.java index 57d833f85..3aa24f044 100644 --- a/src/main/java/nextstep/payments/domain/Payment.java +++ b/src/main/java/nextstep/payments/domain/Payment.java @@ -18,6 +18,10 @@ public class Payment { public Payment() { } + + public Payment(Payment payment) { + this(payment.id, payment.sessionId, payment.nsUserId, payment.amount); + } public Payment(String id, Long sessionId, Long nsUserId, Long amount) { this.id = id; @@ -26,4 +30,9 @@ public Payment(String id, Long sessionId, Long nsUserId, Long amount) { this.amount = amount; this.createdAt = LocalDateTime.now(); } + + public boolean isNotSameAmount(Long tuitionFee) { + // 항상 false 리턴 (결제는 이미 완료된 것으로 가정) + return false; + } } diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 6e87b7cf1..17fb7604d 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -1,5 +1,6 @@ package nextstep.courses.domain; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -10,6 +11,7 @@ import nextstep.courses.enumerate.CoverImageType; import nextstep.courses.enumerate.ProvideType; import nextstep.courses.enumerate.SessionStatusType; +import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; @@ -71,8 +73,14 @@ class CourseTest { void 유료강의_수강신청() { Course course = new Course("title", 1L, List.of(freeSession, paidSession)); assertThatNoException().isThrownBy(() -> { - course.apply(NsUserTest.SANJIGI.getId(), 2L, 10L); + course.apply(NsUserTest.SANJIGI.getId(), 2L, new Payment()); }); } + @Test + void 해당하는_강의가_유료_강의인지_찾는다() throws CanNotJoinException { + Course course = new Course("title", 1L, List.of(freeSession, paidSession)); + assertThat(course.isPaidSession(2L)).isTrue(); + } + } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java index cc82e8051..b1151c2fc 100644 --- a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java +++ b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java @@ -1,9 +1,11 @@ package nextstep.courses.domain; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; +import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; class ProvidePolicyTest { @@ -24,18 +26,16 @@ class ProvidePolicyTest { @Test void 유료인데_수강료와_지불금액이_다르면_에러전파() throws Exception { - ProvidePolicy providePolicy = new ProvidePolicy(10, 10L); - assertThatThrownBy(() -> { - providePolicy.isCorrectPay(11L); - }).isInstanceOf(CanNotJoinException.class) - .hasMessage("지불한 금액과 수강료 금액이 다르다"); + assertThatNoException().isThrownBy(() -> { + new ProvidePolicy(10, 10L).isCorrectPay(new Payment()); + }); } @Test void 무료인데_수강료_납부하면_에러전파() throws Exception { ProvidePolicy providePolicy = new ProvidePolicy(); assertThatThrownBy(() -> { - providePolicy.isCorrectPay(10L); + providePolicy.isCorrectPay(new Payment()); }).isInstanceOf(CanNotJoinException.class) .hasMessage("무료 강의는 지불할 수 없다"); } diff --git a/src/test/java/nextstep/courses/domain/ProvideTest.java b/src/test/java/nextstep/courses/domain/ProvideTest.java index 407c12dbc..eab150b7e 100644 --- a/src/test/java/nextstep/courses/domain/ProvideTest.java +++ b/src/test/java/nextstep/courses/domain/ProvideTest.java @@ -6,6 +6,7 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.ProvideType; +import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; class ProvideTest { @@ -23,7 +24,7 @@ class ProvideTest { Provide provide = new Provide(ProvideType.PAID, new ProvidePolicy(10, 5L)); assertThatNoException().isThrownBy(() -> { - provide.applyPaid(8, 5L); + provide.applyPaid(8, new Payment()); }); } @@ -31,7 +32,7 @@ class ProvideTest { void 무료강의에_지불_후_수강신청한다() throws Exception { Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); assertThatThrownBy(() -> { - provide.applyPaid(8, 5L); + provide.applyPaid(8, new Payment()); }).isInstanceOf(CanNotJoinException.class) .hasMessage("유료 강의는 결제를 해야한다"); } diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 8ac9f20ac..98fe0370a 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -8,6 +8,7 @@ import nextstep.courses.enumerate.CoverImageType; import nextstep.courses.enumerate.ProvideType; import nextstep.courses.enumerate.SessionStatusType; +import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; @@ -85,7 +86,7 @@ class SessionTest { @Test void 유료_session을_수강신청한다() throws Exception { assertThatNoException().isThrownBy(() -> { - paidSession.applyPaidSession(NsUserTest.JAVAJIGI.getId(), 10L); + paidSession.applyPaidSession(NsUserTest.JAVAJIGI.getId(), new Payment()); }); } From 8f33b9aae5917f8952b0748690ab1faac910ad48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 20:41:23 +0900 Subject: [PATCH 18/34] =?UTF-8?q?refactor=20:=20EnrolledUsers,=20Sessions?= =?UTF-8?q?=20=EC=9D=BC=EA=B8=89=EC=BB=AC=EB=A0=89=EC=85=98=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Course.java | 26 +++----- .../courses/domain/EnrolledUsers.java | 37 ++++++++++++ .../java/nextstep/courses/domain/Session.java | 22 +++---- .../nextstep/courses/domain/Sessions.java | 32 ++++++++++ .../nextstep/courses/domain/CourseTest.java | 4 +- .../courses/domain/EnrolledUsersTest.java | 28 +++++++++ .../nextstep/courses/domain/sessionsTest.java | 60 +++++++++++++++++++ 7 files changed, 178 insertions(+), 31 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/EnrolledUsers.java create mode 100644 src/main/java/nextstep/courses/domain/Sessions.java create mode 100644 src/test/java/nextstep/courses/domain/EnrolledUsersTest.java create mode 100644 src/test/java/nextstep/courses/domain/sessionsTest.java diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index 5216c5f5b..d56459bbb 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -1,7 +1,6 @@ package nextstep.courses.domain; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; import nextstep.courses.CanNotJoinException; import nextstep.payments.domain.Payment; @@ -11,21 +10,21 @@ public class Course extends Base { private final Long id; private final String title; private final Long creatorId; - private final List sessions; + private final Sessions sessions; public Course(String title, Long creatorId) { - this(0L, title, creatorId, new ArrayList<>(), LocalDateTime.now(), null); + this(0L, title, creatorId, new Sessions(), LocalDateTime.now(), null); } public Course(String title, Long creatorId, List sessions) { - this(0L, title, creatorId, sessions, LocalDateTime.now(), null); + this(0L, title, creatorId, new Sessions(sessions), LocalDateTime.now(), null); } public Course(Long id, String title, Long creatorId, LocalDateTime createdAt, LocalDateTime updatedAt) { - this(0L, title, creatorId, new ArrayList<>(), LocalDateTime.now(), null); + this(0L, title, creatorId, new Sessions(), LocalDateTime.now(), null); } - public Course(Long id, String title, Long creatorId, List sessions, LocalDateTime createdAt, LocalDateTime updatedAt) { + public Course(Long id, String title, Long creatorId, Sessions sessions, LocalDateTime createdAt, LocalDateTime updatedAt) { super(createdAt, updatedAt); this.id = id; this.title = title; @@ -45,7 +44,7 @@ public LocalDateTime getCreatedAt() { return super.createdDate; } - public List getSessions() { + public Sessions getSessions() { return sessions; } @@ -60,7 +59,7 @@ public String toString() { } public void apply(long userId, long sessionId, Payment payment) throws CanNotJoinException { - Session session = findToApplySession(sessionId); + Session session = sessions.findToApplySession(sessionId); if(payment == null) { session.applyFreeSession(userId); return; @@ -68,17 +67,8 @@ public void apply(long userId, long sessionId, Payment payment) throws CanNotJoi session.applyPaidSession(userId, payment); } - private Session findToApplySession(long sessionId) throws CanNotJoinException { - for(Session session: sessions) { - if(session.isSameSessionId(sessionId)) { - return session; - } - } - throw new CanNotJoinException("신청하려는 강의가 존재하지 않습니다"); - } - public boolean isPaidSession(Long sessionId) throws CanNotJoinException { - Session session = findToApplySession(sessionId); + Session session = sessions.findToApplySession(sessionId); return session.isPaidSession(); } diff --git a/src/main/java/nextstep/courses/domain/EnrolledUsers.java b/src/main/java/nextstep/courses/domain/EnrolledUsers.java new file mode 100644 index 000000000..7b41fef54 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/EnrolledUsers.java @@ -0,0 +1,37 @@ +package nextstep.courses.domain; + +import java.util.ArrayList; +import java.util.List; +import nextstep.courses.CanNotJoinException; + +public class EnrolledUsers { + + private final List enrolledUserList; + + public EnrolledUsers() { + this(List.of()); + } + + public EnrolledUsers(Long... enrolledUserList) { + this(List.of(enrolledUserList)); + } + + public EnrolledUsers(List enrolledUserList) { + this.enrolledUserList = new ArrayList<>(enrolledUserList); + } + + public void registerUserId(Long userId) throws CanNotJoinException { + this.alreadyRegisterUser(userId); + this.enrolledUserList.add(userId); + } + + private void alreadyRegisterUser(Long userId) throws CanNotJoinException { + if(enrolledUserList.contains(userId)) { + throw new CanNotJoinException("이미 수강신청이 완료된 유저입니다"); + } + } + + public int getSize() { + return this.enrolledUserList.size(); + } +} diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 0af285adb..a05f6a8f1 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -1,7 +1,6 @@ package nextstep.courses.domain; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; import java.util.Objects; import nextstep.courses.CanNotJoinException; @@ -17,13 +16,17 @@ public class Session extends Base { private final CoverImage coverImage; private final SessionStatus status; private final Provide provide; - private final List enrolledUsers; + private final EnrolledUsers enrolledUsers; public Session(String creatorId, SessionBody body, Duration duration, CoverImage coverImage, Provide provide) { - this(0L, creatorId, body, duration, coverImage, new SessionStatus(SessionStatusType.PREPARATION), provide, List.of(), LocalDateTime.now(), null); + this(0L, creatorId, body, duration, coverImage, new SessionStatus(SessionStatusType.PREPARATION), provide, new EnrolledUsers(), LocalDateTime.now(), null); } - public Session(Long id, String creatorId, SessionBody body, Duration duration, CoverImage coverImage, SessionStatus status, Provide provide, List enrolledUsers, LocalDateTime createdDate, LocalDateTime updatedDate) { + public Session(Long id, String code, SessionBody body, Duration duration, CoverImage coverImage, SessionStatus status, Provide provide, List enrolledUserIds, LocalDateTime createdAt, LocalDateTime updatedAt) { + this(id, code, body, duration, coverImage, status, provide, new EnrolledUsers(enrolledUserIds), createdAt, updatedAt); + } + + public Session(Long id, String creatorId, SessionBody body, Duration duration, CoverImage coverImage, SessionStatus status, Provide provide, EnrolledUsers enrolledUsers, LocalDateTime createdDate, LocalDateTime updatedDate) { super(createdDate, updatedDate); this.id = id; this.creatorId = creatorId; @@ -32,28 +35,25 @@ public Session(Long id, String creatorId, SessionBody body, Duration duration, C this.coverImage = coverImage; this.status = status; this.provide = provide; - this.enrolledUsers = new ArrayList<>(enrolledUsers); + this.enrolledUsers = enrolledUsers; } public void applyFreeSession(Long userId) throws CanNotJoinException { status.isApplyStatus(); provide.applyFree(); - registerUserId(userId); + enrolledUsers.registerUserId(userId); } public void applyPaidSession(Long userId, Payment payment) throws CanNotJoinException { status.isApplyStatus(); - provide.applyPaid(this.enrolledUsers.size(), payment); - registerUserId(userId); + provide.applyPaid(this.enrolledUsers.getSize(), payment); + enrolledUsers.registerUserId(userId); } public boolean isSameSessionId(Long id) { return Objects.equals(this.id, id); } - private void registerUserId(Long userId) { - this.enrolledUsers.add(userId); - } public boolean isPaidSession() { return provide.isPaid(); diff --git a/src/main/java/nextstep/courses/domain/Sessions.java b/src/main/java/nextstep/courses/domain/Sessions.java new file mode 100644 index 000000000..a6874f0a7 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/Sessions.java @@ -0,0 +1,32 @@ +package nextstep.courses.domain; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import nextstep.courses.CanNotJoinException; + +public class Sessions { + + private final List sessions; + + public Sessions() { + this.sessions = new ArrayList<>(); + } + + public Sessions(Session... sessions) { + this(Arrays.asList(sessions)); + } + + public Sessions(List sessions) { + this.sessions = sessions; + } + + public Session findToApplySession(long sessionId) throws CanNotJoinException { + for(Session session: this.sessions) { + if(session.isSameSessionId(sessionId)) { + return session; + } + } + throw new CanNotJoinException("신청하려는 강의가 존재하지 않습니다"); + } +} diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 17fb7604d..51dd5fe39 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -30,7 +30,7 @@ class CourseTest { new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), new SessionStatus(SessionStatusType.RECRUITING), new Provide(ProvideType.FREE), - List.of(1L, 2L, 3L, 4L, 5L), + List.of(4L, 5L, 6L, 7L, 8L, 9L), LocalDateTime.now(), null ); @@ -43,7 +43,7 @@ class CourseTest { new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), new SessionStatus(SessionStatusType.RECRUITING), new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)), - List.of(1L, 2L, 3L, 4L, 5L), + List.of(4L, 5L, 6L, 7L, 8L, 9L), LocalDateTime.now(), null ); diff --git a/src/test/java/nextstep/courses/domain/EnrolledUsersTest.java b/src/test/java/nextstep/courses/domain/EnrolledUsersTest.java new file mode 100644 index 000000000..498104cfd --- /dev/null +++ b/src/test/java/nextstep/courses/domain/EnrolledUsersTest.java @@ -0,0 +1,28 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import nextstep.courses.CanNotJoinException; +import org.junit.jupiter.api.Test; + +class EnrolledUsersTest { + + @Test + void 이미등록된_회원이다() { + EnrolledUsers enrolledUsers = new EnrolledUsers(List.of(1L, 2L, 3L)); + assertThatThrownBy(() -> { + enrolledUsers.registerUserId(3L); + } + ).isInstanceOf(CanNotJoinException.class) + .hasMessage("이미 수강신청이 완료된 유저입니다"); + } + + @Test + void 등록고객에_수를_추가한다() throws CanNotJoinException { + EnrolledUsers enrolledUsers = new EnrolledUsers(List.of(1L, 2L, 3L)); + assertThatNoException().isThrownBy(() -> enrolledUsers.registerUserId(4L)); + } + +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/sessionsTest.java b/src/test/java/nextstep/courses/domain/sessionsTest.java new file mode 100644 index 000000000..793af03cb --- /dev/null +++ b/src/test/java/nextstep/courses/domain/sessionsTest.java @@ -0,0 +1,60 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import nextstep.courses.CanNotJoinException; +import nextstep.courses.enumerate.CoverImageType; +import nextstep.courses.enumerate.ProvideType; +import nextstep.courses.enumerate.SessionStatusType; +import org.junit.jupiter.api.Test; + +class sessionsTest { + + public static final Session freeSession; + public static final Session paidSession; + + static { + try { + freeSession = new Session( + 1L, + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new SessionStatus(SessionStatusType.RECRUITING), + new Provide(ProvideType.FREE), + List.of(1L, 2L, 3L, 4L, 5L), + LocalDateTime.now(), + null + ); + + paidSession = new Session( + 2L, + "1", + new SessionBody("title", "content"), + new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), + new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), + new SessionStatus(SessionStatusType.RECRUITING), + new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)), + List.of(1L, 2L, 3L, 4L, 5L), + LocalDateTime.now(), + null + ); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + + @Test + void 찾고자하는_세션이_없으면_에러전파() throws CanNotJoinException { + assertThatThrownBy(() -> { + new Sessions(freeSession, paidSession) + .findToApplySession(3L); + }) + .isInstanceOf(CanNotJoinException.class) + .hasMessage("신청하려는 강의가 존재하지 않습니다"); + } +} \ No newline at end of file From 00ab466935b1a5575605495f10ba7339184961dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 21:26:27 +0900 Subject: [PATCH 19/34] =?UTF-8?q?refactor=20:=20=EC=A0=95=EC=9B=90?= =?UTF-8?q?=EC=B4=88=EA=B3=BC=20=EB=A1=9C=EC=A7=81=20EnrolledUsers=20?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EA=B4=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/EnrolledUsers.java | 10 ++++++++-- src/main/java/nextstep/courses/domain/Provide.java | 4 ++-- .../java/nextstep/courses/domain/ProvidePolicy.java | 4 ++-- src/main/java/nextstep/courses/domain/Session.java | 2 +- .../nextstep/courses/domain/ProvidePolicyTest.java | 4 ++-- src/test/java/nextstep/courses/domain/ProvideTest.java | 4 ++-- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/EnrolledUsers.java b/src/main/java/nextstep/courses/domain/EnrolledUsers.java index 7b41fef54..55a64a2a4 100644 --- a/src/main/java/nextstep/courses/domain/EnrolledUsers.java +++ b/src/main/java/nextstep/courses/domain/EnrolledUsers.java @@ -1,6 +1,7 @@ package nextstep.courses.domain; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import nextstep.courses.CanNotJoinException; @@ -12,6 +13,10 @@ public EnrolledUsers() { this(List.of()); } + public EnrolledUsers(int size) { + this(new ArrayList<>(Collections.nCopies(size, null))); + } + public EnrolledUsers(Long... enrolledUserList) { this(List.of(enrolledUserList)); } @@ -31,7 +36,8 @@ private void alreadyRegisterUser(Long userId) throws CanNotJoinException { } } - public int getSize() { - return this.enrolledUserList.size(); + public boolean isAlreadyExceed(int maxEnrollment) { + return maxEnrollment <= this.enrolledUserList.size(); } + } diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java index a10f75288..f1601d2bd 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -26,11 +26,11 @@ private void validate(ProvideType type, ProvidePolicy policy) throws CanNotCreat } } - public void applyPaid(int enrolledCount, Payment payment) throws CanNotJoinException { + public void applyPaid(EnrolledUsers enrolledUsers, Payment payment) throws CanNotJoinException { if(this.type == ProvideType.FREE) { throw new CanNotJoinException("유료 강의는 결제를 해야한다"); } - policy.isAvailableEnroll(enrolledCount); + policy.isAvailableEnroll(enrolledUsers); policy.isCorrectPay(payment); } diff --git a/src/main/java/nextstep/courses/domain/ProvidePolicy.java b/src/main/java/nextstep/courses/domain/ProvidePolicy.java index 13b4401fc..0aa6345bd 100644 --- a/src/main/java/nextstep/courses/domain/ProvidePolicy.java +++ b/src/main/java/nextstep/courses/domain/ProvidePolicy.java @@ -46,12 +46,12 @@ public void isCorrectPay(Payment payment) throws CanNotJoinException { } } - public void isAvailableEnroll(int enrolledCount) throws CanNotJoinException { + public void isAvailableEnroll(EnrolledUsers enrolledUsers) throws CanNotJoinException { if(this.maxEnrollment == null) { throw new CanNotJoinException("무료강의는 정원이 없다"); } - if(this.maxEnrollment <= enrolledCount) { + if(enrolledUsers.isAlreadyExceed(maxEnrollment)) { throw new CanNotJoinException("이미 정원을 초과했다"); } } diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index a05f6a8f1..2b60c63d4 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -46,7 +46,7 @@ public void applyFreeSession(Long userId) throws CanNotJoinException { public void applyPaidSession(Long userId, Payment payment) throws CanNotJoinException { status.isApplyStatus(); - provide.applyPaid(this.enrolledUsers.getSize(), payment); + provide.applyPaid(this.enrolledUsers, payment); enrolledUsers.registerUserId(userId); } diff --git a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java index b1151c2fc..d28682738 100644 --- a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java +++ b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java @@ -44,7 +44,7 @@ class ProvidePolicyTest { void 수강신청_인원이_초과하면_에러전파() throws Exception { ProvidePolicy providePolicy = new ProvidePolicy(10, 10L); assertThatThrownBy(() -> { - providePolicy.isAvailableEnroll(10); + providePolicy.isAvailableEnroll(new EnrolledUsers(10)); }).isInstanceOf(CanNotJoinException.class) .hasMessage("이미 정원을 초과했다"); } @@ -53,7 +53,7 @@ class ProvidePolicyTest { void 무료강의인데_수강신청_시_정원체크하면_에러전파() throws Exception { ProvidePolicy providePolicy = new ProvidePolicy(); assertThatThrownBy(() -> { - providePolicy.isAvailableEnroll(10); + providePolicy.isAvailableEnroll(new EnrolledUsers(10)); }).isInstanceOf(CanNotJoinException.class) .hasMessage("무료강의는 정원이 없다"); } diff --git a/src/test/java/nextstep/courses/domain/ProvideTest.java b/src/test/java/nextstep/courses/domain/ProvideTest.java index eab150b7e..74528da76 100644 --- a/src/test/java/nextstep/courses/domain/ProvideTest.java +++ b/src/test/java/nextstep/courses/domain/ProvideTest.java @@ -24,7 +24,7 @@ class ProvideTest { Provide provide = new Provide(ProvideType.PAID, new ProvidePolicy(10, 5L)); assertThatNoException().isThrownBy(() -> { - provide.applyPaid(8, new Payment()); + provide.applyPaid(new EnrolledUsers(8), new Payment()); }); } @@ -32,7 +32,7 @@ class ProvideTest { void 무료강의에_지불_후_수강신청한다() throws Exception { Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); assertThatThrownBy(() -> { - provide.applyPaid(8, new Payment()); + provide.applyPaid(new EnrolledUsers(8), new Payment()); }).isInstanceOf(CanNotJoinException.class) .hasMessage("유료 강의는 결제를 해야한다"); } From 1980d14cf8afab6add408c40142b9c192638541a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Tue, 9 Dec 2025 21:27:12 +0900 Subject: [PATCH 20/34] =?UTF-8?q?docs=20:=20=EA=B0=9C=EB=B0=9C=20=EA=B3=BC?= =?UTF-8?q?=EC=A0=95=20=EB=A9=94=EB=AA=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 50e02827d..f9ec9fa11 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,152 @@ - 이유 : 맞다 또한 검증에 대해서도 모두 수행하는것은 바람직하지 않음, 검증은 `Answer` 내부에서 해야함 ## 3차 피드백 - - [x] : `Question` 의 `title`, `contents` 필드를 별도로 `QuestionBody` 로 분리하는 것이 의미 있을까? - 생각컨데 분리는 의마가 없다고 본다. - 그 이유는 : `title`, `contents` 로 분리를 하면은 값을 보관해주는 역할에 불과한 점 - 분리한 객체만의 특별한 도메인 규칙이나 행동이 없는 점 - 때문이다. + +# 2단계 : 수강신청(도메인 모델) + +- DB 테이블 설계 없이 도메인 모델부터 구현하기 + - 도메인 모델은 TDD로 구현 (Service 클래스는 단위 테스트 없이) + +## 기능목록 + +1. 과정(Course)과 강의(Session) + - 과정(Course)은 '기수' 단위 운영 + - 과정에 여러개의 강의(Session) 를 가질 수있음 +2. 강의 기간 + - 시작일과 종료일 가짐 +3. 강의에 커버이미지 가짐 + - 이미지 크기는 1MB 이하 + - 이미지 타입은 gif, jpg(jpeg), png, svg + - 이미지 크기 : width - 300px / height - 200px 이상 + - width / height 비율 3:2 +4. 강의 타입 : '무료 강의' '유료 강의'로 나누어진다 + - 무료 강의 : 최대 수강신청 인원 제한이 없다 + - 유료 강의 : 강의 최대 수강 인원 초과할 수 없음 + - 수강생이 결제한 금액과 수강료가 일치 할 시 수강 신청 가능 +5. 강의 상태 : '준비중', '모집중', '종료' + - 모집 중 일때 강의 수강신청 가능 +6. 결제 + - 유료 강의 결제는 이미 완료된 것으로 가정 하고 이후 과정 구현함 + - 결제 완료 한 결제정보는 payments 모듈로 관리, 결제정보는 Payment 객체에 담겨 반환 + +## 객체 설계 + +### 객체 역할 + +- Course : 기수별 session 들의 관리관련 정보 전문가 및 행위 책임자 +- Session : 강의 자체의 전반적인 정보 전문가 및 행위 책임자 +- Duration : 강의의 시작, 종료 관련 정보 전문가 및 행위 책임자 +- CoverImage : 강의의 커버 이미지 관련 정보 전문가 및 행위 책임자 + - CoverImageType +- ProvideType : 강의의 무료, 유료 강의 관련 정보 전문가 및 행위 책임자 +- SessionStatus : 강의의 준비중, 모집 중 같은 정보 전문가 및 행위 책임자 + - SessionStatusType + +### 구현 순서 (작은 도메인 부터) + +Duration → CoverImage → SessionStatus → ProvideType → Session → Course + +### 중요 : 만들어진 강의에 수강신청 하는 것임 + +### 객체 별 기능 사항 + +#### Duration + +- [x] : 종료일이 시작일 보다 뒤에 있을 수없다 +- [x] : 시작일과 종료일이 오늘보다 뒤에 있다 +- [ ] : startDate, endDate 원시 값 포장 + +#### CoverImage + +- [x] : 커버 이미지의 크기는 1MB 이하이다 +- [x] : 이미지 타입은 gif, jpg(jpeg), png, svg 이다 (CoverImageType) +- [x] : 이미지 크기는 width - 300px / height - 200px 이상 이다 +- [x] : width / height 비율 3:2 이다 + +#### SessionStatus + +- [x] : 모집 중 일때 만 강의 수강신청 가능 + +#### Provide + +- [x] : 강의 타입은 무료 강의, 유료 강의 2가지 이다. + - [x] : 수강신청 제한인원은 타입에 존재한다 (규칙) +- [x] : 강의를 수강신청 하면 수강생 수가 올라간다 + - [x] : 클라이언트 코드에서 수강신청 제한인원 받아서 그 수가 넘는지 확인해준다 +- [x] : 지불금액을 보고 금액이 같은지 검증한다 + - [x] : 무료인데 지불하면 안된다. + +##### 객체 분리 필요성 고민 + +1. Provide 를 Free, Paid 로 객체를 나눌 것인가? + - 기대효과 : 각각 다른 규칙에 대해서 정리 가능 + - 예) 무료 : 인원수 제한 X/ 금액 무료 + - 한계점 : 비슷한 형태의 객체가 2개인데, 어떤 강의를 신청하느냐에 따라 요청이 오거나, 불러오는 객체가 달라짐 + +2. enrolledCount, maxEnrollment / tuitionFee, pay 각각 묶을 것인가? + - 기대효과 : 인원수 체크가 손쉽게 됨, 금액을 내야하는지 체크가 가능 / 서로 비슷한 규칙끼리 묶여서 검증 쉬움 + - 한계점 : 최초 고민인 무료인 경우 인원수 제한, 수강료에 대한 통제는 여전히 어려움 + - 규칙 : 그러나 만들어진 각각 객체안에서 무료인 경우 제한 검증 X, 수강료 검증 X 되지 않을까? + - 생성 : 무료인경우 생성자 인자를 생략하기? -> but 결국에 인원수를 0으로 세팅해야함 + +3. enrolledCount, tuitionFee / pay, maxEnrollment 각각 묶을 것인가? + - 기대 효과 : 무료, 유료인 경우에 대한 변칙 적용이 수월함 + - 한계점 : 묶이는 필드끼리 생명주기가 같을지 의문 + - 차라리 현상이 아닌 정해진 생명주기끼리 묶는게 낫지않을까? + - 예) tuitionFee, maxEnrollment (세션자체의 규칙) / enrolledCount, pay (요청 때 마다 변칙) + - 전자는 Session 에서, 후자는 Provide 에서 + +4. tuitionFee, maxEnrollment / pay, enrolledCount 각각 묶을 것인가? + - 기대 효과 : tuitionFee, maxEnrollment 는 상위 클래스 Session 에서 통제함 + - 제약과 현상을 분리함 + - 무료인 경우 0 fee 와 무제한 수강인원에 대한 검증 가능 + - 그리고 억지로 0으로 만들필요 없음 + - 한계점 : 하지만 전자를 결국에 객체로 만들면 0으로 세팅이 필요함 + - 결국에 상단 2번처럼 문제가 + +- 고민 + - 정원을 숫자가 아닌 정책으로 보아야함 + - 무제한 정책은 숫자가 필요없음 + - 제한 정책은 숫자가 필요 + - 정원이 없는것은 null 로 지정 가능 + - DDD 관점에서 '개념 부재' 표현임 (null 보다 의미없는 값(0) 으로 도메인 개념 왜곡이 더큰 문제) + - null 은 인간언어로 표현 가능함 + - 두갈래 고민 + - 2번 : 수강생 수 / 비용 으로 분리 + - 생성 방식에 대한 문제 해결함 -> 고려 가능 + - 도달 여부 쉽게 판단 + - 4번 : 기준 / 준수여부 로 분리 + - 생명주기 비슷 +- 최종 결정 + - 4번: ProvidePolicy / ProvideStatus + - 걱정 : null 로 넣는게 인위적인데 전략패턴을 이용해야할까 싶으면서 오버엔지이너링일까 우려됨 + +#### Session + +- [x] : `Provide` 에게 해당 세션의 제한인원 수 전달해서 남은 자리 조율 +- [x] : 무료, 유료에 따라서 수강신청 메서드 분리 + +#### Course + +- [x] : 신청하는 강의의 id 와 가격을 넣어서 수강신청한다 +- [x] : 수강신청 하려는 session의 id가 없으면 예외전파 + +#### CourseService + +- [x] : 해당 코스의 특정 강의를 조회한다 +- [x] : 조회한 강의를 수강신청한다 + - 무료강의 이면 바로 신청 + - 유료 강의 이면 결제 모듈 조회 후 신청 + - 당연 성공이므로 곧바로 amount 넣기 +- [x] : 조회 성공 후 결과를 저장하기 + +#### 놓치거나 마무리 부분 + +- [x] : 수강신청한 수강생의 정보 넣기 +- [x] : 결제 완료를 기준으로 던지기 +- [x] : 컬렉션을 일급 컬렉션으로 바꾸기 (EnrolledUsers, Sessions) \ No newline at end of file From faf17e1ae10257636d3db2a45104a39ff005e470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Wed, 10 Dec 2025 09:41:14 +0900 Subject: [PATCH 21/34] =?UTF-8?q?refactor=20:=201.=20Base=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A1=9C=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=ED=95=98=EC=97=AC=20=EC=83=81=EC=86=8D?= =?UTF-8?q?=EC=A0=84=EC=9A=A9=EC=9C=BC=EB=A1=9C=EB=A7=8C=20=ED=95=98?= =?UTF-8?q?=EA=B3=A0=20=EC=A7=81=EC=A0=91=20=EC=83=9D=EC=84=B1=EC=9D=80=20?= =?UTF-8?q?=EC=9E=90=EC=8B=9D=EC=9D=B4=20=EB=AA=BB=ED=95=98=EA=B2=8C=20?= =?UTF-8?q?=EB=A7=89=EC=9D=8C=20(=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EC=B2=98=EB=9F=BC=20=EC=82=AC=EC=9A=A9=ED=95=A0=20?= =?UTF-8?q?=EC=9A=B0=EB=A0=A4=20=EB=A7=89=EC=9D=8C)=202.=20Base=20?= =?UTF-8?q?=EC=9D=98=20=ED=95=84=EB=93=9C=EB=A5=BC=20private=20=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=ED=95=B4=20=EC=A7=81=EC=A0=91=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=AA=BB=ED=95=98=EA=B2=8C=20=EB=A7=89=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/nextstep/courses/domain/Base.java | 14 +++++++++++--- src/main/java/nextstep/courses/domain/Course.java | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Base.java b/src/main/java/nextstep/courses/domain/Base.java index 0adb13722..f29567037 100644 --- a/src/main/java/nextstep/courses/domain/Base.java +++ b/src/main/java/nextstep/courses/domain/Base.java @@ -2,10 +2,10 @@ import java.time.LocalDateTime; -public class Base { +public abstract class Base { - protected LocalDateTime createdDate; - protected LocalDateTime updatedDate; + private final LocalDateTime createdDate; + private final LocalDateTime updatedDate; public Base() { this(LocalDateTime.now(), null); @@ -15,4 +15,12 @@ public Base(LocalDateTime createdDate, LocalDateTime updatedDate) { this.createdDate = createdDate; this.updatedDate = updatedDate; } + + protected LocalDateTime getCreatedDate() { + return createdDate; + } + + protected LocalDateTime getUpdatedDate() { + return updatedDate; + } } \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index d56459bbb..ce1c4fde9 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -41,7 +41,7 @@ public Long getCreatorId() { } public LocalDateTime getCreatedAt() { - return super.createdDate; + return super.getCreatedDate(); } public Sessions getSessions() { From d535c7a3ce614600a001bb13a17f56d5cb0c09f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Wed, 10 Dec 2025 09:52:56 +0900 Subject: [PATCH 22/34] =?UTF-8?q?refactor=20:=20CoverImage=20=EC=9D=98=20?= =?UTF-8?q?=EB=A7=8E=EC=9D=80=20=ED=95=84=EB=93=9C=EC=9D=98=20=EC=9B=90?= =?UTF-8?q?=EC=8B=9C=EA=B0=92=EC=9D=84=20=ED=8F=AC=EC=9E=A5=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EA=B4=80=EB=A0=A8=EB=90=9C=20=EA=B2=83=20=EB=81=BC?= =?UTF-8?q?=EB=A6=AC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../nextstep/courses/domain/CoverImage.java | 36 ++++++------------- .../nextstep/courses/domain/Dimensions.java | 32 +++++++++++++++++ .../courses/domain/CoverImageTest.java | 25 ------------- .../courses/domain/DimensionsTest.java | 34 ++++++++++++++++++ 4 files changed, 77 insertions(+), 50 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/Dimensions.java create mode 100644 src/test/java/nextstep/courses/domain/DimensionsTest.java diff --git a/src/main/java/nextstep/courses/domain/CoverImage.java b/src/main/java/nextstep/courses/domain/CoverImage.java index b4fcdd619..3b1c074b9 100644 --- a/src/main/java/nextstep/courses/domain/CoverImage.java +++ b/src/main/java/nextstep/courses/domain/CoverImage.java @@ -5,44 +5,30 @@ public class CoverImage { - public static final double COVER_IMAGE_RATIO = 1.5; public static final int ONE_MEGA_BYTE = 1_000_000; // 1mb 는 1_000_000 byte 로 가정 private final int size; // byte private final CoverImageType type; - private final double width; - private final double height; - private final double ratio; + private final Dimensions dimensions; - public CoverImage(int size, String type, double width, double height) throws CanNotCreateException { - this(size, CoverImageType.valueOfIgnoreCase(type), width, height); + public CoverImage(int size, CoverImageType type, double width, double height) throws CanNotCreateException { + this(size, type, new Dimensions(width, height)); } - public CoverImage(int size, CoverImageType type, double width, double height) throws CanNotCreateException { - validate(size, width, height); + public CoverImage(int size, String type, Dimensions dimensions) throws CanNotCreateException { + this(size, CoverImageType.valueOfIgnoreCase(type), dimensions); + } + + public CoverImage(int size, CoverImageType type, Dimensions dimensions) throws CanNotCreateException { + validate(size); this.size = size; this.type = type; - this.width = width; - this.height = height; - this.ratio = width / height; + this.dimensions = dimensions; } - private void validate(int size, double width, double height) throws CanNotCreateException { + private void validate(int size) throws CanNotCreateException { if(size < ONE_MEGA_BYTE) { throw new CanNotCreateException("커버 이미지의 크기는 1MB 이상이어야 한다"); } - - if(width < 300) { - throw new CanNotCreateException("이미지의 너비(width)는 300px 이상이어야 한다"); - } - - if(height < 200) { - throw new CanNotCreateException("이미지의 높이(height)는 200px 이상이어야 한다"); - } - - if(width / height != COVER_IMAGE_RATIO) { - throw new CanNotCreateException("이미지의 너비(width)와 높이(height)의 비율은 3:2 이어야 한다"); - } - } } diff --git a/src/main/java/nextstep/courses/domain/Dimensions.java b/src/main/java/nextstep/courses/domain/Dimensions.java new file mode 100644 index 000000000..4eff48f35 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/Dimensions.java @@ -0,0 +1,32 @@ +package nextstep.courses.domain; + +import nextstep.courses.CanNotCreateException; + +public class Dimensions { + + public static final double COVER_IMAGE_RATIO = 1.5; + private final double width; + private final double height; + private final double ratio; + + public Dimensions(double width, double height) throws CanNotCreateException { + validate(width, height); + this.width = width; + this.height = height; + this.ratio = width / height; + } + + private void validate(double width, double height) throws CanNotCreateException { + if(width < 300) { + throw new CanNotCreateException("이미지의 너비(width)는 300px 이상이어야 한다"); + } + + if(height < 200) { + throw new CanNotCreateException("이미지의 높이(height)는 200px 이상이어야 한다"); + } + + if(width / height != COVER_IMAGE_RATIO) { + throw new CanNotCreateException("이미지의 너비(width)와 높이(height)의 비율은 3:2 이어야 한다"); + } + } +} diff --git a/src/test/java/nextstep/courses/domain/CoverImageTest.java b/src/test/java/nextstep/courses/domain/CoverImageTest.java index 856638104..9aa17954f 100644 --- a/src/test/java/nextstep/courses/domain/CoverImageTest.java +++ b/src/test/java/nextstep/courses/domain/CoverImageTest.java @@ -15,29 +15,4 @@ class CoverImageTest { }).isInstanceOf(CanNotCreateException.class) .hasMessage("커버 이미지의 크기는 1MB 이상이어야 한다"); } - - @Test - void 커버이미지의_정해진_크기_이하이면_에러전파() { - assertThatThrownBy(() -> { - new CoverImage(1_500_000, CoverImageType.JPEG, 299, 200); - }).isInstanceOf(CanNotCreateException.class) - .hasMessage("이미지의 너비(width)는 300px 이상이어야 한다"); - } - - @Test - void 커버이미지의_정해진_비율이_아니면_에러전파() { - assertThatThrownBy(() -> { - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 199); - }).isInstanceOf(CanNotCreateException.class) - .hasMessage("이미지의 높이(height)는 200px 이상이어야 한다"); - } - - @Test - void 커버이미지의_너비와_높이_비율은_3대2가_아니면_에러전파() { - assertThatThrownBy(() -> { - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 300); - }).isInstanceOf(CanNotCreateException.class) - .hasMessage("이미지의 너비(width)와 높이(height)의 비율은 3:2 이어야 한다"); - } - } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/DimensionsTest.java b/src/test/java/nextstep/courses/domain/DimensionsTest.java new file mode 100644 index 000000000..1669ef7c8 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/DimensionsTest.java @@ -0,0 +1,34 @@ +package nextstep.courses.domain; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import nextstep.courses.CanNotCreateException; +import org.junit.jupiter.api.Test; + +class DimensionsTest { + + @Test + void 커버이미지의_정해진_크기_이하이면_에러전파() { + assertThatThrownBy(() -> { + new Dimensions(299, 200); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("이미지의 너비(width)는 300px 이상이어야 한다"); + } + + @Test + void 커버이미지의_정해진_비율이_아니면_에러전파() { + assertThatThrownBy(() -> { + new Dimensions(300, 199); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("이미지의 높이(height)는 200px 이상이어야 한다"); + } + + @Test + void 커버이미지의_너비와_높이_비율은_3대2가_아니면_에러전파() { + assertThatThrownBy(() -> { + new Dimensions(300, 300); + }).isInstanceOf(CanNotCreateException.class) + .hasMessage("이미지의 너비(width)와 높이(height)의 비율은 3:2 이어야 한다"); + } + +} \ No newline at end of file From 7ff5afb3dd357de9645a03794cce077b79ef80a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Wed, 10 Dec 2025 10:06:15 +0900 Subject: [PATCH 23/34] =?UTF-8?q?refactor=201.=20type=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=EC=9D=80=20enum=20=EB=82=B4=EB=B6=80=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=A7=81=EC=A0=91=20=ED=95=98=EA=B2=8C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?2.=20boolean=20=ED=83=80=EC=9E=85=EC=9D=B4=20=EC=95=84=EB=8B=8C?= =?UTF-8?q?=EB=8D=B0=20is=20=EB=A1=9C=20=EC=8B=9C=EC=9E=91=ED=95=9C=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=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 --- src/main/java/nextstep/courses/domain/Provide.java | 10 +++++----- .../java/nextstep/courses/domain/ProvidePolicy.java | 4 ++-- .../java/nextstep/courses/enumerate/ProvideType.java | 8 ++++++++ .../nextstep/courses/domain/ProvidePolicyTest.java | 8 ++++---- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java index f1601d2bd..a7d4bd142 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -27,20 +27,20 @@ private void validate(ProvideType type, ProvidePolicy policy) throws CanNotCreat } public void applyPaid(EnrolledUsers enrolledUsers, Payment payment) throws CanNotJoinException { - if(this.type == ProvideType.FREE) { + if(this.type.isFree()) { throw new CanNotJoinException("유료 강의는 결제를 해야한다"); } - policy.isAvailableEnroll(enrolledUsers); - policy.isCorrectPay(payment); + policy.validateEnrollment(enrolledUsers); + policy.validatePayment(payment); } public void applyFree() throws CanNotJoinException { - if(this.type == ProvideType.PAID) { + if(this.type.isPaid()) { throw new CanNotJoinException("무료 강의는 결제할 수 없다"); } } public boolean isPaid() { - return this.type == ProvideType.PAID; + return this.type.isPaid(); } } diff --git a/src/main/java/nextstep/courses/domain/ProvidePolicy.java b/src/main/java/nextstep/courses/domain/ProvidePolicy.java index 0aa6345bd..a8949a805 100644 --- a/src/main/java/nextstep/courses/domain/ProvidePolicy.java +++ b/src/main/java/nextstep/courses/domain/ProvidePolicy.java @@ -37,7 +37,7 @@ private static boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Long tuiti return maxEnrollment == null && tuitionFee != null; } - public void isCorrectPay(Payment payment) throws CanNotJoinException { + public void validatePayment(Payment payment) throws CanNotJoinException { if(this.tuitionFee == null) { throw new CanNotJoinException("무료 강의는 지불할 수 없다"); } @@ -46,7 +46,7 @@ public void isCorrectPay(Payment payment) throws CanNotJoinException { } } - public void isAvailableEnroll(EnrolledUsers enrolledUsers) throws CanNotJoinException { + public void validateEnrollment(EnrolledUsers enrolledUsers) throws CanNotJoinException { if(this.maxEnrollment == null) { throw new CanNotJoinException("무료강의는 정원이 없다"); } diff --git a/src/main/java/nextstep/courses/enumerate/ProvideType.java b/src/main/java/nextstep/courses/enumerate/ProvideType.java index 7d68a3895..f2577546b 100644 --- a/src/main/java/nextstep/courses/enumerate/ProvideType.java +++ b/src/main/java/nextstep/courses/enumerate/ProvideType.java @@ -8,4 +8,12 @@ public enum ProvideType { private boolean isExistTuitionFee; ProvideType(String provideType, boolean isExistTuitionFee) {} + + public boolean isFree() { + return this == ProvideType.FREE; + } + + public boolean isPaid() { + return this == ProvideType.PAID; + } } diff --git a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java index d28682738..11fdcecd9 100644 --- a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java +++ b/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java @@ -27,7 +27,7 @@ class ProvidePolicyTest { @Test void 유료인데_수강료와_지불금액이_다르면_에러전파() throws Exception { assertThatNoException().isThrownBy(() -> { - new ProvidePolicy(10, 10L).isCorrectPay(new Payment()); + new ProvidePolicy(10, 10L).validatePayment(new Payment()); }); } @@ -35,7 +35,7 @@ class ProvidePolicyTest { void 무료인데_수강료_납부하면_에러전파() throws Exception { ProvidePolicy providePolicy = new ProvidePolicy(); assertThatThrownBy(() -> { - providePolicy.isCorrectPay(new Payment()); + providePolicy.validatePayment(new Payment()); }).isInstanceOf(CanNotJoinException.class) .hasMessage("무료 강의는 지불할 수 없다"); } @@ -44,7 +44,7 @@ class ProvidePolicyTest { void 수강신청_인원이_초과하면_에러전파() throws Exception { ProvidePolicy providePolicy = new ProvidePolicy(10, 10L); assertThatThrownBy(() -> { - providePolicy.isAvailableEnroll(new EnrolledUsers(10)); + providePolicy.validateEnrollment(new EnrolledUsers(10)); }).isInstanceOf(CanNotJoinException.class) .hasMessage("이미 정원을 초과했다"); } @@ -53,7 +53,7 @@ class ProvidePolicyTest { void 무료강의인데_수강신청_시_정원체크하면_에러전파() throws Exception { ProvidePolicy providePolicy = new ProvidePolicy(); assertThatThrownBy(() -> { - providePolicy.isAvailableEnroll(new EnrolledUsers(10)); + providePolicy.validateEnrollment(new EnrolledUsers(10)); }).isInstanceOf(CanNotJoinException.class) .hasMessage("무료강의는 정원이 없다"); } From 26efd98198c65a69f92d6adc69b2de73aa9daec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Wed, 10 Dec 2025 14:21:03 +0900 Subject: [PATCH 24/34] =?UTF-8?q?refactor=20:=20apply=20=EC=97=90=20Provid?= =?UTF-8?q?eType=20=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EB=B6=84=EA=B8=B0?= =?UTF-8?q?=EB=90=98=EA=B2=8C=EB=81=94=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/nextstep/courses/domain/Course.java | 9 ++++++--- src/main/java/nextstep/courses/domain/Provide.java | 4 ++++ src/main/java/nextstep/courses/domain/Session.java | 4 ++++ .../java/nextstep/courses/service/CourseService.java | 5 +---- src/test/java/nextstep/courses/domain/CourseTest.java | 6 ++++++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index ce1c4fde9..ada941996 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -60,7 +60,7 @@ public String toString() { public void apply(long userId, long sessionId, Payment payment) throws CanNotJoinException { Session session = sessions.findToApplySession(sessionId); - if(payment == null) { + if(this.isFreeSession(sessionId)) { session.applyFreeSession(userId); return; } @@ -68,8 +68,11 @@ public void apply(long userId, long sessionId, Payment payment) throws CanNotJoi } public boolean isPaidSession(Long sessionId) throws CanNotJoinException { - Session session = sessions.findToApplySession(sessionId); - return session.isPaidSession(); + return sessions.findToApplySession(sessionId).isPaidSession(); + } + + public boolean isFreeSession(Long sessionId) throws CanNotJoinException { + return sessions.findToApplySession(sessionId).isFreeSession(); } } diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Provide.java index a7d4bd142..be2b36501 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Provide.java @@ -43,4 +43,8 @@ public void applyFree() throws CanNotJoinException { public boolean isPaid() { return this.type.isPaid(); } + + public boolean isFree() { + return this.type.isFree(); + } } diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 2b60c63d4..ff2719653 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -58,4 +58,8 @@ public boolean isSameSessionId(Long id) { public boolean isPaidSession() { return provide.isPaid(); } + + public boolean isFreeSession() { + return provide.isFree(); + } } \ No newline at end of file diff --git a/src/main/java/nextstep/courses/service/CourseService.java b/src/main/java/nextstep/courses/service/CourseService.java index ec8bb2353..5f12ce52c 100644 --- a/src/main/java/nextstep/courses/service/CourseService.java +++ b/src/main/java/nextstep/courses/service/CourseService.java @@ -18,10 +18,7 @@ public class CourseService { public void apply(NsUser loginUser, long courseId, long sessionId) throws CanNotJoinException { Course course = courseRepository.findById(courseId); - Payment payment = null; - if(course.isPaidSession(sessionId)) { - payment = new PaymentService().payment("id"); - } + Payment payment = new PaymentService().payment("id"); course.apply(loginUser.getId(), sessionId, payment); courseRepository.save(course); } diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 51dd5fe39..91388b634 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -83,4 +83,10 @@ class CourseTest { assertThat(course.isPaidSession(2L)).isTrue(); } + @Test + void 해당하는_강의가_무료_강의인지_찾는다() throws CanNotJoinException { + Course course = new Course("title", 1L, List.of(freeSession, paidSession)); + assertThat(course.isFreeSession(1L)).isTrue(); + } + } \ No newline at end of file From 370be1a4d60f6c21b5e46e726e60b83165c1f9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Wed, 10 Dec 2025 22:45:59 +0900 Subject: [PATCH 25/34] =?UTF-8?q?refactor=201.=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EC=9D=98=20=EC=97=AD=ED=95=A0=EA=B3=BC=20=EC=B1=85=EC=9E=84?= =?UTF-8?q?=EC=9D=84=20=EB=AA=85=ED=99=95=ED=9E=88=20=EC=9D=B8=EC=A7=80?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=B4=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD=202.=20Session=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=ED=95=84=EB=93=9C=20=EC=9D=BC=EB=B6=80=EB=A5=BC=20?= =?UTF-8?q?EnrollmentPolicy=EB=A1=9C=20=EC=9D=B4=EA=B4=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/{Provide.java => Enrollment.java} | 24 ++++---- ...ovidePolicy.java => EnrollmentPolicy.java} | 56 +++++++++++++++---- .../java/nextstep/courses/domain/Session.java | 35 ++++-------- .../courses/domain/SessionStatus.java | 4 ++ .../{ProvideType.java => EnrollmentType.java} | 8 +-- .../nextstep/courses/domain/CourseTest.java | 20 ++++--- ...icyTest.java => EnrollmentPolicyTest.java} | 20 +++---- .../{ProvideTest.java => EnrollmentTest.java} | 19 ++++--- .../nextstep/courses/domain/SessionTest.java | 24 +++++--- .../{sessionsTest.java => SessionsTest.java} | 23 +++++--- 10 files changed, 136 insertions(+), 97 deletions(-) rename src/main/java/nextstep/courses/domain/{Provide.java => Enrollment.java} (55%) rename src/main/java/nextstep/courses/domain/{ProvidePolicy.java => EnrollmentPolicy.java} (54%) rename src/main/java/nextstep/courses/enumerate/{ProvideType.java => EnrollmentType.java} (57%) rename src/test/java/nextstep/courses/domain/{ProvidePolicyTest.java => EnrollmentPolicyTest.java} (73%) rename src/test/java/nextstep/courses/domain/{ProvideTest.java => EnrollmentTest.java} (58%) rename src/test/java/nextstep/courses/domain/{sessionsTest.java => SessionsTest.java} (72%) diff --git a/src/main/java/nextstep/courses/domain/Provide.java b/src/main/java/nextstep/courses/domain/Enrollment.java similarity index 55% rename from src/main/java/nextstep/courses/domain/Provide.java rename to src/main/java/nextstep/courses/domain/Enrollment.java index be2b36501..3c39c9f4e 100644 --- a/src/main/java/nextstep/courses/domain/Provide.java +++ b/src/main/java/nextstep/courses/domain/Enrollment.java @@ -2,42 +2,42 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; -import nextstep.courses.enumerate.ProvideType; +import nextstep.courses.enumerate.EnrollmentType; import nextstep.payments.domain.Payment; -public class Provide { +public class Enrollment { - private final ProvideType type; - private final ProvidePolicy policy; + private final EnrollmentType type; + private final EnrollmentPolicy policy; - public Provide(ProvideType type) throws CanNotCreateException { - this(type, new ProvidePolicy()); + public Enrollment(EnrollmentType type) throws CanNotCreateException { + this(type, new EnrollmentPolicy()); } - public Provide(ProvideType type, ProvidePolicy policy) throws CanNotCreateException { + public Enrollment(EnrollmentType type, EnrollmentPolicy policy) throws CanNotCreateException { validate(type, policy); this.type = type; this.policy = policy; } - private void validate(ProvideType type, ProvidePolicy policy) throws CanNotCreateException { + private void validate(EnrollmentType type, EnrollmentPolicy policy) throws CanNotCreateException { if(policy.isNotCorrectBetween(type)) { throw new CanNotCreateException("강의타입과 정책이 일치하지 않습니다"); } } - public void applyPaid(EnrolledUsers enrolledUsers, Payment payment) throws CanNotJoinException { + public void applyPaid(Long userId, Payment payment) throws CanNotJoinException { if(this.type.isFree()) { throw new CanNotJoinException("유료 강의는 결제를 해야한다"); } - policy.validateEnrollment(enrolledUsers); - policy.validatePayment(payment); + policy.validatePaidApply(userId, payment); } - public void applyFree() throws CanNotJoinException { + public void applyFree(Long userId) throws CanNotJoinException { if(this.type.isPaid()) { throw new CanNotJoinException("무료 강의는 결제할 수 없다"); } + policy.validateFreeApply(userId); } public boolean isPaid() { diff --git a/src/main/java/nextstep/courses/domain/ProvidePolicy.java b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java similarity index 54% rename from src/main/java/nextstep/courses/domain/ProvidePolicy.java rename to src/main/java/nextstep/courses/domain/EnrollmentPolicy.java index a8949a805..2d60ff0dc 100644 --- a/src/main/java/nextstep/courses/domain/ProvidePolicy.java +++ b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java @@ -2,22 +2,34 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; -import nextstep.courses.enumerate.ProvideType; +import nextstep.courses.enumerate.EnrollmentType; import nextstep.payments.domain.Payment; -public class ProvidePolicy { +public class EnrollmentPolicy { - private final Integer maxEnrollment; private final Long tuitionFee; + private final Integer maxEnrollment; + private final EnrolledUsers enrolledUsers; + private final SessionStatus status; + + public EnrollmentPolicy() throws CanNotCreateException { + this(null, null, null, null); + } - public ProvidePolicy() throws CanNotCreateException { - this(null, null); + public EnrollmentPolicy(Integer maxEnrollment, Long tuitionFee) throws CanNotCreateException { + this(tuitionFee, maxEnrollment, new EnrolledUsers(), new SessionStatus()); } - public ProvidePolicy(Integer maxEnrollment, Long tuitionFee) throws CanNotCreateException { + public EnrollmentPolicy(EnrolledUsers enrolledUsers, SessionStatus status) throws CanNotCreateException { + this(null, null, enrolledUsers, status); + } + + public EnrollmentPolicy(Long tuitionFee, Integer maxEnrollment, EnrolledUsers enrolledUsers, SessionStatus status) throws CanNotCreateException { validate(maxEnrollment, tuitionFee); - this.maxEnrollment = maxEnrollment; this.tuitionFee = tuitionFee; + this.maxEnrollment = maxEnrollment; + this.enrolledUsers = enrolledUsers; + this.status = status; } private void validate(Integer maxEnrollment, Long tuitionFee) throws CanNotCreateException { @@ -37,6 +49,26 @@ private static boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Long tuiti return maxEnrollment == null && tuitionFee != null; } + public void validatePaidApply(Long userId, Payment payment) throws CanNotJoinException { + validateApplyStatus(); + validateEnrollment(); + validatePayment(payment); + registerUser(userId); + } + + public void validateFreeApply(Long userId) throws CanNotJoinException { + validateApplyStatus(); + registerUser(userId); + } + + public void validateApplyStatus() throws CanNotJoinException { + status.isApplyStatus(); + } + + public void registerUser(Long userId) throws CanNotJoinException { + enrolledUsers.registerUserId(userId); + } + public void validatePayment(Payment payment) throws CanNotJoinException { if(this.tuitionFee == null) { throw new CanNotJoinException("무료 강의는 지불할 수 없다"); @@ -46,21 +78,21 @@ public void validatePayment(Payment payment) throws CanNotJoinException { } } - public void validateEnrollment(EnrolledUsers enrolledUsers) throws CanNotJoinException { + public void validateEnrollment() throws CanNotJoinException { if(this.maxEnrollment == null) { throw new CanNotJoinException("무료강의는 정원이 없다"); } - if(enrolledUsers.isAlreadyExceed(maxEnrollment)) { + if(this.enrolledUsers.isAlreadyExceed(this.maxEnrollment)) { throw new CanNotJoinException("이미 정원을 초과했다"); } } - public boolean isNotCorrectBetween(ProvideType type) { - if(type == ProvideType.FREE) { + public boolean isNotCorrectBetween(EnrollmentType type) { + if(type == EnrollmentType.FREE) { return !(this.maxEnrollment == null && this.tuitionFee == null); } - if(type == ProvideType.PAID) { + if(type == EnrollmentType.PAID) { return !(this.maxEnrollment != null && this.tuitionFee != null); } return true; diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index ff2719653..fe5cb41bd 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -1,10 +1,8 @@ package nextstep.courses.domain; import java.time.LocalDateTime; -import java.util.List; import java.util.Objects; import nextstep.courses.CanNotJoinException; -import nextstep.courses.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; public class Session extends Base { @@ -14,52 +12,39 @@ public class Session extends Base { private final SessionBody body; private final Duration duration; private final CoverImage coverImage; - private final SessionStatus status; - private final Provide provide; - private final EnrolledUsers enrolledUsers; + private final Enrollment enrollment; - public Session(String creatorId, SessionBody body, Duration duration, CoverImage coverImage, Provide provide) { - this(0L, creatorId, body, duration, coverImage, new SessionStatus(SessionStatusType.PREPARATION), provide, new EnrolledUsers(), LocalDateTime.now(), null); + public Session(String creatorId, SessionBody body, Duration duration, CoverImage coverImage, Enrollment enrollment) { + this(0L, creatorId, body, duration, coverImage, enrollment, LocalDateTime.now(), null); } - public Session(Long id, String code, SessionBody body, Duration duration, CoverImage coverImage, SessionStatus status, Provide provide, List enrolledUserIds, LocalDateTime createdAt, LocalDateTime updatedAt) { - this(id, code, body, duration, coverImage, status, provide, new EnrolledUsers(enrolledUserIds), createdAt, updatedAt); - } - - public Session(Long id, String creatorId, SessionBody body, Duration duration, CoverImage coverImage, SessionStatus status, Provide provide, EnrolledUsers enrolledUsers, LocalDateTime createdDate, LocalDateTime updatedDate) { + public Session(Long id, String creatorId, SessionBody body, Duration duration, CoverImage coverImage, Enrollment enrollment, LocalDateTime createdDate, LocalDateTime updatedDate) { super(createdDate, updatedDate); this.id = id; this.creatorId = creatorId; this.body = body; this.duration = duration; this.coverImage = coverImage; - this.status = status; - this.provide = provide; - this.enrolledUsers = enrolledUsers; + this.enrollment = enrollment; } public void applyFreeSession(Long userId) throws CanNotJoinException { - status.isApplyStatus(); - provide.applyFree(); - enrolledUsers.registerUserId(userId); + enrollment.applyFree(userId); } - + public void applyPaidSession(Long userId, Payment payment) throws CanNotJoinException { - status.isApplyStatus(); - provide.applyPaid(this.enrolledUsers, payment); - enrolledUsers.registerUserId(userId); + enrollment.applyPaid(userId, payment); } public boolean isSameSessionId(Long id) { return Objects.equals(this.id, id); } - public boolean isPaidSession() { - return provide.isPaid(); + return enrollment.isPaid(); } public boolean isFreeSession() { - return provide.isFree(); + return enrollment.isFree(); } } \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/SessionStatus.java b/src/main/java/nextstep/courses/domain/SessionStatus.java index cb1a258e0..a7f10ff5a 100644 --- a/src/main/java/nextstep/courses/domain/SessionStatus.java +++ b/src/main/java/nextstep/courses/domain/SessionStatus.java @@ -7,6 +7,10 @@ public class SessionStatus { private final SessionStatusType sessionStatusType; + public SessionStatus() { + this(SessionStatusType.PREPARATION); + } + public SessionStatus(SessionStatusType sessionStatusType) { this.sessionStatusType = sessionStatusType; } diff --git a/src/main/java/nextstep/courses/enumerate/ProvideType.java b/src/main/java/nextstep/courses/enumerate/EnrollmentType.java similarity index 57% rename from src/main/java/nextstep/courses/enumerate/ProvideType.java rename to src/main/java/nextstep/courses/enumerate/EnrollmentType.java index f2577546b..a893e0af6 100644 --- a/src/main/java/nextstep/courses/enumerate/ProvideType.java +++ b/src/main/java/nextstep/courses/enumerate/EnrollmentType.java @@ -1,19 +1,19 @@ package nextstep.courses.enumerate; -public enum ProvideType { +public enum EnrollmentType { PAID("paid", true), FREE("free", false); private String provideType; private boolean isExistTuitionFee; - ProvideType(String provideType, boolean isExistTuitionFee) {} + EnrollmentType(String provideType, boolean isExistTuitionFee) {} public boolean isFree() { - return this == ProvideType.FREE; + return this == EnrollmentType.FREE; } public boolean isPaid() { - return this == ProvideType.PAID; + return this == EnrollmentType.PAID; } } diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 91388b634..6b592666f 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -9,7 +9,7 @@ import java.util.List; import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.CoverImageType; -import nextstep.courses.enumerate.ProvideType; +import nextstep.courses.enumerate.EnrollmentType; import nextstep.courses.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; @@ -28,9 +28,11 @@ class CourseTest { new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new SessionStatus(SessionStatusType.RECRUITING), - new Provide(ProvideType.FREE), - List.of(4L, 5L, 6L, 7L, 8L, 9L), + new Enrollment( + EnrollmentType.FREE, + new EnrollmentPolicy( + new EnrolledUsers(List.of(4L, 5L, 6L, 7L, 8L, 9L)), + new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), null ); @@ -41,9 +43,13 @@ class CourseTest { new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new SessionStatus(SessionStatusType.RECRUITING), - new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)), - List.of(4L, 5L, 6L, 7L, 8L, 9L), + new Enrollment( + EnrollmentType.PAID, + new EnrollmentPolicy( + 10L, + 10, + new EnrolledUsers(List.of(4L, 5L, 6L, 7L, 8L, 9L)), + new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), null ); diff --git a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java similarity index 73% rename from src/test/java/nextstep/courses/domain/ProvidePolicyTest.java rename to src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java index 11fdcecd9..c356a0e99 100644 --- a/src/test/java/nextstep/courses/domain/ProvidePolicyTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java @@ -8,18 +8,18 @@ import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; -class ProvidePolicyTest { +class EnrollmentPolicyTest { @Test void maxEnrollment와tuitionFee_두개중_하나만_null이면_에러전파() { assertThatThrownBy(() -> { - new ProvidePolicy(10, null); + new EnrollmentPolicy(10, null); }).isInstanceOf(CanNotCreateException.class) .hasMessage("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); assertThatThrownBy(() -> { - new ProvidePolicy(null, 10L); + new EnrollmentPolicy(null, 10L); }).isInstanceOf(CanNotCreateException.class) .hasMessage("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); } @@ -27,33 +27,33 @@ class ProvidePolicyTest { @Test void 유료인데_수강료와_지불금액이_다르면_에러전파() throws Exception { assertThatNoException().isThrownBy(() -> { - new ProvidePolicy(10, 10L).validatePayment(new Payment()); + new EnrollmentPolicy(10, 10L).validatePayment(new Payment()); }); } @Test void 무료인데_수강료_납부하면_에러전파() throws Exception { - ProvidePolicy providePolicy = new ProvidePolicy(); + EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy(); assertThatThrownBy(() -> { - providePolicy.validatePayment(new Payment()); + enrollmentPolicy.validatePayment(new Payment()); }).isInstanceOf(CanNotJoinException.class) .hasMessage("무료 강의는 지불할 수 없다"); } @Test void 수강신청_인원이_초과하면_에러전파() throws Exception { - ProvidePolicy providePolicy = new ProvidePolicy(10, 10L); + EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy(10L, 10, new EnrolledUsers(10), new SessionStatus()); assertThatThrownBy(() -> { - providePolicy.validateEnrollment(new EnrolledUsers(10)); + enrollmentPolicy.validateEnrollment(); }).isInstanceOf(CanNotJoinException.class) .hasMessage("이미 정원을 초과했다"); } @Test void 무료강의인데_수강신청_시_정원체크하면_에러전파() throws Exception { - ProvidePolicy providePolicy = new ProvidePolicy(); + EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy(new EnrolledUsers(10), new SessionStatus()); assertThatThrownBy(() -> { - providePolicy.validateEnrollment(new EnrolledUsers(10)); + enrollmentPolicy.validateEnrollment(); }).isInstanceOf(CanNotJoinException.class) .hasMessage("무료강의는 정원이 없다"); } diff --git a/src/test/java/nextstep/courses/domain/ProvideTest.java b/src/test/java/nextstep/courses/domain/EnrollmentTest.java similarity index 58% rename from src/test/java/nextstep/courses/domain/ProvideTest.java rename to src/test/java/nextstep/courses/domain/EnrollmentTest.java index 74528da76..c1eb71533 100644 --- a/src/test/java/nextstep/courses/domain/ProvideTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentTest.java @@ -5,42 +5,43 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; -import nextstep.courses.enumerate.ProvideType; +import nextstep.courses.enumerate.EnrollmentType; +import nextstep.courses.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; -class ProvideTest { +class EnrollmentTest { @Test void 무료강의인데_수강료가있으면_에러전파() throws CanNotCreateException { assertThatThrownBy(() -> { - new Provide(ProvideType.FREE, new ProvidePolicy(10, 10L)); + new Enrollment(EnrollmentType.FREE, new EnrollmentPolicy(10, 10L)); }).isInstanceOf(CanNotCreateException.class) .hasMessage("강의타입과 정책이 일치하지 않습니다"); } @Test void 유료강의에_수강신청한다() throws Exception { - Provide provide = new Provide(ProvideType.PAID, new ProvidePolicy(10, 5L)); + Enrollment enrollment = new Enrollment(EnrollmentType.PAID, new EnrollmentPolicy(5L, 10, new EnrolledUsers(8), new SessionStatus(SessionStatusType.RECRUITING))); assertThatNoException().isThrownBy(() -> { - provide.applyPaid(new EnrolledUsers(8), new Payment()); + enrollment.applyPaid(10L, new Payment()); }); } @Test void 무료강의에_지불_후_수강신청한다() throws Exception { - Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); + Enrollment enrollment = new Enrollment(EnrollmentType.FREE, new EnrollmentPolicy()); assertThatThrownBy(() -> { - provide.applyPaid(new EnrolledUsers(8), new Payment()); + enrollment.applyPaid(10L, new Payment()); }).isInstanceOf(CanNotJoinException.class) .hasMessage("유료 강의는 결제를 해야한다"); } @Test void 무료강의에_지불_없이_수강신청한다() throws Exception { - Provide provide = new Provide(ProvideType.FREE, new ProvidePolicy()); - assertThatNoException().isThrownBy(provide::applyFree); + Enrollment enrollment = new Enrollment(EnrollmentType.FREE, new EnrollmentPolicy(new EnrolledUsers(8), new SessionStatus(SessionStatusType.RECRUITING))); + assertThatNoException().isThrownBy(() -> enrollment.applyFree(10L)); } } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 98fe0370a..2e476be72 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -6,7 +6,7 @@ import java.time.LocalDateTime; import java.util.List; import nextstep.courses.enumerate.CoverImageType; -import nextstep.courses.enumerate.ProvideType; +import nextstep.courses.enumerate.EnrollmentType; import nextstep.courses.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; @@ -25,9 +25,11 @@ class SessionTest { new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new SessionStatus(SessionStatusType.RECRUITING), - new Provide(ProvideType.FREE), - List.of(11L, 12L, 13L, 14L, 15L), + new Enrollment( + EnrollmentType.FREE, + new EnrollmentPolicy( + new EnrolledUsers(List.of(11L, 12L, 13L, 14L, 15L)), + new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), null ); @@ -38,9 +40,13 @@ class SessionTest { new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new SessionStatus(SessionStatusType.RECRUITING), - new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)), - List.of(11L, 12L, 13L, 14L, 15L), + new Enrollment( + EnrollmentType.PAID, + new EnrollmentPolicy( + 10L, + 10, + new EnrolledUsers(List.of(11L, 12L, 13L, 14L, 15L)), + new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), null ); @@ -58,7 +64,7 @@ class SessionTest { new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Provide(ProvideType.FREE) + new Enrollment(EnrollmentType.FREE) ); }); } @@ -71,7 +77,7 @@ class SessionTest { new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)) + new Enrollment(EnrollmentType.PAID, new EnrollmentPolicy(10, 10L)) ); }); } diff --git a/src/test/java/nextstep/courses/domain/sessionsTest.java b/src/test/java/nextstep/courses/domain/SessionsTest.java similarity index 72% rename from src/test/java/nextstep/courses/domain/sessionsTest.java rename to src/test/java/nextstep/courses/domain/SessionsTest.java index 793af03cb..df037d52f 100644 --- a/src/test/java/nextstep/courses/domain/sessionsTest.java +++ b/src/test/java/nextstep/courses/domain/SessionsTest.java @@ -7,11 +7,11 @@ import java.util.List; import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.CoverImageType; -import nextstep.courses.enumerate.ProvideType; +import nextstep.courses.enumerate.EnrollmentType; import nextstep.courses.enumerate.SessionStatusType; import org.junit.jupiter.api.Test; -class sessionsTest { +class SessionsTest { public static final Session freeSession; public static final Session paidSession; @@ -24,22 +24,27 @@ class sessionsTest { new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new SessionStatus(SessionStatusType.RECRUITING), - new Provide(ProvideType.FREE), - List.of(1L, 2L, 3L, 4L, 5L), + new Enrollment( + EnrollmentType.FREE, + new EnrollmentPolicy( + new EnrolledUsers(List.of(1L, 2L, 3L, 4L, 5L)), + new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), null ); - paidSession = new Session( 2L, "1", new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new SessionStatus(SessionStatusType.RECRUITING), - new Provide(ProvideType.PAID, new ProvidePolicy(10, 10L)), - List.of(1L, 2L, 3L, 4L, 5L), + new Enrollment( + EnrollmentType.PAID, + new EnrollmentPolicy( + 10L, + 10, + new EnrolledUsers(List.of(1L, 2L, 3L, 4L, 5L)), + new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), null ); From 7c466558c85fe823bab0c3d022a27956a398b2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Wed, 10 Dec 2025 23:37:29 +0900 Subject: [PATCH 26/34] =?UTF-8?q?refactor=20:=20=EA=B0=81=EA=B0=81=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=EB=A5=BC=20SessionApply=EB=A1=9C=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Course.java | 10 ++++----- .../nextstep/courses/domain/Enrollment.java | 20 +++++++++-------- .../courses/domain/EnrollmentPolicy.java | 6 ++--- .../java/nextstep/courses/domain/Session.java | 14 +++++++----- .../nextstep/courses/domain/SessionApply.java | 22 +++++++++++++++++++ .../courses/domain/EnrollmentTest.java | 14 ++---------- .../nextstep/courses/domain/SessionTest.java | 4 ++-- 7 files changed, 54 insertions(+), 36 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/SessionApply.java diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index ada941996..4732c4ed5 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -59,12 +59,12 @@ public String toString() { } public void apply(long userId, long sessionId, Payment payment) throws CanNotJoinException { + this.apply(new SessionApply(userId, payment), sessionId); + } + + public void apply(SessionApply request, long sessionId) throws CanNotJoinException { Session session = sessions.findToApplySession(sessionId); - if(this.isFreeSession(sessionId)) { - session.applyFreeSession(userId); - return; - } - session.applyPaidSession(userId, payment); + session.applySession(request); } public boolean isPaidSession(Long sessionId) throws CanNotJoinException { diff --git a/src/main/java/nextstep/courses/domain/Enrollment.java b/src/main/java/nextstep/courses/domain/Enrollment.java index 3c39c9f4e..08ca86773 100644 --- a/src/main/java/nextstep/courses/domain/Enrollment.java +++ b/src/main/java/nextstep/courses/domain/Enrollment.java @@ -26,18 +26,20 @@ private void validate(EnrollmentType type, EnrollmentPolicy policy) throws CanNo } } - public void applyPaid(Long userId, Payment payment) throws CanNotJoinException { - if(this.type.isFree()) { - throw new CanNotJoinException("유료 강의는 결제를 해야한다"); + public void apply(SessionApply sessionApply) throws CanNotJoinException { + if(isFree()) { + policy.validateFreeApply(sessionApply.getUserId()); + return; } - policy.validatePaidApply(userId, payment); + policy.validatePaidApply(sessionApply); } - public void applyFree(Long userId) throws CanNotJoinException { - if(this.type.isPaid()) { - throw new CanNotJoinException("무료 강의는 결제할 수 없다"); - } - policy.validateFreeApply(userId); + public void apply(Long userid) throws CanNotJoinException { + apply(new SessionApply(userid, null)); + } + + public void apply(Long userid, Payment payment) throws CanNotJoinException { + apply(new SessionApply(userid, payment)); } public boolean isPaid() { diff --git a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java index 2d60ff0dc..a1a209c92 100644 --- a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java +++ b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java @@ -49,11 +49,11 @@ private static boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Long tuiti return maxEnrollment == null && tuitionFee != null; } - public void validatePaidApply(Long userId, Payment payment) throws CanNotJoinException { + public void validatePaidApply(SessionApply sessionApply) throws CanNotJoinException { validateApplyStatus(); validateEnrollment(); - validatePayment(payment); - registerUser(userId); + validatePayment(sessionApply.getPayment()); + registerUser(sessionApply.getUserId()); } public void validateFreeApply(Long userId) throws CanNotJoinException { diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index fe5cb41bd..97f142878 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -28,12 +28,16 @@ public Session(Long id, String creatorId, SessionBody body, Duration duration, C this.enrollment = enrollment; } - public void applyFreeSession(Long userId) throws CanNotJoinException { - enrollment.applyFree(userId); + public void applySession(SessionApply request) throws CanNotJoinException { + enrollment.apply(request); } - - public void applyPaidSession(Long userId, Payment payment) throws CanNotJoinException { - enrollment.applyPaid(userId, payment); + + public void applySession(Long userid) throws CanNotJoinException { + applySession(new SessionApply(userid, null)); + } + + public void applySession(Long userid, Payment payment) throws CanNotJoinException { + applySession(new SessionApply(userid, payment)); } public boolean isSameSessionId(Long id) { diff --git a/src/main/java/nextstep/courses/domain/SessionApply.java b/src/main/java/nextstep/courses/domain/SessionApply.java new file mode 100644 index 000000000..bd370538d --- /dev/null +++ b/src/main/java/nextstep/courses/domain/SessionApply.java @@ -0,0 +1,22 @@ +package nextstep.courses.domain; + +import nextstep.payments.domain.Payment; + +public class SessionApply { + + private final long userId; + private final Payment payment; + + public SessionApply(long userId, Payment payment) { + this.userId = userId; + this.payment = payment; + } + + public long getUserId() { + return userId; + } + + public Payment getPayment() { + return payment; + } +} diff --git a/src/test/java/nextstep/courses/domain/EnrollmentTest.java b/src/test/java/nextstep/courses/domain/EnrollmentTest.java index c1eb71533..c349fa231 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentTest.java @@ -4,7 +4,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; -import nextstep.courses.CanNotJoinException; import nextstep.courses.enumerate.EnrollmentType; import nextstep.courses.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; @@ -25,23 +24,14 @@ class EnrollmentTest { Enrollment enrollment = new Enrollment(EnrollmentType.PAID, new EnrollmentPolicy(5L, 10, new EnrolledUsers(8), new SessionStatus(SessionStatusType.RECRUITING))); assertThatNoException().isThrownBy(() -> { - enrollment.applyPaid(10L, new Payment()); + enrollment.apply(10L, new Payment()); }); } - @Test - void 무료강의에_지불_후_수강신청한다() throws Exception { - Enrollment enrollment = new Enrollment(EnrollmentType.FREE, new EnrollmentPolicy()); - assertThatThrownBy(() -> { - enrollment.applyPaid(10L, new Payment()); - }).isInstanceOf(CanNotJoinException.class) - .hasMessage("유료 강의는 결제를 해야한다"); - } - @Test void 무료강의에_지불_없이_수강신청한다() throws Exception { Enrollment enrollment = new Enrollment(EnrollmentType.FREE, new EnrollmentPolicy(new EnrolledUsers(8), new SessionStatus(SessionStatusType.RECRUITING))); - assertThatNoException().isThrownBy(() -> enrollment.applyFree(10L)); + assertThatNoException().isThrownBy(() -> enrollment.apply(10L)); } } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 2e476be72..336fecfa8 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -85,14 +85,14 @@ class SessionTest { @Test void 무료_session을_수강신청한다() throws Exception { assertThatNoException().isThrownBy(() -> { - freeSession.applyFreeSession(NsUserTest.JAVAJIGI.getId()); + freeSession.applySession(NsUserTest.JAVAJIGI.getId()); }); } @Test void 유료_session을_수강신청한다() throws Exception { assertThatNoException().isThrownBy(() -> { - paidSession.applyPaidSession(NsUserTest.JAVAJIGI.getId(), new Payment()); + paidSession.applySession(NsUserTest.JAVAJIGI.getId(), new Payment()); }); } From 2dc593ed5eccdb80bb432e2e0722270289e15652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Thu, 11 Dec 2025 10:23:57 +0900 Subject: [PATCH 27/34] =?UTF-8?q?refactor=20:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20static=20=EB=93=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/EnrollmentPolicy.java | 8 ++++---- src/main/java/nextstep/courses/service/CourseService.java | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java index a1a209c92..b069601e7 100644 --- a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java +++ b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java @@ -41,11 +41,11 @@ private void validate(Integer maxEnrollment, Long tuitionFee) throws CanNotCreat } } - private static boolean isTuitionFeeOnlyNull(Integer maxEnrollment, Long tuitionFee) { + private boolean isTuitionFeeOnlyNull(Integer maxEnrollment, Long tuitionFee) { return maxEnrollment != null && tuitionFee == null; } - private static boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Long tuitionFee) { + private boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Long tuitionFee) { return maxEnrollment == null && tuitionFee != null; } @@ -89,10 +89,10 @@ public void validateEnrollment() throws CanNotJoinException { } public boolean isNotCorrectBetween(EnrollmentType type) { - if(type == EnrollmentType.FREE) { + if(type.isFree()) { return !(this.maxEnrollment == null && this.tuitionFee == null); } - if(type == EnrollmentType.PAID) { + if(type.isPaid()) { return !(this.maxEnrollment != null && this.tuitionFee != null); } return true; diff --git a/src/main/java/nextstep/courses/service/CourseService.java b/src/main/java/nextstep/courses/service/CourseService.java index 5f12ce52c..ba55428fe 100644 --- a/src/main/java/nextstep/courses/service/CourseService.java +++ b/src/main/java/nextstep/courses/service/CourseService.java @@ -4,6 +4,7 @@ import nextstep.courses.CanNotJoinException; import nextstep.courses.domain.Course; import nextstep.courses.domain.CourseRepository; +import nextstep.courses.domain.SessionApply; import nextstep.payments.domain.Payment; import nextstep.payments.service.PaymentService; import nextstep.users.domain.NsUser; @@ -19,7 +20,7 @@ public void apply(NsUser loginUser, long courseId, long sessionId) throws CanNot Course course = courseRepository.findById(courseId); Payment payment = new PaymentService().payment("id"); - course.apply(loginUser.getId(), sessionId, payment); + course.apply(new SessionApply(loginUser.getId(), payment), sessionId); courseRepository.save(course); } From 89be588aff17778826b4c9d4ae6c1345d3b54764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Fri, 12 Dec 2025 10:18:10 +0900 Subject: [PATCH 28/34] =?UTF-8?q?refactor=20:=20null=20object=20+=20?= =?UTF-8?q?=EC=A0=84=EB=9E=B5=20=ED=8C=A8=ED=84=B4=20=EB=8F=84=EC=9E=85?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=AC=B4=EB=A3=8C=20=EC=9C=A0=EB=A3=8C?= =?UTF-8?q?=EA=B0=95=EC=9D=98=20=EC=A0=95=EC=B1=85=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=20DI=20=EB=B0=A9=EC=8B=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Course.java | 18 ++--- .../nextstep/courses/domain/Enrollment.java | 19 ++--- .../courses/domain/EnrollmentPolicy.java | 81 ++++--------------- .../java/nextstep/courses/domain/Session.java | 12 +-- .../nextstep/courses/domain/Sessions.java | 2 +- .../EnrollmentCondition.java | 18 +++++ .../FreeEnrollmentCondition.java | 32 ++++++++ .../PaidEnrollmentCondition.java | 51 ++++++++++++ .../courses/service/CourseService.java | 4 +- .../nextstep/courses/domain/CourseTest.java | 25 ++---- .../courses/domain/EnrollmentPolicyTest.java | 63 ++++++--------- .../courses/domain/EnrollmentTest.java | 30 +++++-- .../nextstep/courses/domain/SessionTest.java | 12 +-- .../nextstep/courses/domain/SessionsTest.java | 10 ++- .../FreeEnrollmentConditionTest.java | 17 ++++ .../PaidEnrollmentConditionTest.java | 49 +++++++++++ 16 files changed, 270 insertions(+), 173 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/enrollmentcondition/EnrollmentCondition.java create mode 100644 src/main/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentCondition.java create mode 100644 src/main/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentCondition.java create mode 100644 src/test/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentConditionTest.java create mode 100644 src/test/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentConditionTest.java diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/Course.java index 4732c4ed5..ed0efeed4 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/Course.java @@ -58,21 +58,13 @@ public String toString() { '}'; } - public void apply(long userId, long sessionId, Payment payment) throws CanNotJoinException { - this.apply(new SessionApply(userId, payment), sessionId); + public void enrollCourse(long userId, long sessionId, Payment payment) throws CanNotJoinException { + this.enrollCourse(new SessionApply(userId, payment), sessionId); } - public void apply(SessionApply request, long sessionId) throws CanNotJoinException { - Session session = sessions.findToApplySession(sessionId); - session.applySession(request); - } - - public boolean isPaidSession(Long sessionId) throws CanNotJoinException { - return sessions.findToApplySession(sessionId).isPaidSession(); - } - - public boolean isFreeSession(Long sessionId) throws CanNotJoinException { - return sessions.findToApplySession(sessionId).isFreeSession(); + public void enrollCourse(SessionApply request, long sessionId) throws CanNotJoinException { + Session session = sessions.findEnrollSession(sessionId); + session.enrollSession(request); } } diff --git a/src/main/java/nextstep/courses/domain/Enrollment.java b/src/main/java/nextstep/courses/domain/Enrollment.java index 08ca86773..3f3d79878 100644 --- a/src/main/java/nextstep/courses/domain/Enrollment.java +++ b/src/main/java/nextstep/courses/domain/Enrollment.java @@ -2,6 +2,7 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; import nextstep.courses.enumerate.EnrollmentType; import nextstep.payments.domain.Payment; @@ -11,7 +12,7 @@ public class Enrollment { private final EnrollmentPolicy policy; public Enrollment(EnrollmentType type) throws CanNotCreateException { - this(type, new EnrollmentPolicy()); + this(type, new EnrollmentPolicy(FreeEnrollmentCondition.INSTANCE)); } public Enrollment(EnrollmentType type, EnrollmentPolicy policy) throws CanNotCreateException { @@ -26,20 +27,16 @@ private void validate(EnrollmentType type, EnrollmentPolicy policy) throws CanNo } } - public void apply(SessionApply sessionApply) throws CanNotJoinException { - if(isFree()) { - policy.validateFreeApply(sessionApply.getUserId()); - return; - } - policy.validatePaidApply(sessionApply); + public void enroll(SessionApply sessionApply) throws CanNotJoinException { + policy.enroll(sessionApply); } - public void apply(Long userid) throws CanNotJoinException { - apply(new SessionApply(userid, null)); + public void enroll(Long userid) throws CanNotJoinException { + enroll(new SessionApply(userid, null)); } - public void apply(Long userid, Payment payment) throws CanNotJoinException { - apply(new SessionApply(userid, payment)); + public void enroll(Long userid, Payment payment) throws CanNotJoinException { + enroll(new SessionApply(userid, payment)); } public boolean isPaid() { diff --git a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java index b069601e7..bcb58f31c 100644 --- a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java +++ b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java @@ -1,99 +1,46 @@ package nextstep.courses.domain; -import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.enrollmentcondition.EnrollmentCondition; import nextstep.courses.enumerate.EnrollmentType; -import nextstep.payments.domain.Payment; public class EnrollmentPolicy { - private final Long tuitionFee; - private final Integer maxEnrollment; + private final EnrollmentCondition enrollmentCondition; private final EnrolledUsers enrolledUsers; private final SessionStatus status; - public EnrollmentPolicy() throws CanNotCreateException { - this(null, null, null, null); + public EnrollmentPolicy(EnrollmentCondition enrollmentCondition) { + this(enrollmentCondition, new EnrolledUsers(), new SessionStatus()); } - public EnrollmentPolicy(Integer maxEnrollment, Long tuitionFee) throws CanNotCreateException { - this(tuitionFee, maxEnrollment, new EnrolledUsers(), new SessionStatus()); - } - - public EnrollmentPolicy(EnrolledUsers enrolledUsers, SessionStatus status) throws CanNotCreateException { - this(null, null, enrolledUsers, status); - } - - public EnrollmentPolicy(Long tuitionFee, Integer maxEnrollment, EnrolledUsers enrolledUsers, SessionStatus status) throws CanNotCreateException { - validate(maxEnrollment, tuitionFee); - this.tuitionFee = tuitionFee; - this.maxEnrollment = maxEnrollment; + public EnrollmentPolicy(EnrollmentCondition enrollmentCondition, EnrolledUsers enrolledUsers, SessionStatus status) { + this.enrollmentCondition = enrollmentCondition; this.enrolledUsers = enrolledUsers; this.status = status; } - private void validate(Integer maxEnrollment, Long tuitionFee) throws CanNotCreateException { - if(IsMaxEnrollmentOnlyNull(maxEnrollment, tuitionFee)) { - throw new CanNotCreateException("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); - } - if(isTuitionFeeOnlyNull(maxEnrollment, tuitionFee)) { - throw new CanNotCreateException("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); - } - } - - private boolean isTuitionFeeOnlyNull(Integer maxEnrollment, Long tuitionFee) { - return maxEnrollment != null && tuitionFee == null; - } - - private boolean IsMaxEnrollmentOnlyNull(Integer maxEnrollment, Long tuitionFee) { - return maxEnrollment == null && tuitionFee != null; - } - - public void validatePaidApply(SessionApply sessionApply) throws CanNotJoinException { - validateApplyStatus(); - validateEnrollment(); - validatePayment(sessionApply.getPayment()); + public void enroll(SessionApply sessionApply) throws CanNotJoinException { + validateEnrollStatus(); + enrollmentCondition.isFull(enrolledUsers); + enrollmentCondition.isPaid(sessionApply.getPayment()); registerUser(sessionApply.getUserId()); } - public void validateFreeApply(Long userId) throws CanNotJoinException { - validateApplyStatus(); - registerUser(userId); - } - - public void validateApplyStatus() throws CanNotJoinException { + private void validateEnrollStatus() throws CanNotJoinException { status.isApplyStatus(); } - public void registerUser(Long userId) throws CanNotJoinException { + private void registerUser(Long userId) throws CanNotJoinException { enrolledUsers.registerUserId(userId); } - public void validatePayment(Payment payment) throws CanNotJoinException { - if(this.tuitionFee == null) { - throw new CanNotJoinException("무료 강의는 지불할 수 없다"); - } - if(payment.isNotSameAmount(this.tuitionFee)) { - throw new CanNotJoinException("지불한 금액과 수강료 금액이 다르다"); - } - } - - public void validateEnrollment() throws CanNotJoinException { - if(this.maxEnrollment == null) { - throw new CanNotJoinException("무료강의는 정원이 없다"); - } - - if(this.enrolledUsers.isAlreadyExceed(this.maxEnrollment)) { - throw new CanNotJoinException("이미 정원을 초과했다"); - } - } - public boolean isNotCorrectBetween(EnrollmentType type) { if(type.isFree()) { - return !(this.maxEnrollment == null && this.tuitionFee == null); + return !(this.enrollmentCondition.maxEnrollment().isEmpty() && this.enrollmentCondition.tuitionFee().isEmpty()); } if(type.isPaid()) { - return !(this.maxEnrollment != null && this.tuitionFee != null); + return !(this.enrollmentCondition.maxEnrollment().isPresent() && this.enrollmentCondition.tuitionFee().isPresent()); } return true; } diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 97f142878..7b0043388 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -28,16 +28,16 @@ public Session(Long id, String creatorId, SessionBody body, Duration duration, C this.enrollment = enrollment; } - public void applySession(SessionApply request) throws CanNotJoinException { - enrollment.apply(request); + public void enrollSession(SessionApply request) throws CanNotJoinException { + enrollment.enroll(request); } - public void applySession(Long userid) throws CanNotJoinException { - applySession(new SessionApply(userid, null)); + public void enrollSession(Long userid) throws CanNotJoinException { + enrollSession(new SessionApply(userid, null)); } - public void applySession(Long userid, Payment payment) throws CanNotJoinException { - applySession(new SessionApply(userid, payment)); + public void enrollSession(Long userid, Payment payment) throws CanNotJoinException { + enrollSession(new SessionApply(userid, payment)); } public boolean isSameSessionId(Long id) { diff --git a/src/main/java/nextstep/courses/domain/Sessions.java b/src/main/java/nextstep/courses/domain/Sessions.java index a6874f0a7..dcf94af96 100644 --- a/src/main/java/nextstep/courses/domain/Sessions.java +++ b/src/main/java/nextstep/courses/domain/Sessions.java @@ -21,7 +21,7 @@ public Sessions(List sessions) { this.sessions = sessions; } - public Session findToApplySession(long sessionId) throws CanNotJoinException { + public Session findEnrollSession(long sessionId) throws CanNotJoinException { for(Session session: this.sessions) { if(session.isSameSessionId(sessionId)) { return session; diff --git a/src/main/java/nextstep/courses/domain/enrollmentcondition/EnrollmentCondition.java b/src/main/java/nextstep/courses/domain/enrollmentcondition/EnrollmentCondition.java new file mode 100644 index 000000000..c00b4356a --- /dev/null +++ b/src/main/java/nextstep/courses/domain/enrollmentcondition/EnrollmentCondition.java @@ -0,0 +1,18 @@ +package nextstep.courses.domain.enrollmentcondition; + +import java.util.Optional; +import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.EnrolledUsers; +import nextstep.payments.domain.Payment; + +public interface EnrollmentCondition { + + void isPaid(Payment payment) throws CanNotJoinException; + + void isFull(EnrolledUsers enrolledUsers) throws CanNotJoinException; + + Optional tuitionFee(); + + Optional maxEnrollment(); + +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentCondition.java b/src/main/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentCondition.java new file mode 100644 index 000000000..864311640 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentCondition.java @@ -0,0 +1,32 @@ +package nextstep.courses.domain.enrollmentcondition; + +import java.util.Optional; +import nextstep.courses.domain.EnrolledUsers; +import nextstep.payments.domain.Payment; + +public class FreeEnrollmentCondition implements EnrollmentCondition { + + public static final FreeEnrollmentCondition INSTANCE = new FreeEnrollmentCondition(); + + private FreeEnrollmentCondition() {} + + @Override + public void isPaid(Payment payment) { + return; + } + + @Override + public void isFull(EnrolledUsers enrolledUsers) { + return; + } + + @Override + public Optional tuitionFee() { + return Optional.empty(); + } + + @Override + public Optional maxEnrollment() { + return Optional.empty(); + } +} diff --git a/src/main/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentCondition.java b/src/main/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentCondition.java new file mode 100644 index 000000000..374a0482b --- /dev/null +++ b/src/main/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentCondition.java @@ -0,0 +1,51 @@ +package nextstep.courses.domain.enrollmentcondition; + +import java.util.Optional; +import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.EnrolledUsers; +import nextstep.payments.domain.Payment; + +public class PaidEnrollmentCondition implements EnrollmentCondition { + + private final long tuitionFee; + private final int maxEnrollment; + + public PaidEnrollmentCondition(long tuitionFee, int maxEnrollment) { + validate(tuitionFee, maxEnrollment); + this.tuitionFee = tuitionFee; + this.maxEnrollment = maxEnrollment; + } + + private void validate(long tuitionFee, int maxEnrollment) { + if(tuitionFee <= 0) { + throw new IllegalArgumentException("수강료는 양수이어야 한다"); + } + if(maxEnrollment <= 0) { + throw new IllegalArgumentException("정원은 양수이어야 한다"); + } + } + + @Override + public void isPaid(Payment payment) throws CanNotJoinException { + if(payment.isNotSameAmount(this.tuitionFee)) { + throw new CanNotJoinException("지불한 금액과 수강료 금액이 다르다"); + } + } + + @Override + public void isFull(EnrolledUsers enrolledUsers) throws CanNotJoinException { + if(enrolledUsers.isAlreadyExceed(this.maxEnrollment)) { + throw new CanNotJoinException("이미 정원을 초과했다"); + } + } + + @Override + public Optional tuitionFee() { + return Optional.of(tuitionFee); + } + + @Override + public Optional maxEnrollment() { + return Optional.of(maxEnrollment); + } +} diff --git a/src/main/java/nextstep/courses/service/CourseService.java b/src/main/java/nextstep/courses/service/CourseService.java index ba55428fe..3f9774454 100644 --- a/src/main/java/nextstep/courses/service/CourseService.java +++ b/src/main/java/nextstep/courses/service/CourseService.java @@ -16,11 +16,11 @@ public class CourseService { private CourseRepository courseRepository; @Transactional - public void apply(NsUser loginUser, long courseId, long sessionId) throws CanNotJoinException { + public void enroll(NsUser loginUser, long courseId, long sessionId) throws CanNotJoinException { Course course = courseRepository.findById(courseId); Payment payment = new PaymentService().payment("id"); - course.apply(new SessionApply(loginUser.getId(), payment), sessionId); + course.enrollCourse(new SessionApply(loginUser.getId(), payment), sessionId); courseRepository.save(course); } diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 6b592666f..1d49cc9c1 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -1,6 +1,5 @@ package nextstep.courses.domain; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -8,6 +7,8 @@ import java.time.LocalDateTime; import java.util.List; import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; import nextstep.courses.enumerate.CoverImageType; import nextstep.courses.enumerate.EnrollmentType; import nextstep.courses.enumerate.SessionStatusType; @@ -31,6 +32,7 @@ class CourseTest { new Enrollment( EnrollmentType.FREE, new EnrollmentPolicy( + FreeEnrollmentCondition.INSTANCE, new EnrolledUsers(List.of(4L, 5L, 6L, 7L, 8L, 9L)), new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), @@ -46,8 +48,7 @@ class CourseTest { new Enrollment( EnrollmentType.PAID, new EnrollmentPolicy( - 10L, - 10, + new PaidEnrollmentCondition(10L, 10), new EnrolledUsers(List.of(4L, 5L, 6L, 7L, 8L, 9L)), new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), @@ -62,7 +63,7 @@ class CourseTest { void 수강신청하는_session이_없으면_예외전파() { Course course = new Course("title", 1L, List.of(freeSession, paidSession)); assertThatThrownBy(() -> { - course.apply(NsUserTest.JAVAJIGI.getId(), 3L, null); + course.enrollCourse(NsUserTest.JAVAJIGI.getId(), 3L, null); }).isInstanceOf(CanNotJoinException.class) .hasMessage("신청하려는 강의가 존재하지 않습니다"); } @@ -71,7 +72,7 @@ class CourseTest { void 무료강의_수강신청() { Course course = new Course("title", 1L, List.of(freeSession, paidSession)); assertThatNoException().isThrownBy(() -> { - course.apply(NsUserTest.JAVAJIGI.getId(), 1L, null); + course.enrollCourse(NsUserTest.JAVAJIGI.getId(), 1L, null); }); } @@ -79,20 +80,8 @@ class CourseTest { void 유료강의_수강신청() { Course course = new Course("title", 1L, List.of(freeSession, paidSession)); assertThatNoException().isThrownBy(() -> { - course.apply(NsUserTest.SANJIGI.getId(), 2L, new Payment()); + course.enrollCourse(NsUserTest.SANJIGI.getId(), 2L, new Payment()); }); } - @Test - void 해당하는_강의가_유료_강의인지_찾는다() throws CanNotJoinException { - Course course = new Course("title", 1L, List.of(freeSession, paidSession)); - assertThat(course.isPaidSession(2L)).isTrue(); - } - - @Test - void 해당하는_강의가_무료_강의인지_찾는다() throws CanNotJoinException { - Course course = new Course("title", 1L, List.of(freeSession, paidSession)); - assertThat(course.isFreeSession(1L)).isTrue(); - } - } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java index c356a0e99..81b354367 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java @@ -3,58 +3,41 @@ import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; +import nextstep.courses.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; class EnrollmentPolicyTest { - @Test - void maxEnrollment와tuitionFee_두개중_하나만_null이면_에러전파() { - - assertThatThrownBy(() -> { - new EnrollmentPolicy(10, null); - }).isInstanceOf(CanNotCreateException.class) - .hasMessage("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); - - assertThatThrownBy(() -> { - new EnrollmentPolicy(null, 10L); - }).isInstanceOf(CanNotCreateException.class) - .hasMessage("하나만 무료정책을 가질 수없다 (하나만 null 일 수 없다)"); - } - - @Test - void 유료인데_수강료와_지불금액이_다르면_에러전파() throws Exception { - assertThatNoException().isThrownBy(() -> { - new EnrollmentPolicy(10, 10L).validatePayment(new Payment()); - }); - } - - @Test - void 무료인데_수강료_납부하면_에러전파() throws Exception { - EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy(); - assertThatThrownBy(() -> { - enrollmentPolicy.validatePayment(new Payment()); - }).isInstanceOf(CanNotJoinException.class) - .hasMessage("무료 강의는 지불할 수 없다"); - } - @Test void 수강신청_인원이_초과하면_에러전파() throws Exception { - EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy(10L, 10, new EnrolledUsers(10), new SessionStatus()); + EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy( + new PaidEnrollmentCondition(5L, 10), + new EnrolledUsers(10), + new SessionStatus(SessionStatusType.RECRUITING) + ); + SessionApply sessionApply = new SessionApply(10L, new Payment()); + assertThatThrownBy(() -> { - enrollmentPolicy.validateEnrollment(); + enrollmentPolicy.enroll(sessionApply); }).isInstanceOf(CanNotJoinException.class) .hasMessage("이미 정원을 초과했다"); } - + @Test - void 무료강의인데_수강신청_시_정원체크하면_에러전파() throws Exception { - EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy(new EnrolledUsers(10), new SessionStatus()); - assertThatThrownBy(() -> { - enrollmentPolicy.validateEnrollment(); - }).isInstanceOf(CanNotJoinException.class) - .hasMessage("무료강의는 정원이 없다"); + void 무료강의인데_수강신청_시_정원체크를_해도_상관없다() throws Exception { + SessionApply sessionApply = new SessionApply(1000L, new Payment()); + EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy( + FreeEnrollmentCondition.INSTANCE, + new EnrolledUsers(8), + new SessionStatus(SessionStatusType.RECRUITING) + ); + + assertThatNoException().isThrownBy(() -> { + enrollmentPolicy.enroll(sessionApply); + }); } } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/EnrollmentTest.java b/src/test/java/nextstep/courses/domain/EnrollmentTest.java index c349fa231..cca8d5040 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentTest.java @@ -4,6 +4,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; +import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; import nextstep.courses.enumerate.EnrollmentType; import nextstep.courses.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; @@ -12,26 +14,42 @@ class EnrollmentTest { @Test - void 무료강의인데_수강료가있으면_에러전파() throws CanNotCreateException { + void 무료강의인데_수강료가있으면_에러전파() { assertThatThrownBy(() -> { - new Enrollment(EnrollmentType.FREE, new EnrollmentPolicy(10, 10L)); + new Enrollment(EnrollmentType.FREE, new EnrollmentPolicy(new PaidEnrollmentCondition(5L, 10))); }).isInstanceOf(CanNotCreateException.class) .hasMessage("강의타입과 정책이 일치하지 않습니다"); } @Test void 유료강의에_수강신청한다() throws Exception { - Enrollment enrollment = new Enrollment(EnrollmentType.PAID, new EnrollmentPolicy(5L, 10, new EnrolledUsers(8), new SessionStatus(SessionStatusType.RECRUITING))); + Enrollment enrollment = + new Enrollment( + EnrollmentType.PAID, + new EnrollmentPolicy( + new PaidEnrollmentCondition(5L, 10), + new EnrolledUsers(8), + new SessionStatus(SessionStatusType.RECRUITING) + ) + ); assertThatNoException().isThrownBy(() -> { - enrollment.apply(10L, new Payment()); + enrollment.enroll(10L, new Payment()); }); } @Test void 무료강의에_지불_없이_수강신청한다() throws Exception { - Enrollment enrollment = new Enrollment(EnrollmentType.FREE, new EnrollmentPolicy(new EnrolledUsers(8), new SessionStatus(SessionStatusType.RECRUITING))); - assertThatNoException().isThrownBy(() -> enrollment.apply(10L)); + Enrollment enrollment = + new Enrollment( + EnrollmentType.FREE, + new EnrollmentPolicy( + FreeEnrollmentCondition.INSTANCE, + new EnrolledUsers(8), + new SessionStatus(SessionStatusType.RECRUITING) + ) + ); + assertThatNoException().isThrownBy(() -> enrollment.enroll(10L)); } } \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 336fecfa8..cef4ab6b6 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -5,6 +5,8 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; +import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; import nextstep.courses.enumerate.CoverImageType; import nextstep.courses.enumerate.EnrollmentType; import nextstep.courses.enumerate.SessionStatusType; @@ -28,6 +30,7 @@ class SessionTest { new Enrollment( EnrollmentType.FREE, new EnrollmentPolicy( + FreeEnrollmentCondition.INSTANCE, new EnrolledUsers(List.of(11L, 12L, 13L, 14L, 15L)), new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), @@ -43,8 +46,7 @@ class SessionTest { new Enrollment( EnrollmentType.PAID, new EnrollmentPolicy( - 10L, - 10, + new PaidEnrollmentCondition(5L, 10), new EnrolledUsers(List.of(11L, 12L, 13L, 14L, 15L)), new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), @@ -77,7 +79,7 @@ class SessionTest { new SessionBody("title", "content"), new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Enrollment(EnrollmentType.PAID, new EnrollmentPolicy(10, 10L)) + new Enrollment(EnrollmentType.PAID, new EnrollmentPolicy(new PaidEnrollmentCondition(10L, 10))) ); }); } @@ -85,14 +87,14 @@ class SessionTest { @Test void 무료_session을_수강신청한다() throws Exception { assertThatNoException().isThrownBy(() -> { - freeSession.applySession(NsUserTest.JAVAJIGI.getId()); + freeSession.enrollSession(NsUserTest.JAVAJIGI.getId()); }); } @Test void 유료_session을_수강신청한다() throws Exception { assertThatNoException().isThrownBy(() -> { - paidSession.applySession(NsUserTest.JAVAJIGI.getId(), new Payment()); + paidSession.enrollSession(NsUserTest.JAVAJIGI.getId(), new Payment()); }); } diff --git a/src/test/java/nextstep/courses/domain/SessionsTest.java b/src/test/java/nextstep/courses/domain/SessionsTest.java index df037d52f..00df4ee8c 100644 --- a/src/test/java/nextstep/courses/domain/SessionsTest.java +++ b/src/test/java/nextstep/courses/domain/SessionsTest.java @@ -6,6 +6,8 @@ import java.time.LocalDateTime; import java.util.List; import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; import nextstep.courses.enumerate.CoverImageType; import nextstep.courses.enumerate.EnrollmentType; import nextstep.courses.enumerate.SessionStatusType; @@ -27,6 +29,7 @@ class SessionsTest { new Enrollment( EnrollmentType.FREE, new EnrollmentPolicy( + FreeEnrollmentCondition.INSTANCE, new EnrolledUsers(List.of(1L, 2L, 3L, 4L, 5L)), new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), @@ -41,8 +44,7 @@ class SessionsTest { new Enrollment( EnrollmentType.PAID, new EnrollmentPolicy( - 10L, - 10, + new PaidEnrollmentCondition(10L, 10), new EnrolledUsers(List.of(1L, 2L, 3L, 4L, 5L)), new SessionStatus(SessionStatusType.RECRUITING))), LocalDateTime.now(), @@ -54,10 +56,10 @@ class SessionsTest { } @Test - void 찾고자하는_세션이_없으면_에러전파() throws CanNotJoinException { + void 찾고자하는_세션이_없으면_에러전파() { assertThatThrownBy(() -> { new Sessions(freeSession, paidSession) - .findToApplySession(3L); + .findEnrollSession(3L); }) .isInstanceOf(CanNotJoinException.class) .hasMessage("신청하려는 강의가 존재하지 않습니다"); diff --git a/src/test/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentConditionTest.java b/src/test/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentConditionTest.java new file mode 100644 index 000000000..f71ea6a66 --- /dev/null +++ b/src/test/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentConditionTest.java @@ -0,0 +1,17 @@ +package nextstep.courses.domain.enrollmentcondition; + +import static org.assertj.core.api.Assertions.assertThatNoException; + +import nextstep.courses.domain.EnrolledUsers; +import nextstep.payments.domain.Payment; +import org.junit.jupiter.api.Test; + +class FreeEnrollmentConditionTest { + + @Test + void 무료강의에_지불_없이_수강신청한다() throws Exception { + FreeEnrollmentCondition freeEnrollmentCondition = FreeEnrollmentCondition.INSTANCE; + assertThatNoException().isThrownBy(() -> freeEnrollmentCondition.isPaid(new Payment())); + assertThatNoException().isThrownBy(() -> freeEnrollmentCondition.isFull(new EnrolledUsers(100))); + } +} \ No newline at end of file diff --git a/src/test/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentConditionTest.java b/src/test/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentConditionTest.java new file mode 100644 index 000000000..46c41d1ec --- /dev/null +++ b/src/test/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentConditionTest.java @@ -0,0 +1,49 @@ +package nextstep.courses.domain.enrollmentcondition; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.EnrolledUsers; +import nextstep.payments.domain.Payment; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class PaidEnrollmentConditionTest { + + @ParameterizedTest + @ValueSource(longs = {0, -1}) + void 수강료가_음수이면_에러전파(long tuitionFee) { + assertThatThrownBy(() -> new PaidEnrollmentCondition(tuitionFee, 10)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("수강료는 양수이어야 한다"); + } + + @ParameterizedTest + @ValueSource(ints = {0, -1}) + void 정원이_음수이면_에러전파(int maxEnrollment) { + assertThatThrownBy(() -> new PaidEnrollmentCondition(5L, maxEnrollment)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("정원은 양수이어야 한다"); + } + + @Test + void 유료강의에_수강신청한다() { + PaidEnrollmentCondition paidEnrollmentCondition = new PaidEnrollmentCondition(5L, 10); + assertThatNoException().isThrownBy(() -> { + paidEnrollmentCondition.isPaid(new Payment()); + assertThatNoException().isThrownBy(() -> paidEnrollmentCondition.isFull(new EnrolledUsers(8))); + }); + } + + @Test + void 유료강의에_수강신청에_정원이_초과하면_에러전파() { + PaidEnrollmentCondition paidEnrollmentCondition + = new PaidEnrollmentCondition(5L, 10); + + assertThatThrownBy(() -> paidEnrollmentCondition.isFull(new EnrolledUsers(10))) + .isInstanceOf(CanNotJoinException.class) + .hasMessage("이미 정원을 초과했다"); + } +} \ No newline at end of file From 93d0c8aa72782b35d10b8e2c0034725f2a2327f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Fri, 12 Dec 2025 10:23:19 +0900 Subject: [PATCH 29/34] =?UTF-8?q?refactor=20:=20=EB=94=94=EB=A0=89?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EA=B5=AC=EC=A1=B0=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/nextstep/courses/domain/CoverImage.java | 2 +- src/main/java/nextstep/courses/domain/Enrollment.java | 2 +- src/main/java/nextstep/courses/domain/EnrollmentPolicy.java | 2 +- src/main/java/nextstep/courses/domain/SessionStatus.java | 2 +- .../courses/{ => domain}/enumerate/CoverImageType.java | 2 +- .../courses/{ => domain}/enumerate/EnrollmentType.java | 2 +- .../courses/{ => domain}/enumerate/SessionStatusType.java | 2 +- src/test/java/nextstep/courses/domain/CourseTest.java | 6 +++--- src/test/java/nextstep/courses/domain/CoverImageTest.java | 2 +- .../java/nextstep/courses/domain/EnrollmentPolicyTest.java | 2 +- src/test/java/nextstep/courses/domain/EnrollmentTest.java | 4 ++-- .../java/nextstep/courses/domain/SessionStatusTest.java | 2 +- src/test/java/nextstep/courses/domain/SessionTest.java | 6 +++--- src/test/java/nextstep/courses/domain/SessionsTest.java | 6 +++--- .../enumerate}/CoverImageTypeTest.java | 3 +-- 15 files changed, 22 insertions(+), 23 deletions(-) rename src/main/java/nextstep/courses/{ => domain}/enumerate/CoverImageType.java (95%) rename src/main/java/nextstep/courses/{ => domain}/enumerate/EnrollmentType.java (90%) rename src/main/java/nextstep/courses/{ => domain}/enumerate/SessionStatusType.java (61%) rename src/test/java/nextstep/courses/{enumberate => domain/enumerate}/CoverImageTypeTest.java (85%) diff --git a/src/main/java/nextstep/courses/domain/CoverImage.java b/src/main/java/nextstep/courses/domain/CoverImage.java index 3b1c074b9..c41d7174c 100644 --- a/src/main/java/nextstep/courses/domain/CoverImage.java +++ b/src/main/java/nextstep/courses/domain/CoverImage.java @@ -1,7 +1,7 @@ package nextstep.courses.domain; import nextstep.courses.CanNotCreateException; -import nextstep.courses.enumerate.CoverImageType; +import nextstep.courses.domain.enumerate.CoverImageType; public class CoverImage { diff --git a/src/main/java/nextstep/courses/domain/Enrollment.java b/src/main/java/nextstep/courses/domain/Enrollment.java index 3f3d79878..51ff088fb 100644 --- a/src/main/java/nextstep/courses/domain/Enrollment.java +++ b/src/main/java/nextstep/courses/domain/Enrollment.java @@ -3,7 +3,7 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; -import nextstep.courses.enumerate.EnrollmentType; +import nextstep.courses.domain.enumerate.EnrollmentType; import nextstep.payments.domain.Payment; public class Enrollment { diff --git a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java index bcb58f31c..5e891f88d 100644 --- a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java +++ b/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java @@ -2,7 +2,7 @@ import nextstep.courses.CanNotJoinException; import nextstep.courses.domain.enrollmentcondition.EnrollmentCondition; -import nextstep.courses.enumerate.EnrollmentType; +import nextstep.courses.domain.enumerate.EnrollmentType; public class EnrollmentPolicy { diff --git a/src/main/java/nextstep/courses/domain/SessionStatus.java b/src/main/java/nextstep/courses/domain/SessionStatus.java index a7f10ff5a..1cec50f4a 100644 --- a/src/main/java/nextstep/courses/domain/SessionStatus.java +++ b/src/main/java/nextstep/courses/domain/SessionStatus.java @@ -1,7 +1,7 @@ package nextstep.courses.domain; import nextstep.courses.CanNotJoinException; -import nextstep.courses.enumerate.SessionStatusType; +import nextstep.courses.domain.enumerate.SessionStatusType; public class SessionStatus { diff --git a/src/main/java/nextstep/courses/enumerate/CoverImageType.java b/src/main/java/nextstep/courses/domain/enumerate/CoverImageType.java similarity index 95% rename from src/main/java/nextstep/courses/enumerate/CoverImageType.java rename to src/main/java/nextstep/courses/domain/enumerate/CoverImageType.java index 81524ad1b..30aa7c242 100644 --- a/src/main/java/nextstep/courses/enumerate/CoverImageType.java +++ b/src/main/java/nextstep/courses/domain/enumerate/CoverImageType.java @@ -1,4 +1,4 @@ -package nextstep.courses.enumerate; +package nextstep.courses.domain.enumerate; import nextstep.courses.CanNotCreateException; diff --git a/src/main/java/nextstep/courses/enumerate/EnrollmentType.java b/src/main/java/nextstep/courses/domain/enumerate/EnrollmentType.java similarity index 90% rename from src/main/java/nextstep/courses/enumerate/EnrollmentType.java rename to src/main/java/nextstep/courses/domain/enumerate/EnrollmentType.java index a893e0af6..bb6213e0e 100644 --- a/src/main/java/nextstep/courses/enumerate/EnrollmentType.java +++ b/src/main/java/nextstep/courses/domain/enumerate/EnrollmentType.java @@ -1,4 +1,4 @@ -package nextstep.courses.enumerate; +package nextstep.courses.domain.enumerate; public enum EnrollmentType { PAID("paid", true), diff --git a/src/main/java/nextstep/courses/enumerate/SessionStatusType.java b/src/main/java/nextstep/courses/domain/enumerate/SessionStatusType.java similarity index 61% rename from src/main/java/nextstep/courses/enumerate/SessionStatusType.java rename to src/main/java/nextstep/courses/domain/enumerate/SessionStatusType.java index 8904938bd..6f6d76855 100644 --- a/src/main/java/nextstep/courses/enumerate/SessionStatusType.java +++ b/src/main/java/nextstep/courses/domain/enumerate/SessionStatusType.java @@ -1,4 +1,4 @@ -package nextstep.courses.enumerate; +package nextstep.courses.domain.enumerate; public enum SessionStatusType { PREPARATION, RECRUITING, END diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 1d49cc9c1..e7f28fbfd 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -9,9 +9,9 @@ import nextstep.courses.CanNotJoinException; import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.enumerate.CoverImageType; -import nextstep.courses.enumerate.EnrollmentType; -import nextstep.courses.enumerate.SessionStatusType; +import nextstep.courses.domain.enumerate.CoverImageType; +import nextstep.courses.domain.enumerate.EnrollmentType; +import nextstep.courses.domain.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; diff --git a/src/test/java/nextstep/courses/domain/CoverImageTest.java b/src/test/java/nextstep/courses/domain/CoverImageTest.java index 9aa17954f..78efed4fe 100644 --- a/src/test/java/nextstep/courses/domain/CoverImageTest.java +++ b/src/test/java/nextstep/courses/domain/CoverImageTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; -import nextstep.courses.enumerate.CoverImageType; +import nextstep.courses.domain.enumerate.CoverImageType; import org.junit.jupiter.api.Test; class CoverImageTest { diff --git a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java index 81b354367..470b03cc8 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java @@ -6,7 +6,7 @@ import nextstep.courses.CanNotJoinException; import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.enumerate.SessionStatusType; +import nextstep.courses.domain.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; diff --git a/src/test/java/nextstep/courses/domain/EnrollmentTest.java b/src/test/java/nextstep/courses/domain/EnrollmentTest.java index cca8d5040..c1095d713 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentTest.java @@ -6,8 +6,8 @@ import nextstep.courses.CanNotCreateException; import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.enumerate.EnrollmentType; -import nextstep.courses.enumerate.SessionStatusType; +import nextstep.courses.domain.enumerate.EnrollmentType; +import nextstep.courses.domain.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; diff --git a/src/test/java/nextstep/courses/domain/SessionStatusTest.java b/src/test/java/nextstep/courses/domain/SessionStatusTest.java index a787f846d..a7e1dfdb2 100644 --- a/src/test/java/nextstep/courses/domain/SessionStatusTest.java +++ b/src/test/java/nextstep/courses/domain/SessionStatusTest.java @@ -3,7 +3,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotJoinException; -import nextstep.courses.enumerate.SessionStatusType; +import nextstep.courses.domain.enumerate.SessionStatusType; import org.junit.jupiter.api.Test; class SessionStatusTest { diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index cef4ab6b6..350872371 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -7,9 +7,9 @@ import java.util.List; import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.enumerate.CoverImageType; -import nextstep.courses.enumerate.EnrollmentType; -import nextstep.courses.enumerate.SessionStatusType; +import nextstep.courses.domain.enumerate.CoverImageType; +import nextstep.courses.domain.enumerate.EnrollmentType; +import nextstep.courses.domain.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; diff --git a/src/test/java/nextstep/courses/domain/SessionsTest.java b/src/test/java/nextstep/courses/domain/SessionsTest.java index 00df4ee8c..e8c84301f 100644 --- a/src/test/java/nextstep/courses/domain/SessionsTest.java +++ b/src/test/java/nextstep/courses/domain/SessionsTest.java @@ -8,9 +8,9 @@ import nextstep.courses.CanNotJoinException; import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.enumerate.CoverImageType; -import nextstep.courses.enumerate.EnrollmentType; -import nextstep.courses.enumerate.SessionStatusType; +import nextstep.courses.domain.enumerate.CoverImageType; +import nextstep.courses.domain.enumerate.EnrollmentType; +import nextstep.courses.domain.enumerate.SessionStatusType; import org.junit.jupiter.api.Test; class SessionsTest { diff --git a/src/test/java/nextstep/courses/enumberate/CoverImageTypeTest.java b/src/test/java/nextstep/courses/domain/enumerate/CoverImageTypeTest.java similarity index 85% rename from src/test/java/nextstep/courses/enumberate/CoverImageTypeTest.java rename to src/test/java/nextstep/courses/domain/enumerate/CoverImageTypeTest.java index e87ffea5d..2f8aa51bb 100644 --- a/src/test/java/nextstep/courses/enumberate/CoverImageTypeTest.java +++ b/src/test/java/nextstep/courses/domain/enumerate/CoverImageTypeTest.java @@ -1,9 +1,8 @@ -package nextstep.courses.enumberate; +package nextstep.courses.domain.enumerate; import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; -import nextstep.courses.enumerate.CoverImageType; import org.junit.jupiter.api.Test; class CoverImageTypeTest { From 7ca2fd52c6bc24910c9b6162afc66242240bfc99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Fri, 12 Dec 2025 22:06:20 +0900 Subject: [PATCH 30/34] =?UTF-8?q?refactor=20:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=94=BD=EC=8A=A4=EC=B3=90=EB=A5=BC=20'=EC=98=A4?= =?UTF-8?q?=EB=B8=8C=EC=A0=9D=ED=8A=B8=20=EB=A7=88=EB=8D=94=20=ED=8C=A8?= =?UTF-8?q?=ED=84=B4'=20+=20=EB=B9=8C=EB=8D=94=ED=8C=A8=ED=84=B4(=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EA=B0=92=20=EC=88=A8=EA=B8=B0=EA=B8=B0,=20?= =?UTF-8?q?=EB=B9=8C=EB=8D=94=20=EB=8D=9C=EC=93=B0=EA=B8=B0,=20=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?=EC=9D=B4=EC=9A=A9=ED=95=B4=20=EB=8F=84=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EA=B0=95=EC=A1=B0,=20=EB=B9=84=EC=8A=B7=ED=95=9C=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20=EC=9D=B4=EC=9A=A9=20=EC=8B=9C=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A4=84=EC=9D=B4=EA=B8=B0=EC=9C=84=ED=95=9C=20but?= =?UTF-8?q?=20=EC=82=AC=EC=9A=A9)=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=97=AC?= =?UTF-8?q?=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/builder/FreeEnrollmentBuilder.java | 43 +++++++++ .../builder/FreeEnrollmentPolicyBuilder.java | 52 ++++++++++ .../domain/builder/FreeSessionBuilder.java | 70 ++++++++++++++ .../domain/builder/PaidEnrollmentBuilder.java | 45 +++++++++ .../builder/PaidEnrollmentPolicyBuilder.java | 52 ++++++++++ .../domain/builder/PaidSessionBuilder.java | 70 ++++++++++++++ .../nextstep/courses/domain/CourseTest.java | 94 +++++++++++-------- .../courses/domain/EnrollmentPolicyTest.java | 23 ++--- .../courses/domain/EnrollmentTest.java | 34 ++----- .../nextstep/courses/domain/SessionTest.java | 90 +++++++----------- 10 files changed, 438 insertions(+), 135 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/builder/FreeEnrollmentBuilder.java create mode 100644 src/main/java/nextstep/courses/domain/builder/FreeEnrollmentPolicyBuilder.java create mode 100644 src/main/java/nextstep/courses/domain/builder/FreeSessionBuilder.java create mode 100644 src/main/java/nextstep/courses/domain/builder/PaidEnrollmentBuilder.java create mode 100644 src/main/java/nextstep/courses/domain/builder/PaidEnrollmentPolicyBuilder.java create mode 100644 src/main/java/nextstep/courses/domain/builder/PaidSessionBuilder.java diff --git a/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentBuilder.java b/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentBuilder.java new file mode 100644 index 000000000..0491adb70 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentBuilder.java @@ -0,0 +1,43 @@ +package nextstep.courses.domain.builder; + +import static nextstep.courses.domain.builder.FreeEnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; + +import nextstep.courses.CanNotCreateException; +import nextstep.courses.domain.Enrollment; +import nextstep.courses.domain.EnrollmentPolicy; +import nextstep.courses.domain.enumerate.EnrollmentType; + +public class FreeEnrollmentBuilder { + + private EnrollmentType enrollmentType = EnrollmentType.FREE; + private EnrollmentPolicy enrollmentPolicy = aFreeEnrollmentPolicyBuilder().build(); + + public static FreeEnrollmentBuilder aFreeEnrollmentBuilder() { + return new FreeEnrollmentBuilder(); + } + + private FreeEnrollmentBuilder() {} + + private FreeEnrollmentBuilder(FreeEnrollmentBuilder copy) { + this.enrollmentType = copy.enrollmentType; + this.enrollmentPolicy = copy.enrollmentPolicy; + } + + public FreeEnrollmentBuilder withEnrollmentType(EnrollmentType enrollmentType) { + this.enrollmentType = enrollmentType; + return this; + } + + public FreeEnrollmentBuilder withEnrollmentPolicy(EnrollmentPolicy enrollmentPolicy) { + this.enrollmentPolicy = enrollmentPolicy; + return this; + } + + public Enrollment build() throws CanNotCreateException { + return new Enrollment(enrollmentType, enrollmentPolicy); + } + + public FreeEnrollmentBuilder but() { + return new FreeEnrollmentBuilder(this); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentPolicyBuilder.java b/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentPolicyBuilder.java new file mode 100644 index 000000000..ce228a6b5 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentPolicyBuilder.java @@ -0,0 +1,52 @@ +package nextstep.courses.domain.builder; + +import java.util.List; +import nextstep.courses.domain.EnrolledUsers; +import nextstep.courses.domain.EnrollmentPolicy; +import nextstep.courses.domain.SessionStatus; +import nextstep.courses.domain.enrollmentcondition.EnrollmentCondition; +import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.enumerate.SessionStatusType; + +public class FreeEnrollmentPolicyBuilder { + + private EnrollmentCondition enrollmentCondition = FreeEnrollmentCondition.INSTANCE; + private EnrolledUsers enrolledUsers = new EnrolledUsers(List.of(1L, 2L, 3L, 4L, 5L)); + private SessionStatus status = new SessionStatus(SessionStatusType.RECRUITING); + + public static FreeEnrollmentPolicyBuilder aFreeEnrollmentPolicyBuilder() { + return new FreeEnrollmentPolicyBuilder(); + } + + private FreeEnrollmentPolicyBuilder() {} + + private FreeEnrollmentPolicyBuilder(FreeEnrollmentPolicyBuilder copy) { + this.enrollmentCondition = copy.enrollmentCondition; + this.enrolledUsers = copy.enrolledUsers; + this.status = copy.status; + } + + public FreeEnrollmentPolicyBuilder withEnrollmentCondition(EnrollmentCondition enrollmentCondition) { + this.enrollmentCondition = enrollmentCondition; + return this; + } + + public FreeEnrollmentPolicyBuilder withEnrolledUsers(EnrolledUsers enrolledUsers) { + this.enrolledUsers = enrolledUsers; + return this; + } + + public FreeEnrollmentPolicyBuilder withSessionStatus(SessionStatus sessionStatus) { + this.status = sessionStatus; + return this; + } + + public EnrollmentPolicy build() { + return new EnrollmentPolicy(enrollmentCondition, enrolledUsers, status); + } + + public FreeEnrollmentPolicyBuilder but() { + return new FreeEnrollmentPolicyBuilder(this); + } + +} diff --git a/src/main/java/nextstep/courses/domain/builder/FreeSessionBuilder.java b/src/main/java/nextstep/courses/domain/builder/FreeSessionBuilder.java new file mode 100644 index 000000000..7dee4fc0c --- /dev/null +++ b/src/main/java/nextstep/courses/domain/builder/FreeSessionBuilder.java @@ -0,0 +1,70 @@ +package nextstep.courses.domain.builder; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import nextstep.courses.CanNotCreateException; +import nextstep.courses.domain.*; +import nextstep.courses.domain.enumerate.CoverImageType; + +public class FreeSessionBuilder { + + private Long id = 1L; + private String creatorId = "1"; + private SessionBody body = new SessionBody("title", "content"); + private Duration duration = new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)); + private CoverImage coverImage = new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200); + private Enrollment enrollment = FreeEnrollmentBuilder.aFreeEnrollmentBuilder().build(); + + public static FreeSessionBuilder aFreeSessionBuilder() throws CanNotCreateException { + return new FreeSessionBuilder(); + } + + public FreeSessionBuilder(FreeSessionBuilder copy) throws CanNotCreateException { + this.id = copy.id; + this.creatorId = copy.creatorId; + this.body = copy.body; + this.duration = copy.duration; + this.coverImage = copy.coverImage; + this.enrollment = copy.enrollment; + } + + private FreeSessionBuilder() throws CanNotCreateException {} + + public FreeSessionBuilder withId(Long id) { + this.id = id; + return this; + } + + public FreeSessionBuilder withCreatorId(String creatorId) { + this.creatorId = creatorId; + return this; + } + + public FreeSessionBuilder withBody(SessionBody body) { + this.body = body; + return this; + } + + public FreeSessionBuilder withDuration(Duration duration) { + this.duration = duration; + return this; + } + + public FreeSessionBuilder withCoverImage(CoverImage coverImage) { + this.coverImage = coverImage; + return this; + } + + public FreeSessionBuilder withEnrollment(Enrollment enrollment) { + this.enrollment = enrollment; + return this; + } + + public Session build() { + return new Session(id, creatorId, body, duration, coverImage, enrollment, LocalDateTime.now(), null); + } + + public FreeSessionBuilder but() throws CanNotCreateException { + return new FreeSessionBuilder(this); + } +} diff --git a/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentBuilder.java b/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentBuilder.java new file mode 100644 index 000000000..89006bd82 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentBuilder.java @@ -0,0 +1,45 @@ +package nextstep.courses.domain.builder; + +import static nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; + +import nextstep.courses.CanNotCreateException; +import nextstep.courses.domain.Enrollment; +import nextstep.courses.domain.EnrollmentPolicy; +import nextstep.courses.domain.enumerate.EnrollmentType; + +public class PaidEnrollmentBuilder { + + private EnrollmentType enrollmentType = EnrollmentType.PAID; + private EnrollmentPolicy enrollmentPolicy = aPaidEnrollmentPolicyBuilder().build(); + + public static PaidEnrollmentBuilder aPaidEnrollmentBuilder() { + return new PaidEnrollmentBuilder(); + } + + private PaidEnrollmentBuilder() {} + + private PaidEnrollmentBuilder(PaidEnrollmentBuilder copy) { + this.enrollmentType = copy.enrollmentType; + this.enrollmentPolicy = copy.enrollmentPolicy; + } + + public PaidEnrollmentBuilder withEnrollmentType(EnrollmentType enrollmentType) { + this.enrollmentType = enrollmentType; + return this; + } + + public PaidEnrollmentBuilder withEnrollmentPolicy(EnrollmentPolicy enrollmentPolicy) { + this.enrollmentPolicy = enrollmentPolicy; + return this; + } + + public Enrollment build() throws CanNotCreateException { + return new Enrollment(enrollmentType, enrollmentPolicy); + } + + public PaidEnrollmentBuilder but() { + return new PaidEnrollmentBuilder(this); + } + + +} diff --git a/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentPolicyBuilder.java b/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentPolicyBuilder.java new file mode 100644 index 000000000..10d3305c5 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentPolicyBuilder.java @@ -0,0 +1,52 @@ +package nextstep.courses.domain.builder; + +import java.util.List; +import nextstep.courses.domain.EnrolledUsers; +import nextstep.courses.domain.EnrollmentPolicy; +import nextstep.courses.domain.SessionStatus; +import nextstep.courses.domain.enrollmentcondition.EnrollmentCondition; +import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; +import nextstep.courses.domain.enumerate.SessionStatusType; + +public class PaidEnrollmentPolicyBuilder { + + private EnrollmentCondition enrollmentCondition = new PaidEnrollmentCondition(10L, 10); + private EnrolledUsers enrolledUsers = new EnrolledUsers(List.of(1L, 2L, 3L, 4L, 5L)); + private SessionStatus status = new SessionStatus(SessionStatusType.RECRUITING); + + public static PaidEnrollmentPolicyBuilder aPaidEnrollmentPolicyBuilder() { + return new PaidEnrollmentPolicyBuilder(); + } + + private PaidEnrollmentPolicyBuilder() {} + + private PaidEnrollmentPolicyBuilder(PaidEnrollmentPolicyBuilder copy) { + this.enrollmentCondition = copy.enrollmentCondition; + this.enrolledUsers = copy.enrolledUsers; + this.status = copy.status; + } + + public PaidEnrollmentPolicyBuilder withEnrollmentCondition(EnrollmentCondition enrollmentCondition) { + this.enrollmentCondition = enrollmentCondition; + return this; + } + + public PaidEnrollmentPolicyBuilder withEnrolledUsers(EnrolledUsers enrolledUsers) { + this.enrolledUsers = enrolledUsers; + return this; + } + + public PaidEnrollmentPolicyBuilder withSessionStatus(SessionStatus sessionStatus) { + this.status = sessionStatus; + return this; + } + + public EnrollmentPolicy build() { + return new EnrollmentPolicy(enrollmentCondition, enrolledUsers, status); + } + + public PaidEnrollmentPolicyBuilder but() { + return new PaidEnrollmentPolicyBuilder(this); + } + +} diff --git a/src/main/java/nextstep/courses/domain/builder/PaidSessionBuilder.java b/src/main/java/nextstep/courses/domain/builder/PaidSessionBuilder.java new file mode 100644 index 000000000..6e731bc6a --- /dev/null +++ b/src/main/java/nextstep/courses/domain/builder/PaidSessionBuilder.java @@ -0,0 +1,70 @@ +package nextstep.courses.domain.builder; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import nextstep.courses.CanNotCreateException; +import nextstep.courses.domain.*; +import nextstep.courses.domain.enumerate.CoverImageType; + +public class PaidSessionBuilder { + + private Long id = 2L; + private String creatorId = "1"; + private SessionBody body = new SessionBody("title", "content"); + private Duration duration = new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)); + private CoverImage coverImage = new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200); + private Enrollment enrollment = PaidEnrollmentBuilder.aPaidEnrollmentBuilder().build(); + + public static PaidSessionBuilder aPaidSessionBuilder() throws CanNotCreateException { + return new PaidSessionBuilder(); + } + + public PaidSessionBuilder(PaidSessionBuilder copy) throws CanNotCreateException { + this.id = copy.id; + this.creatorId = copy.creatorId; + this.body = copy.body; + this.duration = copy.duration; + this.coverImage = copy.coverImage; + this.enrollment = copy.enrollment; + } + + private PaidSessionBuilder() throws CanNotCreateException {} + + public PaidSessionBuilder withId(Long id) { + this.id = id; + return this; + } + + public PaidSessionBuilder withCreatorId(String creatorId) { + this.creatorId = creatorId; + return this; + } + + public PaidSessionBuilder withBody(SessionBody body) { + this.body = body; + return this; + } + + public PaidSessionBuilder withDuration(Duration duration) { + this.duration = duration; + return this; + } + + public PaidSessionBuilder withCoverImage(CoverImage coverImage) { + this.coverImage = coverImage; + return this; + } + + public PaidSessionBuilder withEnrollment(Enrollment enrollment) { + this.enrollment = enrollment; + return this; + } + + public Session build() { + return new Session(id, creatorId, body, duration, coverImage, enrollment, LocalDateTime.now(), null); + } + + public PaidSessionBuilder but() throws CanNotCreateException { + return new PaidSessionBuilder(this); + } +} diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index e7f28fbfd..45a4618ea 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -1,17 +1,17 @@ package nextstep.courses.domain; +import static nextstep.courses.domain.builder.FreeEnrollmentBuilder.aFreeEnrollmentBuilder; +import static nextstep.courses.domain.builder.FreeEnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.FreeSessionBuilder.aFreeSessionBuilder; +import static nextstep.courses.domain.builder.PaidEnrollmentBuilder.aPaidEnrollmentBuilder; +import static nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.PaidSessionBuilder.aPaidSessionBuilder; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.List; +import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; -import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; -import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.domain.enumerate.CoverImageType; -import nextstep.courses.domain.enumerate.EnrollmentType; -import nextstep.courses.domain.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; @@ -23,37 +23,8 @@ class CourseTest { static { try { - freeSession = new Session( - 1L, - "1", - new SessionBody("title", "content"), - new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Enrollment( - EnrollmentType.FREE, - new EnrollmentPolicy( - FreeEnrollmentCondition.INSTANCE, - new EnrolledUsers(List.of(4L, 5L, 6L, 7L, 8L, 9L)), - new SessionStatus(SessionStatusType.RECRUITING))), - LocalDateTime.now(), - null - ); - - paidSession = new Session( - 2L, - "1", - new SessionBody("title", "content"), - new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Enrollment( - EnrollmentType.PAID, - new EnrollmentPolicy( - new PaidEnrollmentCondition(10L, 10), - new EnrolledUsers(List.of(4L, 5L, 6L, 7L, 8L, 9L)), - new SessionStatus(SessionStatusType.RECRUITING))), - LocalDateTime.now(), - null - ); + freeSession = aFreeSessionBuilder().build(); + paidSession = aPaidSessionBuilder().build(); } catch(Exception e) { throw new RuntimeException(e); } @@ -69,16 +40,59 @@ class CourseTest { } @Test - void 무료강의_수강신청() { + void 무료강의_수강신청() throws CanNotCreateException { + Session freeSession = aFreeSessionBuilder() + .withEnrollment( + aFreeEnrollmentBuilder() + .withEnrollmentPolicy( + aFreeEnrollmentPolicyBuilder() + .withEnrolledUsers(new EnrolledUsers(List.of(10L, 11L, 12L, 13L, 14L, 15L))) + .build() + ).build() + ) + .build(); + Session paidSession = aPaidSessionBuilder() + .withEnrollment( + aPaidEnrollmentBuilder() + .withEnrollmentPolicy( + aPaidEnrollmentPolicyBuilder() + .withEnrolledUsers(new EnrolledUsers(List.of(10L, 11L, 12L, 13L, 14L, 15L))) + .build() + ).build() + ) + .build(); + Course course = new Course("title", 1L, List.of(freeSession, paidSession)); + assertThatNoException().isThrownBy(() -> { course.enrollCourse(NsUserTest.JAVAJIGI.getId(), 1L, null); }); } @Test - void 유료강의_수강신청() { + void 유료강의_수강신청() throws CanNotCreateException { + Session freeSession = aFreeSessionBuilder() + .withEnrollment( + aFreeEnrollmentBuilder() + .withEnrollmentPolicy( + aFreeEnrollmentPolicyBuilder() + .withEnrolledUsers(new EnrolledUsers(List.of(10L, 11L, 12L, 13L, 14L, 15L))) + .build() + ).build() + ) + .build(); + Session paidSession = aPaidSessionBuilder() + .withEnrollment( + aPaidEnrollmentBuilder() + .withEnrollmentPolicy( + aPaidEnrollmentPolicyBuilder() + .withEnrolledUsers(new EnrolledUsers(List.of(10L, 11L, 12L, 13L, 14L, 15L))) + .build() + ).build() + ) + .build(); Course course = new Course("title", 1L, List.of(freeSession, paidSession)); + assertThatNoException().isThrownBy(() -> { course.enrollCourse(NsUserTest.SANJIGI.getId(), 2L, new Payment()); }); diff --git a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java index 470b03cc8..b4e97cf6b 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java @@ -1,24 +1,21 @@ package nextstep.courses.domain; +import static nextstep.courses.domain.builder.FreeEnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotJoinException; -import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; -import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.domain.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; class EnrollmentPolicyTest { @Test - void 수강신청_인원이_초과하면_에러전파() throws Exception { - EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy( - new PaidEnrollmentCondition(5L, 10), - new EnrolledUsers(10), - new SessionStatus(SessionStatusType.RECRUITING) - ); + void 수강신청_인원이_초과하면_에러전파() { + EnrollmentPolicy enrollmentPolicy = aPaidEnrollmentPolicyBuilder() + .withEnrolledUsers(new EnrolledUsers(10)) + .build(); SessionApply sessionApply = new SessionApply(10L, new Payment()); assertThatThrownBy(() -> { @@ -28,13 +25,9 @@ class EnrollmentPolicyTest { } @Test - void 무료강의인데_수강신청_시_정원체크를_해도_상관없다() throws Exception { + void 무료강의인데_수강신청_시_정원체크를_해도_상관없다() { SessionApply sessionApply = new SessionApply(1000L, new Payment()); - EnrollmentPolicy enrollmentPolicy = new EnrollmentPolicy( - FreeEnrollmentCondition.INSTANCE, - new EnrolledUsers(8), - new SessionStatus(SessionStatusType.RECRUITING) - ); + EnrollmentPolicy enrollmentPolicy = aFreeEnrollmentPolicyBuilder().build(); assertThatNoException().isThrownBy(() -> { enrollmentPolicy.enroll(sessionApply); diff --git a/src/test/java/nextstep/courses/domain/EnrollmentTest.java b/src/test/java/nextstep/courses/domain/EnrollmentTest.java index c1095d713..281628f54 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentTest.java @@ -4,10 +4,9 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; -import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; -import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.domain.enumerate.EnrollmentType; -import nextstep.courses.domain.enumerate.SessionStatusType; +import nextstep.courses.domain.builder.FreeEnrollmentBuilder; +import nextstep.courses.domain.builder.PaidEnrollmentBuilder; +import nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; @@ -16,23 +15,18 @@ class EnrollmentTest { @Test void 무료강의인데_수강료가있으면_에러전파() { assertThatThrownBy(() -> { - new Enrollment(EnrollmentType.FREE, new EnrollmentPolicy(new PaidEnrollmentCondition(5L, 10))); + FreeEnrollmentBuilder.aFreeEnrollmentBuilder() + .withEnrollmentPolicy( + PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder().build() + ) + .build(); }).isInstanceOf(CanNotCreateException.class) .hasMessage("강의타입과 정책이 일치하지 않습니다"); } @Test void 유료강의에_수강신청한다() throws Exception { - Enrollment enrollment = - new Enrollment( - EnrollmentType.PAID, - new EnrollmentPolicy( - new PaidEnrollmentCondition(5L, 10), - new EnrolledUsers(8), - new SessionStatus(SessionStatusType.RECRUITING) - ) - ); - + Enrollment enrollment = PaidEnrollmentBuilder.aPaidEnrollmentBuilder().build(); assertThatNoException().isThrownBy(() -> { enrollment.enroll(10L, new Payment()); }); @@ -40,15 +34,7 @@ class EnrollmentTest { @Test void 무료강의에_지불_없이_수강신청한다() throws Exception { - Enrollment enrollment = - new Enrollment( - EnrollmentType.FREE, - new EnrollmentPolicy( - FreeEnrollmentCondition.INSTANCE, - new EnrolledUsers(8), - new SessionStatus(SessionStatusType.RECRUITING) - ) - ); + Enrollment enrollment = FreeEnrollmentBuilder.aFreeEnrollmentBuilder().build(); assertThatNoException().isThrownBy(() -> enrollment.enroll(10L)); } diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 350872371..19f2c0a95 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -1,15 +1,14 @@ package nextstep.courses.domain; +import static nextstep.courses.domain.builder.FreeEnrollmentBuilder.aFreeEnrollmentBuilder; +import static nextstep.courses.domain.builder.FreeEnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.FreeSessionBuilder.aFreeSessionBuilder; +import static nextstep.courses.domain.builder.PaidEnrollmentBuilder.aPaidEnrollmentBuilder; +import static nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.PaidSessionBuilder.aPaidSessionBuilder; import static org.assertj.core.api.Assertions.assertThatNoException; -import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.List; -import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; -import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.domain.enumerate.CoverImageType; -import nextstep.courses.domain.enumerate.EnrollmentType; -import nextstep.courses.domain.enumerate.SessionStatusType; import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; @@ -21,79 +20,58 @@ class SessionTest { static { try { - freeSession = new Session( - 1L, - "1", - new SessionBody("title", "content"), - new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Enrollment( - EnrollmentType.FREE, - new EnrollmentPolicy( - FreeEnrollmentCondition.INSTANCE, - new EnrolledUsers(List.of(11L, 12L, 13L, 14L, 15L)), - new SessionStatus(SessionStatusType.RECRUITING))), - LocalDateTime.now(), - null - ); - - paidSession = new Session( - 2L, - "1", - new SessionBody("title", "content"), - new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Enrollment( - EnrollmentType.PAID, - new EnrollmentPolicy( - new PaidEnrollmentCondition(5L, 10), - new EnrolledUsers(List.of(11L, 12L, 13L, 14L, 15L)), - new SessionStatus(SessionStatusType.RECRUITING))), - LocalDateTime.now(), - null - ); + freeSession = aFreeSessionBuilder().build(); + paidSession = aPaidSessionBuilder().build(); } catch(Exception e) { throw new RuntimeException(e); } } - @Test - void 무료_session을_생성한다() throws Exception { + void 무료_session을_생성한다() { assertThatNoException().isThrownBy(() -> { - new Session( - "1", - new SessionBody("title", "content"), - new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Enrollment(EnrollmentType.FREE) - ); + aFreeSessionBuilder().build(); }); } + @Test void 유료_session을_생성한다() throws Exception { assertThatNoException().isThrownBy(() -> { - new Session( - "1", - new SessionBody("title", "content"), - new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)), - new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200), - new Enrollment(EnrollmentType.PAID, new EnrollmentPolicy(new PaidEnrollmentCondition(10L, 10))) - ); + aPaidSessionBuilder().build(); }); } @Test - void 무료_session을_수강신청한다() throws Exception { + void 무료_session을_수강신청한다() { assertThatNoException().isThrownBy(() -> { + Session freeSession = aFreeSessionBuilder() + .withEnrollment( + aFreeEnrollmentBuilder() + .withEnrollmentPolicy( + aFreeEnrollmentPolicyBuilder() + .withEnrolledUsers(new EnrolledUsers(List.of(10L, 11L, 12L, 13L, 14L, 15L))) + .build() + ).build() + ) + .build(); freeSession.enrollSession(NsUserTest.JAVAJIGI.getId()); }); } @Test - void 유료_session을_수강신청한다() throws Exception { + void 유료_session을_수강신청한다() { assertThatNoException().isThrownBy(() -> { + Session paidSession = aPaidSessionBuilder() + .withEnrollment( + aPaidEnrollmentBuilder() + .withEnrollmentPolicy( + aPaidEnrollmentPolicyBuilder() + .withEnrolledUsers(new EnrolledUsers(List.of(10L, 11L, 12L, 13L, 14L, 15L))) + .build() + ).build() + ) + .build(); paidSession.enrollSession(NsUserTest.JAVAJIGI.getId(), new Payment()); }); } From d16f9884aaf621718d1ca1043bd01d4290d555a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Fri, 12 Dec 2025 22:07:21 +0900 Subject: [PATCH 31/34] =?UTF-8?q?docs=20:=20=EB=A6=AC=ED=8C=A9=ED=84=B0?= =?UTF-8?q?=EB=A7=81=20=EA=B8=B0=EC=A4=80=20=EB=A9=94=EB=AA=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f9ec9fa11..5c53181b2 100644 --- a/README.md +++ b/README.md @@ -218,4 +218,23 @@ Duration → CoverImage → SessionStatus → ProvideType → Session → Course - [x] : 수강신청한 수강생의 정보 넣기 - [x] : 결제 완료를 기준으로 던지기 -- [x] : 컬렉션을 일급 컬렉션으로 바꾸기 (EnrolledUsers, Sessions) \ No newline at end of file +- [x] : 컬렉션을 일급 컬렉션으로 바꾸기 (EnrolledUsers, Sessions) + +## 1차 피드백 + +- [x] : 무료 유료인 상태의 객체 구분을 null로 구현이 아닌, null을 추상화한 Null Object 로 추가 + - 인터페이스로 null Object 로 구분하기 / 그에 따라서 구현하는 방향 바꾸기 + - 무료는 싱글턴 null 객체로, 유료는 생성자로 초기화 + - DI 방식으로 하니 무분별하게 분기 칠 필요가 없어짐 +- [x] : 무료 유료 구분은 생성자 유무가 아닌 ProvideType 값에 따라 결정 + - apply() 분기도 마찬가지 +- [x] : Base 추상클래스로 구현하여 직접 생상안되게 하기 +- [x] : CoverImage 필드 수 줄이기 +- [x] : boolean 타입이 아닌데 is 로 시작하는 메서드명 validate 시작으로 변경 +- [x] : `ProvidePolicy` 에 수강신청 판단 하는 모든 값 가져도 될지 고민하기 + - SessionStatus, 현재 수강신청한 수강생 목록도 신청여부 판단에 필요한 값 + - -> 이름을 Enrollment의 EnrollmentPolicy로 몀명하니 필요성을 가지게 됨 +- [x] : 복잡한 객체의 테스트 데이터 생성 시 중복코드 많고, 생성자 인자가 변경되는 경우 변경할 부분이 많음 + - 테스트 데이터 생성 시 방법 탐색해서 적용 후 앞으로 활용하기 + - 테스트 픽스쳐를 '오브젝트 마더 패턴' + 빌더패턴'(기본 값 숨기기, 빌더 덜쓰기, 팩토리 메서드를 이용해 도메인 강조, 비슷한 객체를 이용 시 코드 줄이기위한 but 사용) + - 이용해서 축소 \ No newline at end of file From 44f0d33050d3c41a41da9f6f27b5edc1028f5994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Fri, 12 Dec 2025 22:44:14 +0900 Subject: [PATCH 32/34] =?UTF-8?q?refactor=20:=20Free,=20Paid=EB=A1=9C=20?= =?UTF-8?q?=EB=82=98=EB=88=84=EC=96=B4=EC=A7=84=20Builder=EB=A5=BC=20?= =?UTF-8?q?=ED=95=98=EB=82=98=EB=A1=9C=20=ED=95=A9=EC=B3=90=EC=84=9C=20?= =?UTF-8?q?=EA=B0=84=EC=86=8C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/Session.java | 7 -- .../domain/builder/EnrollmentBuilder.java | 52 ++++++++++++++ .../builder/EnrollmentPolicyBuilder.java | 63 +++++++++++++++++ .../domain/builder/FreeEnrollmentBuilder.java | 43 ------------ .../builder/FreeEnrollmentPolicyBuilder.java | 52 -------------- .../domain/builder/PaidEnrollmentBuilder.java | 45 ------------ .../builder/PaidEnrollmentPolicyBuilder.java | 52 -------------- .../domain/builder/PaidSessionBuilder.java | 70 ------------------- ...essionBuilder.java => SessionBuilder.java} | 37 ++++++---- .../nextstep/courses/domain/CourseTest.java | 14 ++-- .../courses/domain/EnrollmentPolicyTest.java | 4 +- .../courses/domain/EnrollmentTest.java | 14 ++-- .../nextstep/courses/domain/SessionTest.java | 12 ++-- 13 files changed, 161 insertions(+), 304 deletions(-) create mode 100644 src/main/java/nextstep/courses/domain/builder/EnrollmentBuilder.java create mode 100644 src/main/java/nextstep/courses/domain/builder/EnrollmentPolicyBuilder.java delete mode 100644 src/main/java/nextstep/courses/domain/builder/FreeEnrollmentBuilder.java delete mode 100644 src/main/java/nextstep/courses/domain/builder/FreeEnrollmentPolicyBuilder.java delete mode 100644 src/main/java/nextstep/courses/domain/builder/PaidEnrollmentBuilder.java delete mode 100644 src/main/java/nextstep/courses/domain/builder/PaidEnrollmentPolicyBuilder.java delete mode 100644 src/main/java/nextstep/courses/domain/builder/PaidSessionBuilder.java rename src/main/java/nextstep/courses/domain/builder/{FreeSessionBuilder.java => SessionBuilder.java} (53%) diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java index 7b0043388..0584d2bcb 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/Session.java @@ -44,11 +44,4 @@ public boolean isSameSessionId(Long id) { return Objects.equals(this.id, id); } - public boolean isPaidSession() { - return enrollment.isPaid(); - } - - public boolean isFreeSession() { - return enrollment.isFree(); - } } \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/builder/EnrollmentBuilder.java b/src/main/java/nextstep/courses/domain/builder/EnrollmentBuilder.java new file mode 100644 index 000000000..f8459af6c --- /dev/null +++ b/src/main/java/nextstep/courses/domain/builder/EnrollmentBuilder.java @@ -0,0 +1,52 @@ +package nextstep.courses.domain.builder; + +import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; + +import nextstep.courses.CanNotCreateException; +import nextstep.courses.domain.Enrollment; +import nextstep.courses.domain.EnrollmentPolicy; +import nextstep.courses.domain.enumerate.EnrollmentType; + +public class EnrollmentBuilder { + + private EnrollmentType enrollmentType; + private EnrollmentPolicy enrollmentPolicy; + + public static EnrollmentBuilder aFreeEnrollmentBuilder() { + return new EnrollmentBuilder() + .withEnrollmentType(EnrollmentType.FREE) + .withEnrollmentPolicy(aFreeEnrollmentPolicyBuilder().build()); + } + + public static EnrollmentBuilder aPaidEnrollmentBuilder() { + return new EnrollmentBuilder() + .withEnrollmentType(EnrollmentType.PAID) + .withEnrollmentPolicy(aPaidEnrollmentPolicyBuilder().build()); + } + + private EnrollmentBuilder() {} + + private EnrollmentBuilder(EnrollmentBuilder copy) { + this.enrollmentType = copy.enrollmentType; + this.enrollmentPolicy = copy.enrollmentPolicy; + } + + public EnrollmentBuilder withEnrollmentType(EnrollmentType enrollmentType) { + this.enrollmentType = enrollmentType; + return this; + } + + public EnrollmentBuilder withEnrollmentPolicy(EnrollmentPolicy enrollmentPolicy) { + this.enrollmentPolicy = enrollmentPolicy; + return this; + } + + public Enrollment build() throws CanNotCreateException { + return new Enrollment(enrollmentType, enrollmentPolicy); + } + + public EnrollmentBuilder but() { + return new EnrollmentBuilder(this); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/builder/EnrollmentPolicyBuilder.java b/src/main/java/nextstep/courses/domain/builder/EnrollmentPolicyBuilder.java new file mode 100644 index 000000000..62e84ed11 --- /dev/null +++ b/src/main/java/nextstep/courses/domain/builder/EnrollmentPolicyBuilder.java @@ -0,0 +1,63 @@ +package nextstep.courses.domain.builder; + +import java.util.List; +import nextstep.courses.domain.EnrolledUsers; +import nextstep.courses.domain.EnrollmentPolicy; +import nextstep.courses.domain.SessionStatus; +import nextstep.courses.domain.enrollmentcondition.EnrollmentCondition; +import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; +import nextstep.courses.domain.enumerate.SessionStatusType; + +public class EnrollmentPolicyBuilder { + + private EnrollmentCondition enrollmentCondition; + private EnrolledUsers enrolledUsers = new EnrolledUsers(List.of(1L, 2L, 3L, 4L, 5L)); + private SessionStatus status = new SessionStatus(SessionStatusType.RECRUITING); + + public static EnrollmentPolicyBuilder aFreeEnrollmentPolicyBuilder() { + return new EnrollmentPolicyBuilder() + .withEnrollmentCondition(FreeEnrollmentCondition.INSTANCE); + } + + public static EnrollmentPolicyBuilder aPaidEnrollmentPolicyBuilder() { + return new EnrollmentPolicyBuilder() + .withEnrollmentCondition(new PaidEnrollmentCondition(10L, 10)); + } + + private EnrollmentPolicyBuilder() {} + + private EnrollmentPolicyBuilder(EnrollmentCondition enrollmentCondition) { + this.enrollmentCondition = enrollmentCondition; + } + + private EnrollmentPolicyBuilder(EnrollmentPolicyBuilder copy) { + this.enrollmentCondition = copy.enrollmentCondition; + this.enrolledUsers = copy.enrolledUsers; + this.status = copy.status; + } + + public EnrollmentPolicyBuilder withEnrollmentCondition(EnrollmentCondition enrollmentCondition) { + this.enrollmentCondition = enrollmentCondition; + return this; + } + + public EnrollmentPolicyBuilder withEnrolledUsers(EnrolledUsers enrolledUsers) { + this.enrolledUsers = enrolledUsers; + return this; + } + + public EnrollmentPolicyBuilder withSessionStatus(SessionStatus sessionStatus) { + this.status = sessionStatus; + return this; + } + + public EnrollmentPolicy build() { + return new EnrollmentPolicy(enrollmentCondition, enrolledUsers, status); + } + + public EnrollmentPolicyBuilder but() { + return new EnrollmentPolicyBuilder(this); + } + +} diff --git a/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentBuilder.java b/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentBuilder.java deleted file mode 100644 index 0491adb70..000000000 --- a/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentBuilder.java +++ /dev/null @@ -1,43 +0,0 @@ -package nextstep.courses.domain.builder; - -import static nextstep.courses.domain.builder.FreeEnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; - -import nextstep.courses.CanNotCreateException; -import nextstep.courses.domain.Enrollment; -import nextstep.courses.domain.EnrollmentPolicy; -import nextstep.courses.domain.enumerate.EnrollmentType; - -public class FreeEnrollmentBuilder { - - private EnrollmentType enrollmentType = EnrollmentType.FREE; - private EnrollmentPolicy enrollmentPolicy = aFreeEnrollmentPolicyBuilder().build(); - - public static FreeEnrollmentBuilder aFreeEnrollmentBuilder() { - return new FreeEnrollmentBuilder(); - } - - private FreeEnrollmentBuilder() {} - - private FreeEnrollmentBuilder(FreeEnrollmentBuilder copy) { - this.enrollmentType = copy.enrollmentType; - this.enrollmentPolicy = copy.enrollmentPolicy; - } - - public FreeEnrollmentBuilder withEnrollmentType(EnrollmentType enrollmentType) { - this.enrollmentType = enrollmentType; - return this; - } - - public FreeEnrollmentBuilder withEnrollmentPolicy(EnrollmentPolicy enrollmentPolicy) { - this.enrollmentPolicy = enrollmentPolicy; - return this; - } - - public Enrollment build() throws CanNotCreateException { - return new Enrollment(enrollmentType, enrollmentPolicy); - } - - public FreeEnrollmentBuilder but() { - return new FreeEnrollmentBuilder(this); - } -} \ No newline at end of file diff --git a/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentPolicyBuilder.java b/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentPolicyBuilder.java deleted file mode 100644 index ce228a6b5..000000000 --- a/src/main/java/nextstep/courses/domain/builder/FreeEnrollmentPolicyBuilder.java +++ /dev/null @@ -1,52 +0,0 @@ -package nextstep.courses.domain.builder; - -import java.util.List; -import nextstep.courses.domain.EnrolledUsers; -import nextstep.courses.domain.EnrollmentPolicy; -import nextstep.courses.domain.SessionStatus; -import nextstep.courses.domain.enrollmentcondition.EnrollmentCondition; -import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; -import nextstep.courses.domain.enumerate.SessionStatusType; - -public class FreeEnrollmentPolicyBuilder { - - private EnrollmentCondition enrollmentCondition = FreeEnrollmentCondition.INSTANCE; - private EnrolledUsers enrolledUsers = new EnrolledUsers(List.of(1L, 2L, 3L, 4L, 5L)); - private SessionStatus status = new SessionStatus(SessionStatusType.RECRUITING); - - public static FreeEnrollmentPolicyBuilder aFreeEnrollmentPolicyBuilder() { - return new FreeEnrollmentPolicyBuilder(); - } - - private FreeEnrollmentPolicyBuilder() {} - - private FreeEnrollmentPolicyBuilder(FreeEnrollmentPolicyBuilder copy) { - this.enrollmentCondition = copy.enrollmentCondition; - this.enrolledUsers = copy.enrolledUsers; - this.status = copy.status; - } - - public FreeEnrollmentPolicyBuilder withEnrollmentCondition(EnrollmentCondition enrollmentCondition) { - this.enrollmentCondition = enrollmentCondition; - return this; - } - - public FreeEnrollmentPolicyBuilder withEnrolledUsers(EnrolledUsers enrolledUsers) { - this.enrolledUsers = enrolledUsers; - return this; - } - - public FreeEnrollmentPolicyBuilder withSessionStatus(SessionStatus sessionStatus) { - this.status = sessionStatus; - return this; - } - - public EnrollmentPolicy build() { - return new EnrollmentPolicy(enrollmentCondition, enrolledUsers, status); - } - - public FreeEnrollmentPolicyBuilder but() { - return new FreeEnrollmentPolicyBuilder(this); - } - -} diff --git a/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentBuilder.java b/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentBuilder.java deleted file mode 100644 index 89006bd82..000000000 --- a/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentBuilder.java +++ /dev/null @@ -1,45 +0,0 @@ -package nextstep.courses.domain.builder; - -import static nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; - -import nextstep.courses.CanNotCreateException; -import nextstep.courses.domain.Enrollment; -import nextstep.courses.domain.EnrollmentPolicy; -import nextstep.courses.domain.enumerate.EnrollmentType; - -public class PaidEnrollmentBuilder { - - private EnrollmentType enrollmentType = EnrollmentType.PAID; - private EnrollmentPolicy enrollmentPolicy = aPaidEnrollmentPolicyBuilder().build(); - - public static PaidEnrollmentBuilder aPaidEnrollmentBuilder() { - return new PaidEnrollmentBuilder(); - } - - private PaidEnrollmentBuilder() {} - - private PaidEnrollmentBuilder(PaidEnrollmentBuilder copy) { - this.enrollmentType = copy.enrollmentType; - this.enrollmentPolicy = copy.enrollmentPolicy; - } - - public PaidEnrollmentBuilder withEnrollmentType(EnrollmentType enrollmentType) { - this.enrollmentType = enrollmentType; - return this; - } - - public PaidEnrollmentBuilder withEnrollmentPolicy(EnrollmentPolicy enrollmentPolicy) { - this.enrollmentPolicy = enrollmentPolicy; - return this; - } - - public Enrollment build() throws CanNotCreateException { - return new Enrollment(enrollmentType, enrollmentPolicy); - } - - public PaidEnrollmentBuilder but() { - return new PaidEnrollmentBuilder(this); - } - - -} diff --git a/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentPolicyBuilder.java b/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentPolicyBuilder.java deleted file mode 100644 index 10d3305c5..000000000 --- a/src/main/java/nextstep/courses/domain/builder/PaidEnrollmentPolicyBuilder.java +++ /dev/null @@ -1,52 +0,0 @@ -package nextstep.courses.domain.builder; - -import java.util.List; -import nextstep.courses.domain.EnrolledUsers; -import nextstep.courses.domain.EnrollmentPolicy; -import nextstep.courses.domain.SessionStatus; -import nextstep.courses.domain.enrollmentcondition.EnrollmentCondition; -import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; -import nextstep.courses.domain.enumerate.SessionStatusType; - -public class PaidEnrollmentPolicyBuilder { - - private EnrollmentCondition enrollmentCondition = new PaidEnrollmentCondition(10L, 10); - private EnrolledUsers enrolledUsers = new EnrolledUsers(List.of(1L, 2L, 3L, 4L, 5L)); - private SessionStatus status = new SessionStatus(SessionStatusType.RECRUITING); - - public static PaidEnrollmentPolicyBuilder aPaidEnrollmentPolicyBuilder() { - return new PaidEnrollmentPolicyBuilder(); - } - - private PaidEnrollmentPolicyBuilder() {} - - private PaidEnrollmentPolicyBuilder(PaidEnrollmentPolicyBuilder copy) { - this.enrollmentCondition = copy.enrollmentCondition; - this.enrolledUsers = copy.enrolledUsers; - this.status = copy.status; - } - - public PaidEnrollmentPolicyBuilder withEnrollmentCondition(EnrollmentCondition enrollmentCondition) { - this.enrollmentCondition = enrollmentCondition; - return this; - } - - public PaidEnrollmentPolicyBuilder withEnrolledUsers(EnrolledUsers enrolledUsers) { - this.enrolledUsers = enrolledUsers; - return this; - } - - public PaidEnrollmentPolicyBuilder withSessionStatus(SessionStatus sessionStatus) { - this.status = sessionStatus; - return this; - } - - public EnrollmentPolicy build() { - return new EnrollmentPolicy(enrollmentCondition, enrolledUsers, status); - } - - public PaidEnrollmentPolicyBuilder but() { - return new PaidEnrollmentPolicyBuilder(this); - } - -} diff --git a/src/main/java/nextstep/courses/domain/builder/PaidSessionBuilder.java b/src/main/java/nextstep/courses/domain/builder/PaidSessionBuilder.java deleted file mode 100644 index 6e731bc6a..000000000 --- a/src/main/java/nextstep/courses/domain/builder/PaidSessionBuilder.java +++ /dev/null @@ -1,70 +0,0 @@ -package nextstep.courses.domain.builder; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import nextstep.courses.CanNotCreateException; -import nextstep.courses.domain.*; -import nextstep.courses.domain.enumerate.CoverImageType; - -public class PaidSessionBuilder { - - private Long id = 2L; - private String creatorId = "1"; - private SessionBody body = new SessionBody("title", "content"); - private Duration duration = new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)); - private CoverImage coverImage = new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200); - private Enrollment enrollment = PaidEnrollmentBuilder.aPaidEnrollmentBuilder().build(); - - public static PaidSessionBuilder aPaidSessionBuilder() throws CanNotCreateException { - return new PaidSessionBuilder(); - } - - public PaidSessionBuilder(PaidSessionBuilder copy) throws CanNotCreateException { - this.id = copy.id; - this.creatorId = copy.creatorId; - this.body = copy.body; - this.duration = copy.duration; - this.coverImage = copy.coverImage; - this.enrollment = copy.enrollment; - } - - private PaidSessionBuilder() throws CanNotCreateException {} - - public PaidSessionBuilder withId(Long id) { - this.id = id; - return this; - } - - public PaidSessionBuilder withCreatorId(String creatorId) { - this.creatorId = creatorId; - return this; - } - - public PaidSessionBuilder withBody(SessionBody body) { - this.body = body; - return this; - } - - public PaidSessionBuilder withDuration(Duration duration) { - this.duration = duration; - return this; - } - - public PaidSessionBuilder withCoverImage(CoverImage coverImage) { - this.coverImage = coverImage; - return this; - } - - public PaidSessionBuilder withEnrollment(Enrollment enrollment) { - this.enrollment = enrollment; - return this; - } - - public Session build() { - return new Session(id, creatorId, body, duration, coverImage, enrollment, LocalDateTime.now(), null); - } - - public PaidSessionBuilder but() throws CanNotCreateException { - return new PaidSessionBuilder(this); - } -} diff --git a/src/main/java/nextstep/courses/domain/builder/FreeSessionBuilder.java b/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java similarity index 53% rename from src/main/java/nextstep/courses/domain/builder/FreeSessionBuilder.java rename to src/main/java/nextstep/courses/domain/builder/SessionBuilder.java index 7dee4fc0c..fb333fc44 100644 --- a/src/main/java/nextstep/courses/domain/builder/FreeSessionBuilder.java +++ b/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java @@ -1,25 +1,34 @@ package nextstep.courses.domain.builder; +import static nextstep.courses.domain.builder.EnrollmentBuilder.aFreeEnrollmentBuilder; +import static nextstep.courses.domain.builder.EnrollmentBuilder.aPaidEnrollmentBuilder; + import java.time.LocalDate; import java.time.LocalDateTime; import nextstep.courses.CanNotCreateException; import nextstep.courses.domain.*; import nextstep.courses.domain.enumerate.CoverImageType; -public class FreeSessionBuilder { +public class SessionBuilder { private Long id = 1L; private String creatorId = "1"; private SessionBody body = new SessionBody("title", "content"); private Duration duration = new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)); private CoverImage coverImage = new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200); - private Enrollment enrollment = FreeEnrollmentBuilder.aFreeEnrollmentBuilder().build(); + private Enrollment enrollment = aPaidEnrollmentBuilder().build(); + + public static SessionBuilder aPaidSessionBuilder() throws CanNotCreateException { + return new SessionBuilder() + .withEnrollment(aPaidEnrollmentBuilder().build()); + } - public static FreeSessionBuilder aFreeSessionBuilder() throws CanNotCreateException { - return new FreeSessionBuilder(); + public static SessionBuilder aFreeSessionBuilder() throws CanNotCreateException { + return new SessionBuilder() + .withEnrollment(aFreeEnrollmentBuilder().build()); } - public FreeSessionBuilder(FreeSessionBuilder copy) throws CanNotCreateException { + public SessionBuilder(SessionBuilder copy) throws CanNotCreateException { this.id = copy.id; this.creatorId = copy.creatorId; this.body = copy.body; @@ -28,34 +37,34 @@ public FreeSessionBuilder(FreeSessionBuilder copy) throws CanNotCreateException this.enrollment = copy.enrollment; } - private FreeSessionBuilder() throws CanNotCreateException {} + private SessionBuilder() throws CanNotCreateException {} - public FreeSessionBuilder withId(Long id) { + public SessionBuilder withId(Long id) { this.id = id; return this; } - public FreeSessionBuilder withCreatorId(String creatorId) { + public SessionBuilder withCreatorId(String creatorId) { this.creatorId = creatorId; return this; } - public FreeSessionBuilder withBody(SessionBody body) { + public SessionBuilder withBody(SessionBody body) { this.body = body; return this; } - public FreeSessionBuilder withDuration(Duration duration) { + public SessionBuilder withDuration(Duration duration) { this.duration = duration; return this; } - public FreeSessionBuilder withCoverImage(CoverImage coverImage) { + public SessionBuilder withCoverImage(CoverImage coverImage) { this.coverImage = coverImage; return this; } - public FreeSessionBuilder withEnrollment(Enrollment enrollment) { + public SessionBuilder withEnrollment(Enrollment enrollment) { this.enrollment = enrollment; return this; } @@ -64,7 +73,7 @@ public Session build() { return new Session(id, creatorId, body, duration, coverImage, enrollment, LocalDateTime.now(), null); } - public FreeSessionBuilder but() throws CanNotCreateException { - return new FreeSessionBuilder(this); + public SessionBuilder but() throws CanNotCreateException { + return new SessionBuilder(this); } } diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java index 45a4618ea..7e7a858b3 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/CourseTest.java @@ -1,11 +1,11 @@ package nextstep.courses.domain; -import static nextstep.courses.domain.builder.FreeEnrollmentBuilder.aFreeEnrollmentBuilder; -import static nextstep.courses.domain.builder.FreeEnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; -import static nextstep.courses.domain.builder.FreeSessionBuilder.aFreeSessionBuilder; -import static nextstep.courses.domain.builder.PaidEnrollmentBuilder.aPaidEnrollmentBuilder; -import static nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; -import static nextstep.courses.domain.builder.PaidSessionBuilder.aPaidSessionBuilder; +import static nextstep.courses.domain.builder.EnrollmentBuilder.aFreeEnrollmentBuilder; +import static nextstep.courses.domain.builder.EnrollmentBuilder.aPaidEnrollmentBuilder; +import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.SessionBuilder.aFreeSessionBuilder; +import static nextstep.courses.domain.builder.SessionBuilder.aPaidSessionBuilder; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -52,6 +52,7 @@ class CourseTest { ) .build(); Session paidSession = aPaidSessionBuilder() + .withId(2L) .withEnrollment( aPaidEnrollmentBuilder() .withEnrollmentPolicy( @@ -82,6 +83,7 @@ class CourseTest { ) .build(); Session paidSession = aPaidSessionBuilder() + .withId(2L) .withEnrollment( aPaidEnrollmentBuilder() .withEnrollmentPolicy( diff --git a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java index b4e97cf6b..441cb2726 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java @@ -1,7 +1,7 @@ package nextstep.courses.domain; -import static nextstep.courses.domain.builder.FreeEnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; -import static nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/src/test/java/nextstep/courses/domain/EnrollmentTest.java b/src/test/java/nextstep/courses/domain/EnrollmentTest.java index 281628f54..484f97c7e 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentTest.java +++ b/src/test/java/nextstep/courses/domain/EnrollmentTest.java @@ -1,12 +1,12 @@ package nextstep.courses.domain; +import static nextstep.courses.domain.builder.EnrollmentBuilder.aFreeEnrollmentBuilder; +import static nextstep.courses.domain.builder.EnrollmentBuilder.aPaidEnrollmentBuilder; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotCreateException; -import nextstep.courses.domain.builder.FreeEnrollmentBuilder; -import nextstep.courses.domain.builder.PaidEnrollmentBuilder; -import nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder; +import nextstep.courses.domain.builder.EnrollmentPolicyBuilder; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; @@ -15,9 +15,9 @@ class EnrollmentTest { @Test void 무료강의인데_수강료가있으면_에러전파() { assertThatThrownBy(() -> { - FreeEnrollmentBuilder.aFreeEnrollmentBuilder() + aFreeEnrollmentBuilder() .withEnrollmentPolicy( - PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder().build() + EnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder().build() ) .build(); }).isInstanceOf(CanNotCreateException.class) @@ -26,7 +26,7 @@ class EnrollmentTest { @Test void 유료강의에_수강신청한다() throws Exception { - Enrollment enrollment = PaidEnrollmentBuilder.aPaidEnrollmentBuilder().build(); + Enrollment enrollment = aPaidEnrollmentBuilder().build(); assertThatNoException().isThrownBy(() -> { enrollment.enroll(10L, new Payment()); }); @@ -34,7 +34,7 @@ class EnrollmentTest { @Test void 무료강의에_지불_없이_수강신청한다() throws Exception { - Enrollment enrollment = FreeEnrollmentBuilder.aFreeEnrollmentBuilder().build(); + Enrollment enrollment = aFreeEnrollmentBuilder().build(); assertThatNoException().isThrownBy(() -> enrollment.enroll(10L)); } diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java index 19f2c0a95..2e2d134e5 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/SessionTest.java @@ -1,11 +1,11 @@ package nextstep.courses.domain; -import static nextstep.courses.domain.builder.FreeEnrollmentBuilder.aFreeEnrollmentBuilder; -import static nextstep.courses.domain.builder.FreeEnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; -import static nextstep.courses.domain.builder.FreeSessionBuilder.aFreeSessionBuilder; -import static nextstep.courses.domain.builder.PaidEnrollmentBuilder.aPaidEnrollmentBuilder; -import static nextstep.courses.domain.builder.PaidEnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; -import static nextstep.courses.domain.builder.PaidSessionBuilder.aPaidSessionBuilder; +import static nextstep.courses.domain.builder.EnrollmentBuilder.aFreeEnrollmentBuilder; +import static nextstep.courses.domain.builder.EnrollmentBuilder.aPaidEnrollmentBuilder; +import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; +import static nextstep.courses.domain.builder.SessionBuilder.aFreeSessionBuilder; +import static nextstep.courses.domain.builder.SessionBuilder.aPaidSessionBuilder; import static org.assertj.core.api.Assertions.assertThatNoException; import java.util.List; From 4dd0d8760f32db2762d83f62727d93c0a1a95545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Fri, 12 Dec 2025 22:48:17 +0900 Subject: [PATCH 33/34] =?UTF-8?q?refactor=20:=20=EB=86=93=EC=B9=9C=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EA=B8=B0=EB=B3=B8=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/nextstep/courses/domain/builder/SessionBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java b/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java index fb333fc44..79e6b34a8 100644 --- a/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java +++ b/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java @@ -16,7 +16,7 @@ public class SessionBuilder { private SessionBody body = new SessionBody("title", "content"); private Duration duration = new Duration(LocalDate.now().plusDays(1), LocalDate.now().plusDays(3)); private CoverImage coverImage = new CoverImage(1_500_000, CoverImageType.JPEG, 300, 200); - private Enrollment enrollment = aPaidEnrollmentBuilder().build(); + private Enrollment enrollment; public static SessionBuilder aPaidSessionBuilder() throws CanNotCreateException { return new SessionBuilder() From f3fe388520cbb0a1966dfb2afdb742fe7e54e437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=86=E1=85=A9=E1=84=8C=E1=85=A2=E1=84=8B=E1=85=A7?= =?UTF-8?q?=E1=86=BC?= Date: Fri, 12 Dec 2025 22:55:54 +0900 Subject: [PATCH 34/34] =?UTF-8?q?chore=20:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=EB=9F=AD=EC=B3=90=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../courses/domain/builder/EnrollmentBuilder.java | 4 ++-- .../domain/builder/EnrollmentPolicyBuilder.java | 12 ++++++------ .../courses/domain/builder/SessionBuilder.java | 6 +++++- .../nextstep/courses/domain/{ => common}/Base.java | 2 +- .../nextstep/courses/domain/{ => course}/Course.java | 5 ++++- .../domain/{ => course}/CourseRepository.java | 2 +- .../courses/domain/{ => course}/SessionApply.java | 2 +- .../domain/{ => enrollment}/EnrolledUsers.java | 2 +- .../courses/domain/{ => enrollment}/Enrollment.java | 5 +++-- .../domain/{ => enrollment}/EnrollmentPolicy.java | 5 +++-- .../domain/{ => enrollment}/SessionStatus.java | 2 +- .../enrollmentcondition/EnrollmentCondition.java | 4 ++-- .../enrollmentcondition/FreeEnrollmentCondition.java | 4 ++-- .../enrollmentcondition/PaidEnrollmentCondition.java | 4 ++-- .../courses/domain/{ => session}/CoverImage.java | 2 +- .../courses/domain/{ => session}/Dimensions.java | 2 +- .../courses/domain/{ => session}/Duration.java | 2 +- .../courses/domain/{ => session}/Session.java | 5 ++++- .../courses/domain/{ => session}/SessionBody.java | 2 +- .../courses/domain/{ => session}/Sessions.java | 2 +- .../courses/infrastructure/JdbcCourseRepository.java | 9 ++++----- .../java/nextstep/courses/service/CourseService.java | 6 +++--- .../courses/domain/{ => course}/CourseTest.java | 4 +++- .../domain/{ => enrollment}/EnrolledUsersTest.java | 2 +- .../{ => enrollment}/EnrollmentPolicyTest.java | 3 ++- .../domain/{ => enrollment}/EnrollmentTest.java | 2 +- .../domain/{ => enrollment}/SessionStatusTest.java | 2 +- .../FreeEnrollmentConditionTest.java | 4 ++-- .../PaidEnrollmentConditionTest.java | 4 ++-- .../courses/domain/{ => session}/CoverImageTest.java | 2 +- .../courses/domain/{ => session}/DimensionsTest.java | 2 +- .../courses/domain/{ => session}/DurationTest.java | 2 +- .../domain/{ => session}/SessionBodyTest.java | 2 +- .../courses/domain/{ => session}/SessionTest.java | 3 ++- .../courses/domain/{ => session}/SessionsTest.java | 10 +++++++--- .../courses/infrastructure/CourseRepositoryTest.java | 8 ++++---- 36 files changed, 79 insertions(+), 60 deletions(-) rename src/main/java/nextstep/courses/domain/{ => common}/Base.java (93%) rename src/main/java/nextstep/courses/domain/{ => course}/Course.java (91%) rename src/main/java/nextstep/courses/domain/{ => course}/CourseRepository.java (71%) rename src/main/java/nextstep/courses/domain/{ => course}/SessionApply.java (91%) rename src/main/java/nextstep/courses/domain/{ => enrollment}/EnrolledUsers.java (96%) rename src/main/java/nextstep/courses/domain/{ => enrollment}/Enrollment.java (89%) rename src/main/java/nextstep/courses/domain/{ => enrollment}/EnrollmentPolicy.java (90%) rename src/main/java/nextstep/courses/domain/{ => enrollment}/SessionStatus.java (93%) rename src/main/java/nextstep/courses/domain/{ => enrollment}/enrollmentcondition/EnrollmentCondition.java (76%) rename src/main/java/nextstep/courses/domain/{ => enrollment}/enrollmentcondition/FreeEnrollmentCondition.java (84%) rename src/main/java/nextstep/courses/domain/{ => enrollment}/enrollmentcondition/PaidEnrollmentCondition.java (92%) rename src/main/java/nextstep/courses/domain/{ => session}/CoverImage.java (96%) rename src/main/java/nextstep/courses/domain/{ => session}/Dimensions.java (96%) rename src/main/java/nextstep/courses/domain/{ => session}/Duration.java (97%) rename src/main/java/nextstep/courses/domain/{ => session}/Session.java (89%) rename src/main/java/nextstep/courses/domain/{ => session}/SessionBody.java (94%) rename src/main/java/nextstep/courses/domain/{ => session}/Sessions.java (95%) rename src/test/java/nextstep/courses/domain/{ => course}/CourseTest.java (96%) rename src/test/java/nextstep/courses/domain/{ => enrollment}/EnrolledUsersTest.java (95%) rename src/test/java/nextstep/courses/domain/{ => enrollment}/EnrollmentPolicyTest.java (93%) rename src/test/java/nextstep/courses/domain/{ => enrollment}/EnrollmentTest.java (97%) rename src/test/java/nextstep/courses/domain/{ => enrollment}/SessionStatusTest.java (93%) rename src/test/java/nextstep/courses/domain/{ => enrollment}/enrollmentcondition/FreeEnrollmentConditionTest.java (82%) rename src/test/java/nextstep/courses/domain/{ => enrollment}/enrollmentcondition/PaidEnrollmentConditionTest.java (93%) rename src/test/java/nextstep/courses/domain/{ => session}/CoverImageTest.java (93%) rename src/test/java/nextstep/courses/domain/{ => session}/DimensionsTest.java (96%) rename src/test/java/nextstep/courses/domain/{ => session}/DurationTest.java (96%) rename src/test/java/nextstep/courses/domain/{ => session}/SessionBodyTest.java (94%) rename src/test/java/nextstep/courses/domain/{ => session}/SessionTest.java (96%) rename src/test/java/nextstep/courses/domain/{ => session}/SessionsTest.java (84%) diff --git a/src/main/java/nextstep/courses/domain/builder/EnrollmentBuilder.java b/src/main/java/nextstep/courses/domain/builder/EnrollmentBuilder.java index f8459af6c..afeb64ac7 100644 --- a/src/main/java/nextstep/courses/domain/builder/EnrollmentBuilder.java +++ b/src/main/java/nextstep/courses/domain/builder/EnrollmentBuilder.java @@ -4,8 +4,8 @@ import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; import nextstep.courses.CanNotCreateException; -import nextstep.courses.domain.Enrollment; -import nextstep.courses.domain.EnrollmentPolicy; +import nextstep.courses.domain.enrollment.Enrollment; +import nextstep.courses.domain.enrollment.EnrollmentPolicy; import nextstep.courses.domain.enumerate.EnrollmentType; public class EnrollmentBuilder { diff --git a/src/main/java/nextstep/courses/domain/builder/EnrollmentPolicyBuilder.java b/src/main/java/nextstep/courses/domain/builder/EnrollmentPolicyBuilder.java index 62e84ed11..816525bfb 100644 --- a/src/main/java/nextstep/courses/domain/builder/EnrollmentPolicyBuilder.java +++ b/src/main/java/nextstep/courses/domain/builder/EnrollmentPolicyBuilder.java @@ -1,12 +1,12 @@ package nextstep.courses.domain.builder; import java.util.List; -import nextstep.courses.domain.EnrolledUsers; -import nextstep.courses.domain.EnrollmentPolicy; -import nextstep.courses.domain.SessionStatus; -import nextstep.courses.domain.enrollmentcondition.EnrollmentCondition; -import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; -import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; +import nextstep.courses.domain.enrollment.EnrolledUsers; +import nextstep.courses.domain.enrollment.EnrollmentPolicy; +import nextstep.courses.domain.enrollment.SessionStatus; +import nextstep.courses.domain.enrollment.enrollmentcondition.EnrollmentCondition; +import nextstep.courses.domain.enrollment.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.enrollment.enrollmentcondition.PaidEnrollmentCondition; import nextstep.courses.domain.enumerate.SessionStatusType; public class EnrollmentPolicyBuilder { diff --git a/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java b/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java index 79e6b34a8..a1f261a52 100644 --- a/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java +++ b/src/main/java/nextstep/courses/domain/builder/SessionBuilder.java @@ -6,8 +6,12 @@ import java.time.LocalDate; import java.time.LocalDateTime; import nextstep.courses.CanNotCreateException; -import nextstep.courses.domain.*; +import nextstep.courses.domain.enrollment.Enrollment; import nextstep.courses.domain.enumerate.CoverImageType; +import nextstep.courses.domain.session.CoverImage; +import nextstep.courses.domain.session.Duration; +import nextstep.courses.domain.session.Session; +import nextstep.courses.domain.session.SessionBody; public class SessionBuilder { diff --git a/src/main/java/nextstep/courses/domain/Base.java b/src/main/java/nextstep/courses/domain/common/Base.java similarity index 93% rename from src/main/java/nextstep/courses/domain/Base.java rename to src/main/java/nextstep/courses/domain/common/Base.java index f29567037..1dc12de80 100644 --- a/src/main/java/nextstep/courses/domain/Base.java +++ b/src/main/java/nextstep/courses/domain/common/Base.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.common; import java.time.LocalDateTime; diff --git a/src/main/java/nextstep/courses/domain/Course.java b/src/main/java/nextstep/courses/domain/course/Course.java similarity index 91% rename from src/main/java/nextstep/courses/domain/Course.java rename to src/main/java/nextstep/courses/domain/course/Course.java index ed0efeed4..8d7b94d15 100644 --- a/src/main/java/nextstep/courses/domain/Course.java +++ b/src/main/java/nextstep/courses/domain/course/Course.java @@ -1,8 +1,11 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.course; import java.time.LocalDateTime; import java.util.List; import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.common.Base; +import nextstep.courses.domain.session.Session; +import nextstep.courses.domain.session.Sessions; import nextstep.payments.domain.Payment; public class Course extends Base { diff --git a/src/main/java/nextstep/courses/domain/CourseRepository.java b/src/main/java/nextstep/courses/domain/course/CourseRepository.java similarity index 71% rename from src/main/java/nextstep/courses/domain/CourseRepository.java rename to src/main/java/nextstep/courses/domain/course/CourseRepository.java index 6aaeb638d..28180d25e 100644 --- a/src/main/java/nextstep/courses/domain/CourseRepository.java +++ b/src/main/java/nextstep/courses/domain/course/CourseRepository.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.course; public interface CourseRepository { int save(Course course); diff --git a/src/main/java/nextstep/courses/domain/SessionApply.java b/src/main/java/nextstep/courses/domain/course/SessionApply.java similarity index 91% rename from src/main/java/nextstep/courses/domain/SessionApply.java rename to src/main/java/nextstep/courses/domain/course/SessionApply.java index bd370538d..117431891 100644 --- a/src/main/java/nextstep/courses/domain/SessionApply.java +++ b/src/main/java/nextstep/courses/domain/course/SessionApply.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.course; import nextstep.payments.domain.Payment; diff --git a/src/main/java/nextstep/courses/domain/EnrolledUsers.java b/src/main/java/nextstep/courses/domain/enrollment/EnrolledUsers.java similarity index 96% rename from src/main/java/nextstep/courses/domain/EnrolledUsers.java rename to src/main/java/nextstep/courses/domain/enrollment/EnrolledUsers.java index 55a64a2a4..cffe57b70 100644 --- a/src/main/java/nextstep/courses/domain/EnrolledUsers.java +++ b/src/main/java/nextstep/courses/domain/enrollment/EnrolledUsers.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.enrollment; import java.util.ArrayList; import java.util.Collections; diff --git a/src/main/java/nextstep/courses/domain/Enrollment.java b/src/main/java/nextstep/courses/domain/enrollment/Enrollment.java similarity index 89% rename from src/main/java/nextstep/courses/domain/Enrollment.java rename to src/main/java/nextstep/courses/domain/enrollment/Enrollment.java index 51ff088fb..fb00a9299 100644 --- a/src/main/java/nextstep/courses/domain/Enrollment.java +++ b/src/main/java/nextstep/courses/domain/enrollment/Enrollment.java @@ -1,8 +1,9 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.enrollment; import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; -import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.course.SessionApply; +import nextstep.courses.domain.enrollment.enrollmentcondition.FreeEnrollmentCondition; import nextstep.courses.domain.enumerate.EnrollmentType; import nextstep.payments.domain.Payment; diff --git a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java b/src/main/java/nextstep/courses/domain/enrollment/EnrollmentPolicy.java similarity index 90% rename from src/main/java/nextstep/courses/domain/EnrollmentPolicy.java rename to src/main/java/nextstep/courses/domain/enrollment/EnrollmentPolicy.java index 5e891f88d..26839fb59 100644 --- a/src/main/java/nextstep/courses/domain/EnrollmentPolicy.java +++ b/src/main/java/nextstep/courses/domain/enrollment/EnrollmentPolicy.java @@ -1,7 +1,8 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.enrollment; import nextstep.courses.CanNotJoinException; -import nextstep.courses.domain.enrollmentcondition.EnrollmentCondition; +import nextstep.courses.domain.course.SessionApply; +import nextstep.courses.domain.enrollment.enrollmentcondition.EnrollmentCondition; import nextstep.courses.domain.enumerate.EnrollmentType; public class EnrollmentPolicy { diff --git a/src/main/java/nextstep/courses/domain/SessionStatus.java b/src/main/java/nextstep/courses/domain/enrollment/SessionStatus.java similarity index 93% rename from src/main/java/nextstep/courses/domain/SessionStatus.java rename to src/main/java/nextstep/courses/domain/enrollment/SessionStatus.java index 1cec50f4a..5ed67d625 100644 --- a/src/main/java/nextstep/courses/domain/SessionStatus.java +++ b/src/main/java/nextstep/courses/domain/enrollment/SessionStatus.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.enrollment; import nextstep.courses.CanNotJoinException; import nextstep.courses.domain.enumerate.SessionStatusType; diff --git a/src/main/java/nextstep/courses/domain/enrollmentcondition/EnrollmentCondition.java b/src/main/java/nextstep/courses/domain/enrollment/enrollmentcondition/EnrollmentCondition.java similarity index 76% rename from src/main/java/nextstep/courses/domain/enrollmentcondition/EnrollmentCondition.java rename to src/main/java/nextstep/courses/domain/enrollment/enrollmentcondition/EnrollmentCondition.java index c00b4356a..84a0f6142 100644 --- a/src/main/java/nextstep/courses/domain/enrollmentcondition/EnrollmentCondition.java +++ b/src/main/java/nextstep/courses/domain/enrollment/enrollmentcondition/EnrollmentCondition.java @@ -1,8 +1,8 @@ -package nextstep.courses.domain.enrollmentcondition; +package nextstep.courses.domain.enrollment.enrollmentcondition; import java.util.Optional; import nextstep.courses.CanNotJoinException; -import nextstep.courses.domain.EnrolledUsers; +import nextstep.courses.domain.enrollment.EnrolledUsers; import nextstep.payments.domain.Payment; public interface EnrollmentCondition { diff --git a/src/main/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentCondition.java b/src/main/java/nextstep/courses/domain/enrollment/enrollmentcondition/FreeEnrollmentCondition.java similarity index 84% rename from src/main/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentCondition.java rename to src/main/java/nextstep/courses/domain/enrollment/enrollmentcondition/FreeEnrollmentCondition.java index 864311640..4c1141dcb 100644 --- a/src/main/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentCondition.java +++ b/src/main/java/nextstep/courses/domain/enrollment/enrollmentcondition/FreeEnrollmentCondition.java @@ -1,7 +1,7 @@ -package nextstep.courses.domain.enrollmentcondition; +package nextstep.courses.domain.enrollment.enrollmentcondition; import java.util.Optional; -import nextstep.courses.domain.EnrolledUsers; +import nextstep.courses.domain.enrollment.EnrolledUsers; import nextstep.payments.domain.Payment; public class FreeEnrollmentCondition implements EnrollmentCondition { diff --git a/src/main/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentCondition.java b/src/main/java/nextstep/courses/domain/enrollment/enrollmentcondition/PaidEnrollmentCondition.java similarity index 92% rename from src/main/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentCondition.java rename to src/main/java/nextstep/courses/domain/enrollment/enrollmentcondition/PaidEnrollmentCondition.java index 374a0482b..52503538f 100644 --- a/src/main/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentCondition.java +++ b/src/main/java/nextstep/courses/domain/enrollment/enrollmentcondition/PaidEnrollmentCondition.java @@ -1,8 +1,8 @@ -package nextstep.courses.domain.enrollmentcondition; +package nextstep.courses.domain.enrollment.enrollmentcondition; import java.util.Optional; import nextstep.courses.CanNotJoinException; -import nextstep.courses.domain.EnrolledUsers; +import nextstep.courses.domain.enrollment.EnrolledUsers; import nextstep.payments.domain.Payment; public class PaidEnrollmentCondition implements EnrollmentCondition { diff --git a/src/main/java/nextstep/courses/domain/CoverImage.java b/src/main/java/nextstep/courses/domain/session/CoverImage.java similarity index 96% rename from src/main/java/nextstep/courses/domain/CoverImage.java rename to src/main/java/nextstep/courses/domain/session/CoverImage.java index c41d7174c..1f3e6e08d 100644 --- a/src/main/java/nextstep/courses/domain/CoverImage.java +++ b/src/main/java/nextstep/courses/domain/session/CoverImage.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import nextstep.courses.CanNotCreateException; import nextstep.courses.domain.enumerate.CoverImageType; diff --git a/src/main/java/nextstep/courses/domain/Dimensions.java b/src/main/java/nextstep/courses/domain/session/Dimensions.java similarity index 96% rename from src/main/java/nextstep/courses/domain/Dimensions.java rename to src/main/java/nextstep/courses/domain/session/Dimensions.java index 4eff48f35..47e646f9e 100644 --- a/src/main/java/nextstep/courses/domain/Dimensions.java +++ b/src/main/java/nextstep/courses/domain/session/Dimensions.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import nextstep.courses.CanNotCreateException; diff --git a/src/main/java/nextstep/courses/domain/Duration.java b/src/main/java/nextstep/courses/domain/session/Duration.java similarity index 97% rename from src/main/java/nextstep/courses/domain/Duration.java rename to src/main/java/nextstep/courses/domain/session/Duration.java index 90990c8bb..849ee79a2 100644 --- a/src/main/java/nextstep/courses/domain/Duration.java +++ b/src/main/java/nextstep/courses/domain/session/Duration.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import java.time.LocalDate; import nextstep.courses.CanNotCreateException; diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/session/Session.java similarity index 89% rename from src/main/java/nextstep/courses/domain/Session.java rename to src/main/java/nextstep/courses/domain/session/Session.java index 0584d2bcb..c75e27c0e 100644 --- a/src/main/java/nextstep/courses/domain/Session.java +++ b/src/main/java/nextstep/courses/domain/session/Session.java @@ -1,8 +1,11 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import java.time.LocalDateTime; import java.util.Objects; import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.common.Base; +import nextstep.courses.domain.course.SessionApply; +import nextstep.courses.domain.enrollment.Enrollment; import nextstep.payments.domain.Payment; public class Session extends Base { diff --git a/src/main/java/nextstep/courses/domain/SessionBody.java b/src/main/java/nextstep/courses/domain/session/SessionBody.java similarity index 94% rename from src/main/java/nextstep/courses/domain/SessionBody.java rename to src/main/java/nextstep/courses/domain/session/SessionBody.java index 6e2f0adf6..8b76c501a 100644 --- a/src/main/java/nextstep/courses/domain/SessionBody.java +++ b/src/main/java/nextstep/courses/domain/session/SessionBody.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import nextstep.courses.CanNotCreateException; diff --git a/src/main/java/nextstep/courses/domain/Sessions.java b/src/main/java/nextstep/courses/domain/session/Sessions.java similarity index 95% rename from src/main/java/nextstep/courses/domain/Sessions.java rename to src/main/java/nextstep/courses/domain/session/Sessions.java index dcf94af96..76c52f41a 100644 --- a/src/main/java/nextstep/courses/domain/Sessions.java +++ b/src/main/java/nextstep/courses/domain/session/Sessions.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/nextstep/courses/infrastructure/JdbcCourseRepository.java b/src/main/java/nextstep/courses/infrastructure/JdbcCourseRepository.java index f9122cbe3..d4225ec92 100644 --- a/src/main/java/nextstep/courses/infrastructure/JdbcCourseRepository.java +++ b/src/main/java/nextstep/courses/infrastructure/JdbcCourseRepository.java @@ -1,14 +1,13 @@ package nextstep.courses.infrastructure; -import nextstep.courses.domain.Course; -import nextstep.courses.domain.CourseRepository; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import nextstep.courses.domain.course.Course; +import nextstep.courses.domain.course.CourseRepository; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Repository; -import java.sql.Timestamp; -import java.time.LocalDateTime; - @Repository("courseRepository") public class JdbcCourseRepository implements CourseRepository { private JdbcOperations jdbcTemplate; diff --git a/src/main/java/nextstep/courses/service/CourseService.java b/src/main/java/nextstep/courses/service/CourseService.java index 3f9774454..44776b431 100644 --- a/src/main/java/nextstep/courses/service/CourseService.java +++ b/src/main/java/nextstep/courses/service/CourseService.java @@ -2,9 +2,9 @@ import javax.annotation.Resource; import nextstep.courses.CanNotJoinException; -import nextstep.courses.domain.Course; -import nextstep.courses.domain.CourseRepository; -import nextstep.courses.domain.SessionApply; +import nextstep.courses.domain.course.Course; +import nextstep.courses.domain.course.CourseRepository; +import nextstep.courses.domain.course.SessionApply; import nextstep.payments.domain.Payment; import nextstep.payments.service.PaymentService; import nextstep.users.domain.NsUser; diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/course/CourseTest.java similarity index 96% rename from src/test/java/nextstep/courses/domain/CourseTest.java rename to src/test/java/nextstep/courses/domain/course/CourseTest.java index 7e7a858b3..b76c25aec 100644 --- a/src/test/java/nextstep/courses/domain/CourseTest.java +++ b/src/test/java/nextstep/courses/domain/course/CourseTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.course; import static nextstep.courses.domain.builder.EnrollmentBuilder.aFreeEnrollmentBuilder; import static nextstep.courses.domain.builder.EnrollmentBuilder.aPaidEnrollmentBuilder; @@ -12,6 +12,8 @@ import java.util.List; import nextstep.courses.CanNotCreateException; import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.enrollment.EnrolledUsers; +import nextstep.courses.domain.session.Session; import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; diff --git a/src/test/java/nextstep/courses/domain/EnrolledUsersTest.java b/src/test/java/nextstep/courses/domain/enrollment/EnrolledUsersTest.java similarity index 95% rename from src/test/java/nextstep/courses/domain/EnrolledUsersTest.java rename to src/test/java/nextstep/courses/domain/enrollment/EnrolledUsersTest.java index 498104cfd..3de39314f 100644 --- a/src/test/java/nextstep/courses/domain/EnrolledUsersTest.java +++ b/src/test/java/nextstep/courses/domain/enrollment/EnrolledUsersTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.enrollment; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java b/src/test/java/nextstep/courses/domain/enrollment/EnrollmentPolicyTest.java similarity index 93% rename from src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java rename to src/test/java/nextstep/courses/domain/enrollment/EnrollmentPolicyTest.java index 441cb2726..237a1efb9 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentPolicyTest.java +++ b/src/test/java/nextstep/courses/domain/enrollment/EnrollmentPolicyTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.enrollment; import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aFreeEnrollmentPolicyBuilder; import static nextstep.courses.domain.builder.EnrollmentPolicyBuilder.aPaidEnrollmentPolicyBuilder; @@ -6,6 +6,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotJoinException; +import nextstep.courses.domain.course.SessionApply; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; diff --git a/src/test/java/nextstep/courses/domain/EnrollmentTest.java b/src/test/java/nextstep/courses/domain/enrollment/EnrollmentTest.java similarity index 97% rename from src/test/java/nextstep/courses/domain/EnrollmentTest.java rename to src/test/java/nextstep/courses/domain/enrollment/EnrollmentTest.java index 484f97c7e..139317626 100644 --- a/src/test/java/nextstep/courses/domain/EnrollmentTest.java +++ b/src/test/java/nextstep/courses/domain/enrollment/EnrollmentTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.enrollment; import static nextstep.courses.domain.builder.EnrollmentBuilder.aFreeEnrollmentBuilder; import static nextstep.courses.domain.builder.EnrollmentBuilder.aPaidEnrollmentBuilder; diff --git a/src/test/java/nextstep/courses/domain/SessionStatusTest.java b/src/test/java/nextstep/courses/domain/enrollment/SessionStatusTest.java similarity index 93% rename from src/test/java/nextstep/courses/domain/SessionStatusTest.java rename to src/test/java/nextstep/courses/domain/enrollment/SessionStatusTest.java index a7e1dfdb2..4197560f0 100644 --- a/src/test/java/nextstep/courses/domain/SessionStatusTest.java +++ b/src/test/java/nextstep/courses/domain/enrollment/SessionStatusTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.enrollment; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/src/test/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentConditionTest.java b/src/test/java/nextstep/courses/domain/enrollment/enrollmentcondition/FreeEnrollmentConditionTest.java similarity index 82% rename from src/test/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentConditionTest.java rename to src/test/java/nextstep/courses/domain/enrollment/enrollmentcondition/FreeEnrollmentConditionTest.java index f71ea6a66..5044220f2 100644 --- a/src/test/java/nextstep/courses/domain/enrollmentcondition/FreeEnrollmentConditionTest.java +++ b/src/test/java/nextstep/courses/domain/enrollment/enrollmentcondition/FreeEnrollmentConditionTest.java @@ -1,8 +1,8 @@ -package nextstep.courses.domain.enrollmentcondition; +package nextstep.courses.domain.enrollment.enrollmentcondition; import static org.assertj.core.api.Assertions.assertThatNoException; -import nextstep.courses.domain.EnrolledUsers; +import nextstep.courses.domain.enrollment.EnrolledUsers; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; diff --git a/src/test/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentConditionTest.java b/src/test/java/nextstep/courses/domain/enrollment/enrollmentcondition/PaidEnrollmentConditionTest.java similarity index 93% rename from src/test/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentConditionTest.java rename to src/test/java/nextstep/courses/domain/enrollment/enrollmentcondition/PaidEnrollmentConditionTest.java index 46c41d1ec..6c592d801 100644 --- a/src/test/java/nextstep/courses/domain/enrollmentcondition/PaidEnrollmentConditionTest.java +++ b/src/test/java/nextstep/courses/domain/enrollment/enrollmentcondition/PaidEnrollmentConditionTest.java @@ -1,10 +1,10 @@ -package nextstep.courses.domain.enrollmentcondition; +package nextstep.courses.domain.enrollment.enrollmentcondition; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import nextstep.courses.CanNotJoinException; -import nextstep.courses.domain.EnrolledUsers; +import nextstep.courses.domain.enrollment.EnrolledUsers; import nextstep.payments.domain.Payment; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; diff --git a/src/test/java/nextstep/courses/domain/CoverImageTest.java b/src/test/java/nextstep/courses/domain/session/CoverImageTest.java similarity index 93% rename from src/test/java/nextstep/courses/domain/CoverImageTest.java rename to src/test/java/nextstep/courses/domain/session/CoverImageTest.java index 78efed4fe..0845b5814 100644 --- a/src/test/java/nextstep/courses/domain/CoverImageTest.java +++ b/src/test/java/nextstep/courses/domain/session/CoverImageTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/src/test/java/nextstep/courses/domain/DimensionsTest.java b/src/test/java/nextstep/courses/domain/session/DimensionsTest.java similarity index 96% rename from src/test/java/nextstep/courses/domain/DimensionsTest.java rename to src/test/java/nextstep/courses/domain/session/DimensionsTest.java index 1669ef7c8..737307f0c 100644 --- a/src/test/java/nextstep/courses/domain/DimensionsTest.java +++ b/src/test/java/nextstep/courses/domain/session/DimensionsTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/src/test/java/nextstep/courses/domain/DurationTest.java b/src/test/java/nextstep/courses/domain/session/DurationTest.java similarity index 96% rename from src/test/java/nextstep/courses/domain/DurationTest.java rename to src/test/java/nextstep/courses/domain/session/DurationTest.java index 1c7ea0e68..0cc241776 100644 --- a/src/test/java/nextstep/courses/domain/DurationTest.java +++ b/src/test/java/nextstep/courses/domain/session/DurationTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/src/test/java/nextstep/courses/domain/SessionBodyTest.java b/src/test/java/nextstep/courses/domain/session/SessionBodyTest.java similarity index 94% rename from src/test/java/nextstep/courses/domain/SessionBodyTest.java rename to src/test/java/nextstep/courses/domain/session/SessionBodyTest.java index 4528f0faf..6e1db0447 100644 --- a/src/test/java/nextstep/courses/domain/SessionBodyTest.java +++ b/src/test/java/nextstep/courses/domain/session/SessionBodyTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import static org.assertj.core.api.Assertions.assertThatThrownBy; diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/session/SessionTest.java similarity index 96% rename from src/test/java/nextstep/courses/domain/SessionTest.java rename to src/test/java/nextstep/courses/domain/session/SessionTest.java index 2e2d134e5..18d3bf3e9 100644 --- a/src/test/java/nextstep/courses/domain/SessionTest.java +++ b/src/test/java/nextstep/courses/domain/session/SessionTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import static nextstep.courses.domain.builder.EnrollmentBuilder.aFreeEnrollmentBuilder; import static nextstep.courses.domain.builder.EnrollmentBuilder.aPaidEnrollmentBuilder; @@ -9,6 +9,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException; import java.util.List; +import nextstep.courses.domain.enrollment.EnrolledUsers; import nextstep.payments.domain.Payment; import nextstep.users.domain.NsUserTest; import org.junit.jupiter.api.Test; diff --git a/src/test/java/nextstep/courses/domain/SessionsTest.java b/src/test/java/nextstep/courses/domain/session/SessionsTest.java similarity index 84% rename from src/test/java/nextstep/courses/domain/SessionsTest.java rename to src/test/java/nextstep/courses/domain/session/SessionsTest.java index e8c84301f..b0770bb12 100644 --- a/src/test/java/nextstep/courses/domain/SessionsTest.java +++ b/src/test/java/nextstep/courses/domain/session/SessionsTest.java @@ -1,4 +1,4 @@ -package nextstep.courses.domain; +package nextstep.courses.domain.session; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -6,8 +6,12 @@ import java.time.LocalDateTime; import java.util.List; import nextstep.courses.CanNotJoinException; -import nextstep.courses.domain.enrollmentcondition.FreeEnrollmentCondition; -import nextstep.courses.domain.enrollmentcondition.PaidEnrollmentCondition; +import nextstep.courses.domain.enrollment.EnrolledUsers; +import nextstep.courses.domain.enrollment.Enrollment; +import nextstep.courses.domain.enrollment.EnrollmentPolicy; +import nextstep.courses.domain.enrollment.SessionStatus; +import nextstep.courses.domain.enrollment.enrollmentcondition.FreeEnrollmentCondition; +import nextstep.courses.domain.enrollment.enrollmentcondition.PaidEnrollmentCondition; import nextstep.courses.domain.enumerate.CoverImageType; import nextstep.courses.domain.enumerate.EnrollmentType; import nextstep.courses.domain.enumerate.SessionStatusType; diff --git a/src/test/java/nextstep/courses/infrastructure/CourseRepositoryTest.java b/src/test/java/nextstep/courses/infrastructure/CourseRepositoryTest.java index f087fc0ad..a1279a37f 100644 --- a/src/test/java/nextstep/courses/infrastructure/CourseRepositoryTest.java +++ b/src/test/java/nextstep/courses/infrastructure/CourseRepositoryTest.java @@ -1,7 +1,9 @@ package nextstep.courses.infrastructure; -import nextstep.courses.domain.Course; -import nextstep.courses.domain.CourseRepository; +import static org.assertj.core.api.Assertions.assertThat; + +import nextstep.courses.domain.course.Course; +import nextstep.courses.domain.course.CourseRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -10,8 +12,6 @@ import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; import org.springframework.jdbc.core.JdbcTemplate; -import static org.assertj.core.api.Assertions.assertThat; - @JdbcTest public class CourseRepositoryTest { private static final Logger LOGGER = LoggerFactory.getLogger(CourseRepositoryTest.class);