Week 21 — What is the builder pattern in java and how does it work?
Question of the Week #21
What is the builder pattern in java and how does it work?
6 Replies
Builder pattern allow to create readable object and put into constructor values. Also is good to build mock object for unit test where can build object with specify requirements.
Submission from Seba1908#8447
builder pattern is a way to create objects. The most often used to create objects with many fields.
If we want create biulder we have to create static class in our class or we create another class. We always implemented:
* builder methods which look like setters but them give opportunity to trigger after dot another builder method.
* method which build object based on values from builder methods
example with static inner class
public class Weapon {
private String type;
private String name;
private Integer damage;
private Long durability;
private List<String> perks;
private Weapon(final String type, final String name, final Integer damage, final Long durability, final List<String> perks) {
this.type = type;
this.name = name;
this.damage = damage;
this.durability = durability;
this.perks = perks;
}
public String getType() {
return type;
}
public void setType(final String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public Integer getDamage() {
return damage;
}
public void setDamage(final Integer damage) {
this.damage = damage;
}
public Long getDurability() {
return durability;
}
public void setDurability(final Long durability) {
this.durability = durability;
}
public List<String> getPerks() {
return perks;
}
public void setPerks(final List<String> perks) {
this.perks = perks;
}
public static class Builder {
private String type;
private String name;
private Integer damage;
private Long durability;
private List<String> perks = new ArrayList<>();
// builders methods
public Builder withType(final String type) {
this.type = type;
return this;
}
public Builder withName(final String name) {
this.name = name;
return this;
}
public Builder withDamage(final Integer damage) {
this.damage = damage;
return this;
}
public Builder withDurability(final Long durability) {
this.durability = durability;
return this;
}
public Builder withPerks(final List<String> perks) {
this.perks = perks;
return this;
}
// method build aimed object
public Weapon build() {
return new Weapon(type, name, damage, durability, perks);
}
}
}
Submission from Piotr Łyszkowski#0456
The builder pattern is making a static nested Builder class that handles the initialization of all necessary instance variables of the class the Builder is nested in. There is a method in the Builder class for each required instance variable of the outer class, all the methods (except the build method, which returns a new instance of the OuterClass with only the Builder as a parameter in its constructor) return a Builder object (basically the Builder returns itself after setting the instance variable). Here is an example:
The builder is used mainly for larger objects with more variables.
⭐ Submission from nikcho-kouhai#8153
If a class has many fields that have to be initialized in the constructor, maintaining that class can be tedious.
For example, imagine the following class representing a person:
When an instance of this class is created, one needs to specify all of the attributes listed in the constructor, even if some of them are not required:
If the class has many fields, this becomes difficult to read as it might not be clear which argument corresponds to which parameter/field (most IDEs like Eclipse or IntelliJ can provide that information in visual indicators but readability of code should not be dependent on IDEs).
Furthermore, it is possible that bugs slip through if the fields are ordered incorrectly.
A builder allows to construct objects of a certain class by calling methods for different arguments.
For each field, the builder provides a "fluent setter" which accepts the new/future value for that field and returns the instance of the builder.
Returning the current instance/
this
object allows for chaining.
With that builder, it is possible to instantiate classes as follows:
Creating objects like that is often more readable with many fields of similar types and allows to omit some optional fields
This is especially useful for immutable data classes (e.g. records) with many optional fields (where object creation commonly uses default values for some fields)
It is also possible to create builders automatically using annotation processors but that approach makes the build process more complicated and is hard to debug if it goes wrong.
Submission from dan1st#7327