2

what are possibilities of creating immutable bean in Java. For example I have immutable class Person. What's a good way to create instance and fill private fields. Public constructor doesn't seems good to me because of a lot input parameters will occure as class will grow in rest of application. Thank you for any suggestions.

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);
}
}

EDIT: Specify question more precisely.

michal.kreuzman
  • 12,170
  • 10
  • 58
  • 70

9 Answers9

7

You could use the builder pattern.

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, ...);
  }
}

You can then use it like this:

Person p = new PersonBuilder.firstName("Foo").build();

At first sight it might look more complex than a simple constructor with tons of parameters (and it probably is), but there are a few significant advantages:

  • You don't need to specify values that you want to keep at the default values
  • You can extend the Person class and the builder without having to declare multiple constructors or needing to rewrite every code that creates a Person: simply add methods to the builder, if someone doesn't call them, it doesn't matter.
  • You could pass around the builder object to allow different pieces of code to set different parameters of the Person.
  • You can use the builder to create multiple similar Person objects, which can be useful for unit tests, for example:

    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));
    
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • This still requires the same long list of constructor parameters the OP wanted to avoid in the first place. Just now with a lot of extra boilerplate code on top of it. – Péter Török Feb 25 '11 at 10:21
  • @Péter: not exactly. This way he can simply leave out any parameters that he doesn't want to set. Also, it has the added advantage that he can add new properties to `Person` without modifying every code constructing it (or creating tons of different constructors). Another advantage is that you can pass the `Builder` object around to different pieces of code that fill different areas (one filling in the address, one filling in the name, ...). – Joachim Sauer Feb 25 '11 at 10:24
  • @Péter: No, the builder has no args since you use `setters` to fill its fields and the class consturctor will only have one parameter: the builder. – Nicolas Feb 25 '11 at 10:25
  • @Nicolas, please check out what happens in the `build()` method in the code sample above. – Péter Török Feb 25 '11 at 10:28
  • @Joachim, OK, these are valid advantages (even though not all of them are necessarily directly useful for the OP). – Péter Török Feb 25 '11 at 10:29
  • @Péter: Arg, I've not seen how the build method work. This version of the builder pattenr is not efficient. You'd better provide a consturctor `Person(PersonBuilder builder)`signature. Downvote? – Nicolas Feb 25 '11 at 10:46
  • 1
    @Nicolas: I don't really like it if the constructed class needs knowledge of the builder class. But how exactly is that "not efficient"? – Joachim Sauer Feb 25 '11 at 10:51
  • Not efficient relatively to the original issue: avoid to expose a constructor with a lot of parameters. – Nicolas Feb 25 '11 at 10:53
  • @Nicolas: I was under the impression that the problem was more in calling the constructor and having to specify all the parameters all the time. This solution solves that. It does *not* solve the "having to declare the huge argument list once" problem, that's true. – Joachim Sauer Feb 25 '11 at 10:59
  • @Joachim, yeah, the OP was unclear on this, that's also why I commented originally. But I tend to think now your interpretation is correct. – Péter Török Feb 25 '11 at 11:14
  • Yeah I was pretty unclear of this. My point is not expose constructor with a lot of args to rest of application. So when builder takes care of building immutable object I'm far pleased with this solution. Thanks all for discuss it. – michal.kreuzman Feb 25 '11 at 11:22
  • @Joachim Sauer,i dont see the usage of immutable concepts in Builder pattern(wikipedia site),in the above site suggested could you highlight where immutable concept is used and clarify the same with the same example used in the site.will apreciate if you could highlight the lines where immutability is used. – Deepak Feb 25 '11 at 12:14
  • 2
    @Deepak: nowhere in my example is immutability used. My example is there to **enable** immutability in the `Person` class (or to be precise: to enable immutability in the `Person` class while still keeping construction of a `Person` object sane). – Joachim Sauer Feb 25 '11 at 12:20
  • @Joachim Sauer,im not able to digest the fact that builder pattern is related to Immutability.the OP is asking about Immutability.How can a builder Pattern be an example for Immutable Java bean class – Deepak Feb 25 '11 at 14:12
  • 2
    @Deepak: again: **the builder is not an example of an immutable class.** The OP was asking how he could have an immutable `Person` class without having to deal with the pain of having a huge constructor argument list to fill each time. The builder is a solution to **that specific problem**. – Joachim Sauer Feb 25 '11 at 14:50
  • @Deepak: I've found for you an [article](http://java.dzone.com/articles/immutability-with-builder-design-pattern?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+javalobby/frontpage+%28Javalobby+/+Java+Zone%29) about this solution where full example of this is. For me Joachim answer strokes me with solution - I did not use builder pattern for this kind of specific problem before. – michal.kreuzman Feb 25 '11 at 15:18
2

You should have a look at the builder pattern.

Community
  • 1
  • 1
Nicolas
  • 24,509
  • 5
  • 60
  • 66
2

One good solution is to make your fields final, add your constructor private and make use of Builders in your code. In our project we combined the Builder pattern with a validation framework so that once an object is created we are sure it's immutable and valid.

