Ruby(Rails)程序员已经2年了,刚换到另一个使用Java的团队。对Java builder模式有一些疑问。
我理解使用这种模式的好处,即避免伸缩构造函数和创建不一致状态的java bean setter但我无法准确理解它是如何工作的,以下是团队要求我使用的确切模式:
public class Person
{
//why is it so important that this be final, hence immutable
private final String firstName;
private final String lastName;
// Constructor
public Person(String firstName, String lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}
//I have absolutely no idea what is this for and why is this necessary
public static Builder builder()
{
return new Builder();
}
//This is an inner class, where person is the outer class (the owning class)
//but why is this has to be a static class?
public static class Builder
{
private String firstName;
private String lastName;
public Builder withFirstName(String firstName)
{
//this.firstName refers to the Builder instance firstName
this.firstName = firstName;
return this;
//what is this return this? returning this instance of the Builder object?
}
public Builder withLastName(String lastName)
{
this.lastName = lastName;
return this;
}
public Person build()
{
return new Person(firstName, lastName);
//firstName and lastName here refer to the Builder's object instance vars,
//and used to create a new person object
}
}
}
使用它:
Person p = new Person.Builder(5).firstName("foo").lastName("bar").build();
1)Builder的参数“5”是什么?
2)为什么Builder内部类是静态的?
3)public static Builder builder()方法的用途是什么?
4)我是否正确我们实际上正在创建一个新的内部类 - Builder对象,该内部类中的构建方法是否返回一个新的Person对象?
5)似乎要创建这个Person类,我必须加倍内存使用,一个用于外部类,一个用于内部类,是否效率不高?
6)我是否正确我仍然可以通过Person p = new Person(“foo”,“bar”)创建一个新的人物对象;
7)有人会如何测试这个?如何对安装者和吸气剂进行单元测试?
8)我可以在任何领域进行验证吗?
9)我如何指定一个字段是必需的,所以如果有人试图构建一个只有firstName但没有提供lastName的字段,它会抛出异常。
非常感谢提前!
答案 0 :(得分:1)
我不懂这个。 Builder
类中没有定义构造函数,因此这意味着编译器将自动生成无参数构造函数。
如果Builder
类不是静态的,则需要封闭类的实例来访问内部类。这将是一个“鸡和蛋”问题:内部类用于获取外部类的实例,但您首先需要外部类的实例来使用它! static
修饰符使得它不需要外部类的实例来使用它。
这是工厂方法的示例。现在,它只是创建一个Builder
的实例并返回它,但是将来可以将其更改为创建实例并在返回之前修改它,或者在返回实例之前执行安全检查
是的,你是对的。您可以创建内部类的实例,并使用其build
方法获取其外部类的实例。
大多数时候,良好的设计和良好的效率之间存在权衡。但是这一次,尽管你的内存使用量增加了一倍(因为这两个类都包含两个类型为String
的变量),实际的内存使用量并没有那么多。 (如果内存不足,可以通过将参数传递给JVM来更改JVM堆空间。)
是的,您可以像public
类中的Person
构造函数那样接收两个String
个对象。
可以通过创建Builder
的实例对其进行单元测试,使用其withFirstName
和withLastName
方法设置名称,然后在返回的方法上调用getter方法Person
对象,然后检查它们是否等于传入的值(使用String equals
方法)。
您可以使用String
类中的方法检查参数是否符合前提条件,如果不是则抛出异常。
(我假设你的意思是如果一个人传入null
的值,这是因为默认初始化的情况。)你可以利用一个方便的方法介绍在Java 7中引入的java.util.Objects
类Objects.requireNonNull()
中。将参数传递给它,如果参数为null
,它将抛出异常。否则,它将返回参数。