在Java中创建不可变类的可能性

mic*_*man 2 java immutability

在Java中创建不可变bean的可能性有多大?例如,我有不可变的类Person.什么是创建实例和填充私有字段的好方法.公共构造函数对我来说似乎并不好,因为当类在其他应用程序中增长时会出现很多输入参数.谢谢你的任何建议.

public class Person {

private String firstName;
private String lastName;
private List<Address> addresses;
private List<Phone> phones;

public List<Address> getAddresses() {
    return Collections.unmodifiableList(addresses);
}

public String getFirstName() {
    return firstName;
}

public String getLastName() {
    return lastName;
}

public List<Phone> getPhones() {
    return Collections.unmodifiableList(phones);
}
}
Run Code Online (Sandbox Code Playgroud)

编辑:更准确地指定问题.

Joa*_*uer 7

您可以使用构建器模式.

public class PersonBuilder {
  private String firstName;
  // and others...

  public PersonBuilder() {
    // no arguments necessary for the builder
  }

  public PersonBuilder firstName(String firstName) {
    this.firstName = firstName;
    return this;
  }

  public Person build() {
    // here (or in the Person constructor) you could validate the data
    return new Person(firstName, ...);
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用它:

Person p = new PersonBuilder.firstName("Foo").build();
Run Code Online (Sandbox Code Playgroud)

乍一看,它可能看起来比具有大量参数的简单构造函数更复杂(并且可能是),但是有一些显着的优点:

  • 您无需指定要保留默认值的值
  • 您可以扩展Person类和构建器,而无需声明多个构造函数或需要重写创建的每个代码Person:只需向构建器添加方法,如果有人不调用它们,则无关紧要.
  • 您可以传递构建器对象,以允许不同的代码片段设置不同的参数Person.
  • 您可以使用构建器创建多个类似的Person对象,这对于单元测试很有用,例如:

    PersonBuilder builder = new PersonBuilder().firstName("Foo").addAddress(new Address(...));
    Person fooBar = builder.lastName("Bar").build();
    Person fooBaz = builder.lastName("Baz").build();
    assertFalse(fooBar.equals(fooBaz));
    
    Run Code Online (Sandbox Code Playgroud)

  • @Deepak:在我的例子中没有使用不变性.我的例子是在'Person`类中启用**不可变性(或者确切地说:在`Person`类中启用不变性,同时仍然保持构造`Person`对象的理智). (2认同)
  • @Deepak:再次:**构建器不是一个不可变类的例子.**OP问他怎么能有一个不可变的`Person`类而不必处理一个巨大的构造函数参数列表来填充的痛苦每一次.构建器是**特定问题**的解决方案. (2认同)