看下面的代码:
class Person {
String name;
int age;
Person(Consumer<Person> consumer) {
consumer.accept(this);
}
}
如您所见,我正在使用“消费者构造函数”,因此我可以创建一个这样的人:
var person = new Person(p -> {
p.name = "John";
p.age = 30;
})
似乎这种方法比构建器模式或全参数构造函数要好得多。
自 Java 8 发布以来已经过去了 4 年,但没有人使用消费者构造函数(至少我以前没见过)。
我不明白为什么?这种方法是否存在一些缺陷或局限性?
我找到了一个,但我认为它不重要:
class AdvancedPerson extends Person {
String surname;
AdvancedPerson(Consumer<AdvancedPerson> consumer) {
super(); // <-- what to pass?
consumer.accept(this);
}
}
当然,我们可以在 Person
中创建一个无参数构造函数,然后在 AdvancedPerson
消费者构造函数中调用它。但这是解决方案吗?
那你怎么看呢?
使用消费者构造函数安全吗?
这是构建器和全参数构造器的替代品吗?为什么?
最佳答案
在我看来,它既不安全也不优雅。有几个理由反对这种方法:最糟糕的是,它不仅允许而且还强制您在对象尚未初始化时让 this 引用转义。这有几个严重的不良影响:
- 消费者将有一个对象的引用,该对象处于中间构造函数调用中。然后,消费者可以做各种邪恶的事情,例如调用被另一个子类覆盖的方法。
- 消费者也可以看到部分状态的对象,例如一些成员初始化,而其他成员则没有。当涉及多线程时,情况会变得更糟。
- 无法使用这种方法创建不可变对象(immutable对象),因为您必须允许消费者干预正在构建的对象的内部结构。
- 最后但并非最不重要的一点是,您将负责保证类不变量的负担交给了消费者。这绝对是一个类应该自己负责的事情。
有关创建对象的最佳实践,请参阅 effective java 的第二章。
关于java - 消费者构造函数陷阱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49637637/