4
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 构建对象。

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

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

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

4

4 回答 4

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

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

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

于 2012-09-21T15:23:26.487 回答
0

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

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

实际上是最好的事情。

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

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

据我所知,调用 setter 原因是在做一些验证或一些逻辑。这很好。

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

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

于 2012-09-21T15:15:50.783 回答
0

就我个人而言,我不是二传手的忠实粉丝。我喜欢不变性,因此在您的示例中,我会将参数传递给ctor。在那里进行检查,然后分配给最终字段。设置者将不存在。你只会有吸气剂。

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

然后您就会知道对象在构造时处于有效状态。如果它的某些部分为空,那么您可以重载构造函数。您不知道需要通过无参数构造函数和设置器填充哪些字段。通过在构造函数中使用参数强制执行它,您正在强制将对象初始化为有效状态。

于 2012-09-21T15:17:17.223 回答
0

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

但是,这样做的问题是子类可能会覆盖这些设置器,这意味着您预期的验证不再发生。

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


边注:

你教授的例子有点不对劲。

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

于 2012-09-21T15:18:02.110 回答