我对建造者模式非常感兴趣,我经常使用它,但我不确定我制造的建造者是否足够好,而且我对所有可以使用它们的周围环境都有疑问。 这是我如何创建构建器的示例:
public class Person {
private String name;
private String secondName;
private int age;
public static class Builder {
private boolean isBuilt;
private Person person = new Person();
private void check() {
if (isBuilt) {
throw new IllegalStateException(
"The object cannot be modified after built");
}
}
public Builder withName(String name) {
check();
person.name = name;
return this;
}
public Builder withSecondName(String secondName) {
check();
person.secondName = secondName;
return this;
}
public Builder withAge(int age) {
check();
person.age = age;
return this;
}
public Person build() {
check();
isBuilt = true;
return person;
}
}
@Override
public String toString() {
return "Name: " + name + "\nSecond name:" + secondName + "\nAge:" + age;
}
}
快速使用示例:
Person person = new Person.Builder()
.withName("John")
.withSecondName("Smith")
.withAge(50)
.build();
System.out.println(person);
这里有些疑点:
答案 0 :(得分:1)
你认为它真的是不变的吗? [...]这真的是线程安全吗?
您的代码中没有任何部分是不可变的。这也可能妨碍线程安全;这表示很难以二进制方式声明一个类是否是线程安全的。我也不明白为什么你会首先在线程之间共享构建器实例,但是我可能会因代码示例的简单性而误导。
为了更轻松地实现线程安全,您的Builder
应该是不可变的。这意味着每个withXXX()
方法都应返回一个表示新状态的新构建器。 (这可能是更聪明的方法,但这将是直截了当的方法。)
重申一下:我不确定是否必须使构建器线程安全 - 大多数情况下它们是具有非常短的生命周期和可见范围的对象。是否要使它们不可变取决于用例,您可能希望存储部分填充的构建器,但这也很少见。 (主观上,对于名称以with
开头的方法而言,它似乎更直观,不能就地修改对象,而不是名称以set
开头的对象。)
您是否认为此构建器在可以使用的场景方面有任何限制?
这通常是无法回答的,但是如果你确实使你的Person
对象不可变,因此只能由你的构建器构建,它们将无法用作JPA实体,我的猜测也是JSF支持bean。为您创建/管理某些对象的Java框架通常比不期望它们是JavaBeans,这意味着可以通过反射调用no-args构造函数和属性setter来创建这些对象。