Java-来自构造函数的Setters


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. 构造函数抛出异常,因为她正在从构造函数调用setter。现在我的问题是,如果从构造函数中调用setter不是一种安全的方法,那么正确的方法是什么?我的猜测是声明一个无参数构造函数,并使用setter构建对象。

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

    Course createCourse=新课程("1234","Programming 1","Pam Halpert");

我正在调用接受3个参数的构造函数,但是,如果从构造函数调用setter不安全,如何执行此操作并将异常设置到位?我可以使用if语句吗?检查某个内容是否为空,并在必要时抛出异常?

  1. 在构造函数中调用setter通常具有这样的优势,即有时setter内部已经有一些验证逻辑(如示例中的setTitle),并且您不想重复此逻辑。然而,正如您已经提到的,调用setter可能会导致子类可能会用意外行为覆盖它们的问题。为了解决这个问题,你可以将setter设置为私有或最终设置,这样它们就不会被否决。只叫私人/最终的二传手是一种很好的做法,不应该导致任何问题。

  2. 获取无效数据的构造函数引发异常是可以的。您不希望创建无效的对象。

  3. 首先创建一个空对象(通过空构造函数),然后通过setter填充其数据,这是一种相当糟糕的做法。这样,在一段时间内,对象将处于无意义的状态,其中一些数据已填充,一些数据未填充,这可能会导致问题。此外,正如前面提到的另一个答案,你应该考虑减少构造函数的数量——没有教授的课程真的有效吗?如果没有,就不需要构造函数来创建这样的对象。。。

因为这是家庭作业或一些学习,你的教授很想给你看东西。

但是,
Course createCourse = new Course("1234","Programming 1","Pam Halpert");

实际上是最好的做法。

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

构造函数可以抛出和异常,这很好。

在我看来,调用setter reason是在做一些验证或逻辑。这很好。

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

您应该在类外执行此操作,并将它们作为构造函数参数或setter/getter传入。

如果您的setter进行某种形式的数据验证,那么调用setter非常有用。这允许您将验证放在一个地方,并确保在实例化时设置的属性符合验证规则。

然而,问题是子类可能会覆盖这些setter,这意味着您期望的验证不再发生。

因此,创建私有setter来进行验证是有意义的。在构造函数中调用这些私有setter。如果您也想拥有公共setter,那也没关系,只需围绕您的私有setter创建一个公共包装setter即可。


旁注:

你教授的例子有点离谱

验证似乎是为了确保始终设置titlecode。但是,该代码还提供了构造函数,允许而不是设置title。这几乎可以肯定是一个bug(我肯定会在代码审查中将其标记为bug)。

就我个人而言,我不是二传手的超级粉丝。我喜欢不变性,所以在你的例子中,我会把参数传递给ctor。在那里进行检查,然后分配给最终字段。Setter将不存在。你只会有胡瓜。

如果你想更新,那么你可以引入复制构造函数。

然后您就会知道,当对象被构造时,它处于有效的状态。如果它的某些部分为null,则可以重载构造函数。您不知道哪些字段需要通过没有argconstructure和setter来填充。通过在构造函数中使用参数强制它,您就是在强制对象在有效状态下初始化。

最新更新