嗨,我是一名新的 Java 程序员,有一个关于类设计的小问题。
我知道这样的事情是一种循环依赖,可能不是构建项目的一种方式:
public class Course {
private ArrayList<Student> students;
public Course (ArrayList<Student> students) {
this.students = students;
}
}
public class Student {
private Course course;
public Student (Course course) {
this.course = course;
}
}
Run Code Online (Sandbox Code Playgroud)
但是如果 Student.java 改为:
public class Student {
private int courseId;
public Student (int courseId) {
this.courseId = courseId;
}
}
Run Code Online (Sandbox Code Playgroud)
这样courseId就可以用来从 DAO 或其他东西中检索课程。这仍然是一个好的结构吗?从现在开始,每个课程仍然关心学生。每个学生仍然关心课程。
相互引用很好,所有数据库实体都并排存在,相互引用。
构造函数必须允许创建,而不是被禁止只有在另一个已经存在的情况下才能创建它们。
因此可能有两个构造函数。
public class Course {
private List<Student> students = new ArrayList<>();
public Course() {
}
public Course (List<Student> students) {
this.students.addAll(students);
}
}
public class Student {
private Course course;
public Student (Course course) {
this.course = course;
course.addStudent(this);
}
}
Run Code Online (Sandbox Code Playgroud)
对于数据库,通常有数字 ID,但许多对象/关系映射仍然可以让您使用上述类,在引擎盖下使用 ID(JPA、eclipseLink、hibernate)。不需要具有不对称的 ID 和对象引用。
你不应该使用具体的实现(ArrayList),而应该是最灵活的(List)。
此外,最好不要公开字段的内部数据 ( students) 以进行外部更改。
关于概括 ( List) 和实现 ( ArrayList)
一些(脚本)语言的集合只有一种类型。Java 旨在为一个接口提供多种实现。
所以你可以决定是将Map的数据结构实现为fast HashMap还是ordered TreeMap。一般来说,用户现在只需要了解 Map。您无需过度指定代码,甚至可以简单地使用不同的实现类来重新设计。
List<String> list = ...
Collections.sort(list);
list.add(...);
List<String> convert(List<String> list) { ... }
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,您convert可以处理任何类型的 List;您已经编写了一个更通用的算法,而不仅仅是用于 ArrayList。在该方法中,您可以返回一个 ArrayList 或一个 LinkedList。这使得不太可能由于错误的过度规范而更改代码。
针对Nick Hodges 的接口编码(请原谅错误的电源插座和 TypeScript)。
第一个片段可以被认为是一个有效的设计(稍作修改,见下文)。假设你有一个学院:
Student,学生需要选择一门课程,因此构造函数public Student (Course course)Course有一个注册学生列表,但是,它最初是在没有学生的情况下创建的。它们是稍后添加的。事实上,我可以这样使用它:
public class Course {
private String name;
private List<Student> students;
public Course (String name) {
this.name = name;
students = new ArrayList<>();
}
public void addStudent(Student student) {
students.add(student);
}
}
public class Student {
private Course course;
public Student (Course course) {
this.course = course;
}
}
/// -- now...
Course history = new Course("History");
Student historyStudent = new Student(history);
history.add(historyStudent);
Run Code Online (Sandbox Code Playgroud)
作为旁注,此设计可能有多种变体,但我的观点是,您的设计几乎是有效的,除了在课程初始化时不设置学生列表的小修改。
老实说,您最好以 DAO / POJO 方式执行此操作,并将您的课程和学生解耦
如果您使用的是 SQL 数据库,您可能会设置如下表
Course
Student
Enrollment
Run Code Online (Sandbox Code Playgroud)
Enrollment 有一个课程、一个学生、一个开始日期,也许还有一个结束日期。这样,课程和学生就解耦了。
我建议你像这样为你的课程建模