Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/main/java/nextstep/common/domain/BaseEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ public abstract class BaseEntity {
private LocalDateTime createdDate;
private LocalDateTime updatedDate;

protected BaseEntity(Long id) {
this(id, LocalDateTime.now(), LocalDateTime.now());
}

public BaseEntity(Long id, LocalDateTime createdDate, LocalDateTime updatedDate) {
protected BaseEntity(Long id, LocalDateTime createdDate, LocalDateTime updatedDate) {
this.id = id;
this.createdDate = createdDate;
this.updatedDate = updatedDate;
}

public Long getId() {
protected Long getId() {
return id;
}

protected LocalDateTime getCreatedDate() {
return createdDate;
}

protected LocalDateTime getUpdatedDate() {
return updatedDate;
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
Expand Down
151 changes: 151 additions & 0 deletions src/main/java/nextstep/courses/cohort/domain/Cohort.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package nextstep.courses.cohort.domain;

import static java.util.Objects.isNull;

import java.time.LocalDateTime;
import java.util.Objects;
import nextstep.common.domain.BaseEntity;
import nextstep.courses.cohort.domain.enumeration.CohortStateType;

public class Cohort extends BaseEntity {
Copy link
Contributor

Choose a reason for hiding this comment

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

Cohort 객체는 우리가 현장에서 흔하게 접하는 인스턴스 변수가 많은 객체의 모습이다.
객체 지향 생활 체조 원칙의 다음 두 가지 원칙에 지키기 위해 노력해 본다.

  • 규칙 6: 모든 엔티티를 작게 유지한다.
  • 규칙 7: 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.

특히 규칙 7의 경우 지키기 힘들다 하더라도 인스턴스 변수의 수를 줄이기 위해 도전해 본다.
힌트: 상속을 통한 인스턴스 변수 줄이기, 관련 있는 인스턴스 변수를 새로운 객체로 분리하기 등 활용


private final Long courseId;
private int cohortCount;
private CohortStudentCount cohortStudentCount;
private CohortState cohortState2;

public Cohort(
Long courseId,
int cohortCount,
int maxStudentCount,
int presentStudentCount,
CohortStateType cohortStateType,
LocalDateTime registerStartDate,
LocalDateTime registerEndDate,
LocalDateTime cohortStartDate,
LocalDateTime cohortEndDate
) {
this(0L, courseId, cohortCount, maxStudentCount, presentStudentCount,
cohortStateType, registerStartDate, registerEndDate, cohortStartDate,
cohortEndDate, null, null);
}

public Cohort(
Long courseId,
int cohortCount,
int maxStudentCount,
int presentStudentCount,
LocalDateTime registerStartDate,
LocalDateTime registerEndDate,
LocalDateTime cohortStartDate,
LocalDateTime cohortEndDate
) {
this(0L, courseId, cohortCount, maxStudentCount, presentStudentCount,
CohortStateType.PREPARE, registerStartDate, registerEndDate, cohortStartDate,
cohortEndDate, null, null);
}

public Cohort(
Long id,
Long courseId,
int cohortCount,
int maxStudentCount,
int presentStudentCount,
CohortStateType cohortStateType,
LocalDateTime registerStartDate,
LocalDateTime registerEndDate,
LocalDateTime cohortStartDate,
LocalDateTime cohortEndDate,
LocalDateTime createdDate,
LocalDateTime updatedDate
) {
super(id, createdDate, updatedDate);
if (courseId <= 0L) {
throw new IllegalArgumentException("기수는 관련 코스정보가 필수 입니다.");
}

if (cohortCount <= 0) {
throw new IllegalArgumentException("기수는 회차정보가 필수 입니다.");
}

this.courseId = courseId;
this.cohortCount = cohortCount;
this.cohortStudentCount = new CohortStudentCount(maxStudentCount, presentStudentCount);
this.cohortState2 = new CohortState(cohortStateType,
new Period(registerStartDate, registerEndDate),
new Period(cohortStartDate, cohortEndDate));
}

public boolean isCanResist() {
if (!this.cohortState2.isSameState(CohortStateType.RECRUIT)) {
return false;
}

return this.cohortStudentCount.isNotOverMax();
}

public boolean putOnRecruitEnd(LocalDateTime now) {
if (isNull(now)) {
return false;
}

if (this.cohortState2.isBeforeRecruitPeriod(now)) {
return false;
}

if (!this.cohortState2.isSameState(CohortStateType.RECRUIT)) {
return false;
}

if (this.cohortState2.isInRecruitPeriod(now) && this.cohortStudentCount.isNotOverMax()) {
return false;
}

this.cohortState2.changeRecruitEnd();
return true;
}

public boolean isSameCourseId(Long courseId) {
if (isNull(courseId)) {
return false;
}

return this.courseId.equals(courseId);
}

public void registerStudent() {
if (!isCanResist()) {
return;
}

this.cohortStudentCount.plusOneCountAtPresent();
}

public boolean isCohortStateType(CohortStateType cohortStateType) {
return this.cohortState2.isSameState(cohortStateType);
}

public Long getId() {
return super.getId();
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
Cohort cohort = (Cohort) o;
return cohortCount == cohort.cohortCount && Objects.equals(courseId, cohort.courseId)
&& Objects.equals(cohortStudentCount, cohort.cohortStudentCount)
&& Objects.equals(cohortState2, cohort.cohortState2);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), courseId, cohortCount, cohortStudentCount,
cohortState2);
}
}
38 changes: 38 additions & 0 deletions src/main/java/nextstep/courses/cohort/domain/CohortState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package nextstep.courses.cohort.domain;

import static java.util.Objects.isNull;

import java.time.LocalDateTime;
import nextstep.courses.cohort.domain.enumeration.CohortStateType;

public class CohortState {
private CohortStateType cohortStateType;
private Period registerPeriod;
private Period cohortPeriod;

public CohortState(CohortStateType cohortStateType, Period registerPeriod, Period cohortPeriod) {
this.cohortStateType = cohortStateType;
this.registerPeriod = registerPeriod;
this.cohortPeriod = cohortPeriod;
}

public boolean isSameState(CohortStateType cohortStateType) {
if (isNull(cohortStateType)) {
return false;
}

return this.cohortStateType.equals(cohortStateType);
}

public boolean isInRecruitPeriod(LocalDateTime now) {
return this.registerPeriod.isPeriodIn(now);
}

public boolean isBeforeRecruitPeriod(LocalDateTime now) {
return this.registerPeriod.isBeforeStartDate(now);
}

public void changeRecruitEnd() {
this.cohortStateType = CohortStateType.RECRUIT_END;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package nextstep.courses.cohort.domain;

public class CohortStudentCount {

private int maxStudentCount;
private int presentStudentCount;

public CohortStudentCount(int maxStudentCount, int presentStudentCount) {
if (maxStudentCount < 1) {
throw new IllegalArgumentException("수강가능 총인원은 1이상이어야 합니다");
}

if (presentStudentCount < 0) {
throw new IllegalArgumentException("현재 신청인원은 음수일수 없습니다");
}

this.maxStudentCount = maxStudentCount;
this.presentStudentCount = presentStudentCount;
}

public boolean isNotOverMax() {
return this.maxStudentCount > this.presentStudentCount;
}

public void plusOneCountAtPresent() {
if (!isNotOverMax()) {
return;
}

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

import java.util.List;

public class Cohorts {
private List<Cohort> cohorts;

public Cohorts(List<Cohort> cohorts) {
this.cohorts = cohorts;
}
}
38 changes: 38 additions & 0 deletions src/main/java/nextstep/courses/cohort/domain/Period.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package nextstep.courses.cohort.domain;

import static java.util.Objects.isNull;

import java.time.LocalDateTime;

public class Period {
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

private final LocalDateTime startDate;
private final LocalDateTime endDate;

public Period(LocalDateTime startDate, LocalDateTime endDate) {
if (isNull(startDate) || isNull(endDate)) {
throw new IllegalArgumentException("수강신청 시작일과 종료일은 필수값 입니다.");
}

if (startDate.isAfter(endDate)) {
throw new IllegalArgumentException("수강신청 시작일이 종료일보다 미래일수는 없습니다");
}

this.startDate = startDate;
this.endDate = endDate;
}

public boolean isPeriodIn(LocalDateTime targetDate) {
boolean startDateAfter = this.startDate.isBefore(targetDate);
boolean endDateBefore = this.endDate.isAfter(targetDate);

return startDateAfter && endDateBefore;
}

public boolean isOverEndDate(LocalDateTime targetDate) {
return this.endDate.isBefore(targetDate);
}

public boolean isBeforeStartDate(LocalDateTime targetDate) {
return this.startDate.isAfter(targetDate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package nextstep.courses.cohort.domain.enumeration;

public enum CohortStateType {
PREPARE("준비중"),
RECRUIT("모집중"),
RECRUIT_END("모집마감"),
ACTIVE("진행중"),
END("종료"),

;

private final String desc;

CohortStateType(String desc) {
this.desc = desc;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package nextstep.courses.cohort.domain.service;

import static java.util.Objects.isNull;

import java.time.LocalDateTime;
import nextstep.courses.cohort.domain.Cohort;
import nextstep.courses.enrollment.domain.Enrollment;
import nextstep.qna.exception.unchecked.WrongRequestException;

public class CohortDomainService {

public Enrollment registerEnrollment(Cohort cohort, Long studentId, Long courseId) {
if (!cohort.isCanResist()) {
throw new WrongRequestException("해당기수는 수강신청 할 수 없는 상태입니다");
}
if (!cohort.isSameCourseId(courseId)) {
throw new IllegalArgumentException("결제정보와 강의정보가 상이합니다.");
}

cohort.registerStudent();

// Cohort에서 studentId를 전달받아 Enrollment 반환 vs 외부에서 조합해서 Enrollment 반환하는 대신 id getter 오픈
// Cohort에서 Enrollment를 생성하는 동작을 가지고 있는것 보다 외부에서 하는며 두객체의 결합도를 낮추는게 더 좋다고 생각합니다
return new Enrollment(studentId, cohort.getId());
}

public void updateStateToRecruitEnd(Cohort cohort) {
if (isNull(cohort)) {
return;
}

cohort.putOnRecruitEnd(LocalDateTime.now());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package nextstep.courses.cohort.service.repository;

import java.util.Optional;
import nextstep.courses.cohort.domain.Cohort;
import org.springframework.stereotype.Repository;

@Repository
public interface CohortRepository {

Optional<Cohort> findById(Long id);

void update(Cohort cohort);
}
Loading