有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在构造函数中完成类的主要工作时有什么问题吗?

我一直认为,一般来说,类的主要工作应该在其实例方法中完成,而构造函数应该只让实例进入可用的初始状态

但我发现,在实践中,在某些情况下,将所有实际工作都放到构造函数中似乎更有意义

一个例子:我需要从数据库中检索一些DBMS特定的信息。对我来说,最自然的方式似乎是使用带有构造函数的DBMSSpecInfo类:

public DBMSSpecInfo(java.sql.Connection conn) throws SQLException{
  // ... retrieve info from DBMS
}

/** @returns max size of table in kiB */
public int getMaxTableSize() {//...}

/** @returns max size of index in kiB */
public int getMaxIndexSize() {//...}

/** @returns name of default schema */
public String getDefaultSchema() {//...}

您将构造一次类,构造函数将获取所有数据,然后您可以使用各种getter来检索所需的信息

当然,我可以将该方法放在其他地方,只使用DBMSSpecInfo作为返回值(基本上只使用DBMSSpecInfo作为值持有者),但是创建一个仅用于从单个函数返回值的类感觉很难看

那你觉得呢?在建造商中执行主要工作是否存在问题?它在Java中是否“非惯用”?或者这是一种可以接受(尽管可能不常见)的做法


共 (6) 个答案

  1. # 1 楼答案

    我认为在构造函数中执行主要工作不是一个好主意,因为它没有返回值。因此,它使错误处理更加复杂,因为它迫使您使用异常

  2. # 2 楼答案

    在构造函数中执行工作的一个缺点是构造函数不能被重写(也不应该委托给可重写的方法)

    另一个是构造函数要么全有要么全无。如果对象包含初始化失败的数据,那么您就失去了使用可以成功获取的数据的能力。类似地,您必须初始化整个对象,即使您只需要其中的一部分,也可能会对性能产生不利影响

    另一方面,在构造函数中执行此操作允许共享初始化状态(此处:与数据库的连接),并更早地释放

    一如既往,在不同的情况下,不同的方法更可取

  3. # 3 楼答案

    我热衷于实用主义。如果有用,就去做!但以纯洁和善良的名义,我想提出一个设计建议:

    这个类使用检索数据内容的机制来混淆数据内容。您最终在别处使用的对象只对其包含的数据感兴趣。所以“干净”的方法是使用不同的类来挖掘信息,然后创建这个属性对象的实例

    另一个类的生命周期可能更长,因为您通常会调用一个方法来完成工作,而不是调用构造函数。DBMSSpecInfo的构造函数最终可能会分配一组属性,但不会执行很多支持错误的DB访问工作

  4. # 4 楼答案

    主要的实际问题是单元测试——如果不进行实际工作,就无法实例化对象。(或者,您必须模拟参与此工作的所有类)

    相关谈话:OO Design for testability。它给出了为什么在构造函数中工作不利于单元测试的示例

  5. # 5 楼答案

    在您的示例中,我将创建一个静态方法getdbmspecinfo(java.sql.Connection conn),该方法将在出现错误时返回dbmspecinfo对象的实例或null(以防您不想抛出异常)

    对于我来说,DBMSSpecInfo对象只应包含get属性:MaxIndexSize、MaxTableSize、DefaultSchema等

    我会将这个对象的构造函数设置为私有的,这样只能从静态方法创建实例

  6. # 6 楼答案

    在这种情况下,我更愿意将创建代码与类本身分离。它可以放入一个静态工厂方法,或者一个单独的工厂类(也可以是一个公共静态内部类)。选择取决于代码的复杂性和设计上下文(在本例中我们不知道)

    这还允许您进行优化,比如缓存和重用类实例