这是否被认为是循环依赖(这是一个好习惯)?

r0w*_*der 5 java oop

嗨,我是一名新的 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 或其他东西中检索课程。这仍然是一个好的结构吗?从现在开始,每个课程仍然关心学生。每个学生仍然关心课程。

Joo*_*gen 6

相互引用很好,所有数据库实体都并排存在,相互引用。

构造函数必须允许创建,而不是被禁止只有在另一个已经存在的情况下才能创建它们。

因此可能有两个构造函数。

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)。


jbu*_*ddy 5

第一个片段可以被认为是一个有效的设计(稍作修改,见下文)。假设你有一个学院:

  • 要注册 a 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)

作为旁注,此设计可能有多种变体,但我的观点是,您的设计几乎是有效的,除了在课程初始化时不设置学生列表的小修改。


Con*_*Del 5

老实说,您最好以 DAO / POJO 方式执行此操作,并将您的课程和学生解耦

如果您使用的是 SQL 数据库,您可能会设置如下表

Course
Student
Enrollment
Run Code Online (Sandbox Code Playgroud)

Enrollment 有一个课程、一个学生、一个开始日期,也许还有一个结束日期。这样,课程和学生就解耦了。

我建议你像这样为你的课程建模