What Is The Builder Pattern?
You can skip this part if you're familiar with the Builder pattern for creating immutable objects.
The "Builder" pattern helps us, not surprisingly, to build objects. It is often used for building immutable objects. For example, let's say we have this class:
Then, if we want to split the assembly of the fields from the actual construction, we can use a builder in the following manner:
This way we have a mutable inner class StudentBuilder which gathers the fields we need for the immutable class and when the time has come to create the immutable object we just call build() and we get the immutable object already fully constructed.
So what does that have to do with clean code?
What we'll usually try to do next is something that will wrap these lines into a single line like this:
This pattern is very hard to read. You have to scroll back and forth or at least open the tooltip of the method to understand what each number says.
Using the builder pattern can help us create something that is less verbose than the original version of the code (the one with the oh so many lines) and a bit more descriptive than this one liner. We'll create a builder for StudentGrades as follows:
Now we can construct StudentGrades in a verbal, yet concise manner:
This can be read almost as an English sentence "studentGrades for user 97 with math 84...."
Don't know about you - but I really like it this way. This make me feel I read a sentence rather then trying to decrypt the meaning of a random group of numbers.
The "Builder" pattern helps us, not surprisingly, to build objects. It is often used for building immutable objects. For example, let's say we have this class:
public class Student { private final String givenName; private final String lastName; private final int averageGrade; private final int age; public Student (final String givenName, final String lastName, int averageGrade, int age) { this.givenName = givenName; this.lastName = lastName; this.averageGrade = averageGrade; this.age = age; } // Rest of the class is only getters with no setters here }
Then, if we want to split the assembly of the fields from the actual construction, we can use a builder in the following manner:
public class Student { private final String givenName; private final String lastName; private final int averageGrade; private final int age; public Student (final String givenName, final String lastName, int averageGrade, int age) { this.givenName = givenName; this.lastName = lastName; this.averageGrade = averageGrade; this.age = age; } // Rest of the class is only getters with no setters here public static class StudentBuilder { private String givenName; private String lastName; private int averageGrade; private int age; public StudentBuilder() { } public StudentBuilder withGivenName(final String givenName) { this.givenName = givenName; return this; } // The rest of the 'with' setters look the same... public Student build() { return new Student(givenName, lastName, averageGrade, age); } } }
This way we have a mutable inner class StudentBuilder which gathers the fields we need for the immutable class and when the time has come to create the immutable object we just call build() and we get the immutable object already fully constructed.
So what does that have to do with clean code?
Express Yourself With Builders
I'm sure you have seen a pattern similar to that in the past:StudentGrades grades = new StudentGrades(); grades.setStudentId(97); // The student id in the DB grades.setMath(84); grades.setEnglish(92); grades.setChemistry(75); grades.setLiteratue(88); grades.setGymnastic(55); grades.setBiology(76); grades.setHistory(81);
What we'll usually try to do next is something that will wrap these lines into a single line like this:
private StudentGrades createStudentGrades (int id, int math, int english, int chemistry, int literature, int gymnastic, int biology, int history) { StudentGrades grades = new StudentGrade(); grades.setStudentId(id); // The student id in the DB grades.setMath(math); grades.setEnglish(english); grades.setChemistry(chemistry); grades.setLiteratue(literature); grades.setGymnastic(gymnastic); grades.setBiology(biology); grades.setHistory(history); return grades; }And indeed this will make the whole clutter of code into a one-liner:
StudentGrades grades = createStudentGrades(97, 84, 92, 75, 88, 55, 76, 81);Well, this is great. Much less verbose. But without looking back on the createStudentGrades method, will you be able to tell what 75 stands for? Or 88?
This pattern is very hard to read. You have to scroll back and forth or at least open the tooltip of the method to understand what each number says.
Using the builder pattern can help us create something that is less verbose than the original version of the code (the one with the oh so many lines) and a bit more descriptive than this one liner. We'll create a builder for StudentGrades as follows:
// This doesn't have to be inner class now. It's not the immutability that we need the builder for. It's the readability public StudentGradesBuilder { int id; int math; int english; int chemistry; int literature; int gymnastic; int biology; int history; private StudentGradesBuilder() { // Making the constructor private in order to enforce construction // with the readable static construction method. } public StudentGradesBuilder studentGrades() { return new StudentGradesBuilder(); } public StudentGradesBuilder forUser(int id) { this.id = id; return this; } public StudentGradesBuilder withHistory(int history) { this.history = history; return this; } // Rest of setters public StudentGrades build() { StudentGrades grades = new StudentGrade(); grades.setStudentId(id); grades.setMath(math); grades.setEnglish(english); grades.setChemistry(chemistry); grades.setLiteratue(literature); grades.setGymnastic(gymnastic); grades.setBiology(biology); grades.setHistory(history); return grades; } }
Now we can construct StudentGrades in a verbal, yet concise manner:
// Static importing of StudentGradesBuilder.studentGrades() method // allows to call it directly which makes it readable like an English sentence StudentGrades studentGrades = studentGrades().forUser(97).withMath(84) .withEnglish(92).withChemistry(75) .withLiterature(88).withGymnastic(55) .withBiology(76).withHistory(81) .build();
This can be read almost as an English sentence "studentGrades for user 97 with math 84...."
Don't know about you - but I really like it this way. This make me feel I read a sentence rather then trying to decrypt the meaning of a random group of numbers.
Find me on Twitter: @AviEtzioni
More interesting posts from this blog: