Java – 来自构造函数的setter

package cen.col.course.demo; import java.io.Serializable; public class Course implements Serializable { private static final long serialVersionUID = 1L; protected String code; protected String title; protected Professor professor; public Course( String code) throws InvalidDataException { super(); setCode(code); } public Course(String code, String title ) throws InvalidDataException { this(code); setTitle(title); } public Course(String code, String title, Professor professor) throws InvalidDataException { this(code,title); setProfessor(professor); } public String getCode() { return code; } protected void setCode(String code) throws InvalidDataException { if ( code == null || code.length() < 1) { throw new InvalidDataException("Course must have a course code"); } this.code = code; } public String getTitle() { return title; } public void setTitle(String title) throws InvalidDataException { if ( title == null || title.length() < 1) { throw new InvalidDataException("Course must have a title"); } this.title = title; } public Professor getProfessor() { return professor; } public void setProfessor(Professor professor) { this.professor = professor; } public String toString() { String output = getCode() + ": [" + getTitle() + "]"; if (getProfessor() != null ) { output += " is taught by " + getProfessor(); } return output; } public boolean equals(Course c) { if ( ! this.getCode().equals(c.getCode())){ return false; } if ( ! this.getTitle().equals(c.getTitle())){ return false; } // should the prof field be included in test for equality? if ( ! this.getProfessor().equals(c.getProfessor())){ return false; } return true; } } 

我有三个问题:

  1. 我注意到我的教授从构造函数中调用了setter方法。 我做了一些搜索,并对它有不同的想法。 有人说没关系,有人说你在使用子类时要小心,是否可以从构造函数中调用你的setter?

  2. 构造函数抛出exception,因为她从构造函数中调用setter。 现在我的问题是,如果从构造函数中调用setter并不是一种安全的方法,那么这样做的正确方法是什么? 我的猜测是声明一个无参数构造函数,并使用setter构建对象。

  3. 我想这样做是不可能的?

    课程createCourse =新课程(“1234”,“编程1”,“Pam Halpert”);

我正在调用带有3个参数的构造函数,但是,如果从构造函数中调用setter是不安全的,那么如何执行此操作并具有exception? 我可以使用if语句吗? 检查是否有空白并在必要时抛出exception?

由于这是家庭作业或一些学习,你的教授很想向你展示一些东西。

然而,
Course createCourse = new Course("1234","Programming 1","Pam Halpert");

实际上是最好的事情。

根据您正在开发的内容,大多数情况下,您希望提供尽可能少的构造函数,除非您正在设计编程语言。 如果您正在使用公共API或产品,则应确保您的消费者不会犯错误或滥用您的API,如果您允许他们创建错误。

构造函数可以抛出exception,这很好。

据我所知,调用setter的原因是做了一些validation或一些逻辑。 这很好。

请记住,在构造函数中执行任何工作都被认为是一种不好的做法。

你应该在类之外做它并将它们作为构造函数参数或setter / getter传递。

  1. 在构造函数中调用setter通常具有以下优点:有时setter内部已经有一些validation逻辑(比如示例中的setTitle),并且您不希望复制此逻辑。 但是,正如您已经提到的,调用setter可能会导致问题,即子类可能会因意外行为而覆盖它们。 要解决此问题,您可以将setter设置为private或final,以便它们不会被覆盖。 只调用私人/最终制定者是一种很好的做法,不应该导致任何问题。

  2. 获取无效数据的构造函数抛出exception是很好的。 您不想创建无效对象。

  3. 首先创建一个空对象(通过空构造函数),然后通过setter填充其数据是相当不好的做法。 通过这种方式,您将有一段时间处于无意义状态的对象,其中包含一些数据填充,一些数据未填充,这可能会导致麻烦。 另外,正如另一个已经提到的答案,您应该考虑减少构造函数的数量 – 没有教授的课程真的有效吗? 如果不是,则不需要是构造者创建这样的对象……

如果您的setter执行某种forms的数据validation,则调用setter非常有用。 这允许您将validation放在一个位置,并确保在实例化时设置的属性符合validation规则。

但是,问题在于子类可能会覆盖这些setter,这意味着您的预期validation不再发生。

因此,创建进行validation的私有 setter是有意义的。 在构造函数中调用这些私有setter。 如果你想拥有公共设置器,那很好,只需在你的私人设置器周围创建一个公共包装器设置器。


边注:

你教授的例子有点过时了。

validation似乎旨在确保始终设置titlecode 。 但是,代码还提供了允许您设置title构造函数。 这几乎肯定是一个错误(我肯定会在代码审查中将其标记为一个错误)。

就我个人而言,我并不是一个狂热的粉丝。 我喜欢不变性,所以在你的例子中我会将参数传递给ctor。 在那里检查,然后分配到最终字段。 塞特斯不存在。 你只会有吸气剂。

如果要更新,则可以引入复制构造函数。

然后你会知道构造它的对象处于有效状态。 如果它的某些部分为null,那么您可以重载构造函数。 你不知道需要通过no-arg constrcturs和setter来填充哪些字段。 通过在构造函数中使用参数强制执行它,您将强制对象在有效状态下初始化。