Domanda

I very interested in the builder pattern, I use it often but I am not sure if the builders I make are good enough and also I have doubts about all the surroundings where I can use them. This is an example of how I create a builder:

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

Just a quick usage example:

Person person = new Person.Builder()
        .withName("John")
        .withSecondName("Smith")
        .withAge(50)
        .build();
        System.out.println(person);

Here some of my doubts:

  • Do you think it is really immutable?If no, How can I improve it?
  • About thread safety. Well this is probably my main doubt. Is this really thread safe? I saw examples on the internet that say that the class level variables must be final and passed via a constructor. Also I saw one example where the variables were declared as volatile. What do you think about it?
  • Do you think that this builder would have any limitation in what regards the scenario where it can be used? What I mean is would it be suitable to be called in either an EJB, a JSF backing bean, an MDB,or become a JPA entity...?
È stato utile?

Soluzione

Do you think it is really immutable? [...] Is this really thread safe?

No part of your code is immutable. This also probably hampers thread safety; that said it's really difficult to declare that a class is or isn't thread-safe in a binary fashion. I also don't see why you would ever share builder instances between threads in the first place, but I might be mislead by the simplicity of your code sample.

To make achieving thread-safety easier, your Builders should be themselves immutable. This means that every withXXX() method should return a new builder that represents the new state. (There's probably more clever ways of doing this but that would be the straightforward approach.)

Just to reiterate though: I'm not sure it's strictly necessary to make a builder thread-safe - most of the time they're objects with a very short lifetime and scope of visibility. Whether you want to make them immutable depends on the use case, you might want to store partially filled builders but that's also somewhat rare. (Subjectively it does however seem more intuitive for a method whose name starts with with to not modify an object in-place, as opposed to one whose name starts with set.)

Do you think that this builder would have any limitation in what regards the scenario where it can be used?

This is generally unanswerable, but if you do make your Person objects immutable, and thus only constructible by your builder, they'll be unusable as JPA entities, my guess is as JSF backing beans as well. Java frameworks that create/manage certain objects for you more often than not expect them to be JavaBeans, meaning that these objects can be created by calling a no-args constructor and property setters through reflection.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top