Here is a quick example:

public class Person {

public static class Builder {

    private String firstName;
    private String lastName;
    private final List<String> addresses = new ArrayList<String>();
    private final List<String> phones = new ArrayList<String>();

    public Person create() {
        return new Person(firstName, lastName, addresses, phones);
    }

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

    public Builder setLastName(String lastName) {
        this.lastName = lastName;
        return this;
    }

    public Builder addAddresse(String adr) {
        if (adr != null) {
            addresses.add(adr);
        }
        return this;
    }

    public Builder addPhone(String phone) {
        if (phone != null) {
            phones.add(phone);
        }
        return this;
    }
}

// ************************ end of static declarations **********************

private final String firstName;
private final String lastName;
private final List<String> addresses;
private final List<String> phones;

private Person(String firstName, String lastName, List<String> addresses, List<String> phones) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.addresses = addresses;
    this.phones = phones;
}

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

public String getFirstName() {
    return firstName;
}

public String getLastName() {
    return lastName;
}

public List<String> getPhones() {
    return Collections.unmodifiableList(phones);
}
}

In my example you can see that all the setters in the Builder return the Builder instance so that you can easily chain the setters calls. That's pretty useful.

You could take a look at the Builder pattern presented by Joshua Bloch.

As I said before, combined with a validation framework (see for ex. http://www.hibernate.org/subprojects/validator.html) this is really powerfull.

reef
  • 1,813
  • 2
  • 23
  • 36
  • This still requires the same long list of constructor parameters the OP wanted to avoid in the first place. Just now with a lot of extra boilerplate code on top of it. – Péter Török Feb 25 '11 at 10:23
  • @Péter Török: true but it's the Builder that now calls the constructor and not the user anymore. – reef Feb 25 '11 at 10:25
2

With interfaces. Do this:

public interface Person {
    String getFirstName();
    String getLastName();

    // [...]
}

And your implementation:

// PersonImpl is package private, in the same package as the Factory
class PersonImpl {

    String getFirstName();
    void setFirstName(String s);
    String getLastName();
    void setLastName(String s);

    // [...]
}

// The factory is the only authority to create PersonImpl
public class Factory {

    public static Person createPerson() {
        PersonImpl result = new PersonImpl();

        // [ do initialisation here ]

        return result;
    }
}

And never expose the implementation to the places where you want Person to be immutable.

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • Does that ensure immutability ? The creating entity (for example) could still hold a reference to this bean via another interface and change it – Brian Agnew Feb 25 '11 at 10:27
  • You can never entirely ensure immutability in Java. Even String is mutable: http://stackoverflow.com/questions/2481862/how-to-limit-setaccessible-to-only-legitimate-uses. This solution is just a means to design classes in a *somewhat* immutable way. But you're right. I forgot to mention the factory pattern – Lukas Eder Feb 25 '11 at 10:31
1

Initializing in the constructor is nevertheless the simplest and safest way to achieve immutability, as this is the only way to have final fields in your immutable class (which is the standard idiom, and has beneficial effects especially if your class is used in a multithreaded environment). If you have lots of properties in your class, it may be a sign that it is trying to do too much. Consider dividing it to smaller classes, or extracting groups of related properties into compound property classes.

Using a Builder (with a private constructor) is a possibility, however it still needs a way to set the properties of the object being built. So you fall back to the original dilemma of constructor parameters vs accessing the private members. In the latter case you can't declare the properties of the object being built as final, which IMHO is a great minus. And in the former case you still have the same long list of constructor parameters you wanted to avoid in the first place. Just now with a lot of extra boilerplate code on top of it.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
0

Use final fields for all your instance variables. You can create a constructor if you like and choose to not expose setters, e.g.,

public class Person {
   private final String firstName;
   ....

   public Person(String firstName, ... ) {
       this.firstName = firstName;
   }
}
Johan Sjöberg
  • 47,929
  • 21
  • 130
  • 148
0

You can achieve an "immutable" bean by making a read-only interface and then making the implementation into a mutable bean. Passing around the interface won't allow for mutation, but when you construct the object and have the implementation, you can do all sorts of bean-y things:

public interface Person {
   String getFirstName();
   String getLastName();
   // ... other immutable methods ...
}

public class MutablePerson implements Person {
   // ... mutable functions, state goes here ...
}
Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
0

Use the factory-pattern:

  • let Person be an interface with only "get"-functions
  • create a PersonFactory with an appropriate API for building a Person-object
  • the PersonFactory creates an object which implements the Person-interface and returns this
Rolf Rander
  • 3,221
  • 20
  • 21
0
  1. Have final fields.
  2. Make the class as "final" class by declaring as final public class Person
  3. do not use setXXX() methods to set the value since it will change the state of a variable. however getXXX() methods are allowed.
  4. Use a private constructor so that you can set fields using the constructor itself.

Follow the above guidelines for Immutable class.

Deepak
  • 2,094
  • 8
  • 35
  • 48