Помимо связи один-ко-многим, очень распространена связь многие-ко-многим. Например, такой связью обладают курсы и пользователи. С одной стороны, пользователь может проходить множество курсов, с другой, курс проходится большим количеством студентов.
Кажется, что такую связь можно реализовать, сделав зависимую сущность коллекцией с обоих концов, со стороны курса и со стороны пользователя.
user.addCourse(course);
user.getCourses();
// или
course.addUser(user);
course.getUsers();
На практике же, такая реализация не позволяет смоделировать нашу предметную область правильно. Когда человек вступает в курс, то у него появляется дата вступления в курс, кроме этого, курс можно закончить, а это обязательно должно быть где-то отражено. Эта информация не относится ни к курсу, ни к пользователю, она относится к их связи.
Такую связь реализуют с помощью введения третьей сущности, которая может и, обычно, содержит какие-то дополнительные данные появляющиеся только во время создания связи. В случае курсов, мы точно хотим знать когда пользователь начал курс и когда он его закончил. Помимо этого мы можем добавить другую информацию, которая привязана именно к связи, а не к пользователю или курсу.
В случае курсов и пользователей, сущность, которая связывает курсы и пользователи можно назвать CourseMember
(участник курса). Вот ее код:
import java.time.LocalDate;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class CourseMember {
private Course course;
private User user;
private LocalDate startedAt;
private LocalDate finishedAt;
}
И использование:
var course = new Course("Java ООП");
var user = new User("Mila");
var member = new CourseMember();
member.setCourse(course);
member.setUser(user);
member.setStartedAt(LocalDate.now());
Мы связали курсы и пользователей связью многие-ко-многим, при этом получившаяся сущность CourseMember
связана с курсом и пользователем связью один-к-одному. Визуально это выглядит так.
+----------------+ +---------------------+ +----------------+
| User | | CourseMember | | Course |
+----------------+ +---------------------+ +----------------+
| - attributes |1 *| - Course |* 1| - attributes |
| - methods |<---------| - User |--------->| - methods |
+----------------+ | - startedAt | +----------------+
| - finishedAt |
+---------------------+
Для полной реализации таких связей, нам нужно добавить CourseMember
в каждую из зависимых сущностей.
@Setter
@Getter
class User {
private String name;
private List<CourseMember> courseMembers;
public User(String name) {
this.name = name;
courseMembers = new ArrayList<>();
}
public void addCourseMember(CourseMember courseMember) {
courseMembers.add(courseMember);
}
public void removeCourseMember(CourseMember courseMember) {
courseMembers.remove(courseMember);
}
// другие методы
}
@Setter
@Getter
class Course {
private String name;
private List<CourseMember> courseMembers;
public Course(String name) {
this.name = name;
courseMembers = new ArrayList<>();
}
public void addCourseMember(CourseMember courseMember) {
courseMembers.add(courseMember);
}
public void removeCourseMember(CourseMember courseMember) {
courseMembers.remove(courseMember);
}
// другие методы
}
class CourseMember {
private User user;
private Course course;
private String role;
private String enrollmentDate;
public void setCourse(Course course) {
this.course = course;
course.addCourseMember(this);
}
public void setUser(User user) {
this.user = user;
user.addCourseMember(this);
}
}
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.