Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e900a4a
feat: CoverImage -> ImageType 구현
qwer920414-ctrl Dec 15, 2025
8271411
feat: CoverImage -> ImageSize 구현
qwer920414-ctrl Dec 15, 2025
cdcc5a9
feat: CoverImage -> ImageDimension 구현
qwer920414-ctrl Dec 15, 2025
20eb67f
feat: Session -> SessionDuration(시작일자/종료일자) 구현
qwer920414-ctrl Dec 15, 2025
2ae44f9
feat: Session -> SessionState 구현
qwer920414-ctrl Dec 16, 2025
31bccd9
feat: Session -> EnrollmentPolicy 인터페이스 구현 -> FreeEnrollmentPolicy(무료)
qwer920414-ctrl Dec 16, 2025
7131ea4
feat: Session -> EnrollmentPolicy 인터페이스 구현 -> PaidEnrollmentPolicy(유료…
qwer920414-ctrl Dec 16, 2025
00c2257
feat: Session 필드 추가
qwer920414-ctrl Dec 16, 2025
3612e77
feat: Session -> CoverImage 클래스 생성자 추가
qwer920414-ctrl Dec 16, 2025
b9e6e97
feat: Session 기본 생성자 추가
qwer920414-ctrl Dec 16, 2025
770df4d
feat: CoverImage -> ImageType에 fileName 추가
qwer920414-ctrl Dec 17, 2025
7dd2e8c
test: PaidEnrollmentPolicy 테스트코드 추가
qwer920414-ctrl Dec 17, 2025
bfc3ef3
feat: Session - 등록 로직 작성
qwer920414-ctrl Dec 17, 2025
64113eb
feat: Course - Session 추가(List<Session> -> Sessions 일급컬렉션 생성)
qwer920414-ctrl Dec 17, 2025
8f24ee3
feat: Enrollments 일급컬렉션 추가
qwer920414-ctrl Dec 21, 2025
91257e4
refactor: Capacity 역할 이동
qwer920414-ctrl Dec 21, 2025
b93d1f4
fix: Capacity 로직 수정
qwer920414-ctrl Dec 22, 2025
c97f057
refactor: Session Enrollments 적용 & SessionTest(Builder 적용 시도)
qwer920414-ctrl Dec 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/main/java/nextstep/courses/domain/Capacity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package nextstep.courses.domain;

public class Capacity {

private int max;
private int current;

public Capacity(int max, int current) {
this.max = max;
this.current = current;
}

public void validateAvailable() {
if (current > max) {
throw new IllegalStateException();
}
}
}
17 changes: 17 additions & 0 deletions src/main/java/nextstep/courses/domain/CoverImage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package nextstep.courses.domain;

public class CoverImage {
private ImageSize imageSize;
private ImageType imageType;
private ImageDimension imageDimension;

public CoverImage(int size, ImageType imageType, int width, int height) {
this(new ImageSize(size), imageType, new ImageDimension(width, height));
}

public CoverImage(ImageSize imageSize, ImageType imageType, ImageDimension imageDimension) {
this.imageSize = imageSize;
this.imageType = imageType;
this.imageDimension = imageDimension;
}
}
7 changes: 7 additions & 0 deletions src/main/java/nextstep/courses/domain/EnrollmentPolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package nextstep.courses.domain;

import nextstep.payments.domain.Payment;

public interface EnrollmentPolicy {
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

void validateEnrollment(Payment payment);
}
10 changes: 10 additions & 0 deletions src/main/java/nextstep/courses/domain/FreeEnrollmentPolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package nextstep.courses.domain;

import nextstep.payments.domain.Payment;

public class FreeEnrollmentPolicy implements EnrollmentPolicy{
@Override
public void validateEnrollment(Payment payment) {
// 무료강의는 검증하지 않는다
}
}
30 changes: 30 additions & 0 deletions src/main/java/nextstep/courses/domain/ImageDimension.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package nextstep.courses.domain;

public class ImageDimension {

public static final int HEIGHT_RATIO = 2;
public static final int WIDTH_RATIO = 3;
public static final int MIN_WIDTH = 300;
public static final int MIN_HEIGHT = 200;
private int width;
private int height;

public ImageDimension(int width, int height) {
validateMinimumSize(width, height);
validateRatio(width, height);
this.width = width;
this.height = height;
}

private static void validateMinimumSize(int width, int height) {
if (width < MIN_WIDTH || height < MIN_HEIGHT) {
throw new IllegalArgumentException();
}
}

private static void validateRatio(int width, int height) {
if (!(HEIGHT_RATIO * width == WIDTH_RATIO * height)) {
throw new IllegalArgumentException();
}
}
}
29 changes: 29 additions & 0 deletions src/main/java/nextstep/courses/domain/ImageSize.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package nextstep.courses.domain;

import java.util.Objects;

public class ImageSize {

public static final int MAX_SIZE = 1_048_576;
private int imageSize;

public ImageSize(int imageSize) {
if (imageSize > MAX_SIZE) {
throw new IllegalArgumentException();
}
this.imageSize = imageSize;
}

@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
ImageSize imageSize1 = (ImageSize) object;
return imageSize == imageSize1.imageSize;
}

@Override
public int hashCode() {
return Objects.hashCode(imageSize);
}
}
30 changes: 30 additions & 0 deletions src/main/java/nextstep/courses/domain/ImageType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package nextstep.courses.domain;

import java.util.Arrays;

public enum ImageType {

GIF("gif"),
JPG("jpg", "jpeg"),
PNG("png"),
SVG("svg");

private final String[] extensions;

ImageType(String... extensions) {
this.extensions = extensions;
}

private boolean matches(String extension) {
return Arrays.stream(extensions)
.anyMatch(ext -> ext.equalsIgnoreCase(extension));
}

public static ImageType from(String extension) {
return Arrays.stream(values())
.filter(type -> type.matches(extension))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException());
}

}
28 changes: 28 additions & 0 deletions src/main/java/nextstep/courses/domain/Money.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package nextstep.courses.domain;

