I've looked at various definitions of the builder pattern and whilst there's varying definitions, they tend to be focused on the broad definition of incremental construction. However, it seems that most of the examples of builders I've ever seen essentially just construct "value" types with method chaining.
I've found, however, that it can occasionally be more useful to use a completely different sort of model in the builder to accomplish additional tasks. So, in addition to what people generally expect from a builder, this builder:
- Can hide details of the type being created
- Embedding complex build logic into the builder
- Using the same builder to create multiple similar types
I've put together a simple example of a builder variant that I created in Java that'll hopefully better demonstrate the ideas. (Note: 1 isn't really well demonstrated since it would take a lot more code to illustrate)
class FamiliesBuilder {
final Map<String, List<String>> familyMap = new HashMap<>();
String lastName;
List<String> familyList;
FamiliesBuilder newFamily(String lastName) {
this.familyList = this.familyMap.getOrDefault(lastName, new LinkedList<>());
this.familyMap.put(lastName, this.familyList);
this.lastName = lastName;
return this;
}
FamiliesBuilder addFamilyMember(String firstName) {
this.familyList.add(firstName);
return this;
}
Map<String, List<Person>> buildLastNameLookup() {
final Map<String, List<Person>> res = new HashMap<>();
for (Entry<String, List<String>> e : this.familyMap.entrySet()) {
final String personLastName = e.getKey();
final List<Person> people = new LinkedList<>();
for (String firstName : e.getValue()) {
people.add(new Person(firstName, personLastName));
}
res.put(e.getKey(), people);
}
return res;
}
List<Person> build() {
List<Person> people = new LinkedList<>();
for (Entry<String, List<String>> e : this.familyMap.entrySet()) {
String personLastName = e.getKey();
for (String personFirstName : e.getValue()) {
people.add(new Person(personFirstName, personLastName));
}
}
return people;
}
class Person {
private String firstName;
private String lastName;
private Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
public static void main(String... args) {
// Usage example
List<Person> people = new FamiliesBuilder()
.newFamily("Doe")
.addFamilyMember("John")
.addFamilyMember("Jane")
.newFamily("Smith")
.addFamilyMember("Tom")
.build();
}
}
I'm concerned that this variant is too far from the classic builder pattern that calling it a builder may be confusing and, if so, I'm wondering if there are any recognizable design patterns or techniques that accomplish a similar task.