Reputation:
I'm wondering about whether my implementation of the Builder pattern is wrong or not.
Let's say we have a User
class for which we want to have a Builder
, my implementation would be:
public class User
{
private final String name;
private final int age;
private User(Builder builder)
{
this.name = builder.name;
this.age = builder.age;
}
public static class Builder
{
//blah blah
public User build()
{
return new User(this);
}
}
}
But from time to time, I see that some people add this method:
public static Builder builder()
{
return new Builder();
}
for seemingly no reason other than achieving a slightly more readable syntax:
//Before
User user = new User.Builder()
.named("Tester")
.build();
//After
User user = User.builder()
.named("Tester")
.build();
Is this the only advantage? Do I miss anything?
Upvotes: 2
Views: 78
Reputation: 7290
Regarding your initial question:
whether my implementation of the Builder pattern is wrong or not
IMHO, your code uses incorrect dependencies.
Your User
class has to know about the Builder
's internals in
private User(Builder builder)
{
this.name = builder.name;
this.age = builder.age;
}
It should be the other way round: the Builder
should know about the User
's construction requirements. The User
class should not even know that there are any builders that can help in the construction.
So, I'd refactor this to become
public class User
{
private final String name;
private final int age;
private User(String name, int age)
{
this.name = name;
this.age = age;
}
public static class Builder
{
//blah blah
public User build()
{
return new User(name, age);
}
}
}
Regarding the static builder()
method:
You always introduce classes and methods as domain-specific extensions of the Java language, allowing your vallers to write application code using that new vocabulary.
The question always is: "Does your new vocabulary make things easier for the callers of your class?"
So, how would you like to create a User
in your application-specific language? Some possibilities:
new User("Tester", 42);
This can become quite unclear in case of more than two parameters, lacks flexibility.User.withNameAndAge("Tester", 42);
This forces you to provide many similar static methods.User.builder().named("Tester").aged(42).build();
This reads as if you want to give a name to the builder, not the user.new User.Builder().named("Tester").aged(42).build();
This reads as if you want to give a name to the builder, not the user.User.named("Tester").aged(42).build();
This is nice to read, but a bit complex to implementnew User().named("Tester").aged(42);
This is nice to read, but runs the risk of incomplete initialization.Decide what you find best (regarding readability, flexibility, robustness, ...) and then implement it. For some creation styles you'll need a Builder
class, for others it might be helpful under the hood, and for others it's not necessary.
Upvotes: -3