import java.util.Objects;

public class Money {
private final long amount;

public Money(long amount) {
this.amount = amount;
}

public boolean isEqualTo(Money other) {
return this.equals(other);
}

@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
Money money = (Money) object;
return amount == money.amount;
}

@Override
public int hashCode() {
return Objects.hashCode(amount);
}
}
26 changes: 26 additions & 0 deletions src/main/java/nextstep/courses/domain/PaidEnrollmentPolicy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package nextstep.courses.domain;

import nextstep.payments.domain.Payment;

public class PaidEnrollmentPolicy implements EnrollmentPolicy {

private final Money money;
private final Capacity capacity;

public PaidEnrollmentPolicy(Money money, Capacity capacity) {
this.money = money;
this.capacity = capacity;
}

@Override
public void validateEnrollment(Payment payment) {
capacity.validateAvailable();
validatePayment(payment);
}

private void validatePayment(Payment payment) {
if (!payment.isSameAmount(money)) {
throw new IllegalArgumentException();
}
}
}
38 changes: 38 additions & 0 deletions src/main/java/nextstep/courses/domain/Session.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package nextstep.courses.domain;

import nextstep.payments.domain.Payment;

import java.time.LocalDateTime;

public class Session {
private final long id;
private final SessionDuration sessionDuration;
private final CoverImage coverImage;
private final EnrollmentPolicy enrollmentPolicy;
private final SessionState sessionState;

public Session(long id
, LocalDateTime startDate
, LocalDateTime endDate
, int size
, ImageType imageType
, int width
, int height
, EnrollmentPolicy enrollmentPolicy
, SessionState sessionState) {
this(id, new SessionDuration(startDate, endDate), new CoverImage(size, imageType, width, height)
, enrollmentPolicy, sessionState);
}

public Session(long id, SessionDuration sessionDuration, CoverImage coverImage
, EnrollmentPolicy enrollmentPolicy, SessionState sessionState) {
this.id = id;
this.sessionDuration = sessionDuration;
this.coverImage = coverImage;
this.enrollmentPolicy = enrollmentPolicy;
this.sessionState = sessionState;
}

public void enroll() {
}
}
20 changes: 20 additions & 0 deletions src/main/java/nextstep/courses/domain/SessionDuration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package nextstep.courses.domain;

import java.time.LocalDateTime;

public class SessionDuration {
private LocalDateTime startDate;
private LocalDateTime endDate;

public SessionDuration(LocalDateTime startDate, LocalDateTime endDate) {
validateDate(startDate, endDate);
this.startDate = startDate;
this.endDate = endDate;
}

private void validateDate(LocalDateTime startDate, LocalDateTime endDate) {
if (!startDate.isBefore(endDate)) {
throw new IllegalArgumentException();
}
}
}
13 changes: 13 additions & 0 deletions src/main/java/nextstep/courses/domain/SessionState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package nextstep.courses.domain;

public enum SessionState {
READY,
OPEN,
CLOSED;

public void validateEnroll() {
if (this != OPEN) {
throw new IllegalStateException();
}
}
}
10 changes: 8 additions & 2 deletions src/main/java/nextstep/payments/domain/Payment.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package nextstep.payments.domain;

import nextstep.courses.domain.Money;

import java.time.LocalDateTime;

public class Payment {
Expand All @@ -12,7 +14,7 @@ public class Payment {
private Long nsUserId;

// 결제 금액
private Long amount;
private Money amount;

private LocalDateTime createdAt;

Expand All @@ -23,7 +25,11 @@ public Payment(String id, Long sessionId, Long nsUserId, Long amount) {
this.id = id;
this.sessionId = sessionId;
this.nsUserId = nsUserId;
this.amount = amount;
this.amount = new Money(amount);
this.createdAt = LocalDateTime.now();
}

public boolean isSameAmount(Money money) {
return amount.isEqualTo(money);
}
}
17 changes: 17 additions & 0 deletions src/test/java/nextstep/courses/domain/CapacityTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package nextstep.courses.domain;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

class CapacityTest {

@Test
@DisplayName("최대 인원을 넘어서 수강신청이 들어오면 Exceptionn")
void max() {
Capacity capacity = new Capacity(300, 301);
assertThatThrownBy(() -> capacity.validateAvailable())
.isInstanceOf(IllegalStateException.class);
}
}
41 changes: 41 additions & 0 deletions src/test/java/nextstep/courses/domain/ImageDimensionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package nextstep.courses.domain;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class ImageDimensionTest {

@Test
@DisplayName("width가 300px 미만이면 예외가 발생한다")
void create_width_exception() {
assertThatThrownBy(() -> new ImageDimension(299, 200))
.isInstanceOf(IllegalArgumentException.class);
}

@Test
@DisplayName("height가 200px 미만이면 예외가 발생한다")
void create_height_exception() {
assertThatThrownBy(() -> new ImageDimension(300, 199))
.isInstanceOf(IllegalArgumentException.class);
}

@Test
@DisplayName("width와 height는 3:2 비율이 아니면 예외가 발생한다")
void create_width_height_exception() {
assertThatThrownBy(() -> new ImageDimension(300, 300))
.isInstanceOf(IllegalArgumentException.class);
}

@Test
@DisplayName("width_height_정상생성")
void create_success() {
assertThatNoException()
.isThrownBy(() -> new ImageDimension(300, 200));

assertThatNoException()
.isThrownBy(() -> new ImageDimension(600, 400));
}
}
Loading