Design Patterns in Android — Builder
Design patterns are reusable solutions to the most commonly occurring software problems. They can speed up the development process by providing a proven way of resolving frequent issues.
In this series of articles, I’d like to introduce the most common design patterns with examples of Android implementations in practice.
Introduction
Design patterns can be divided into the three sections:
- Creational Design Patterns deliver solutions for creating classes, objects (Singleton, Factory, Builder, etc.)
- Structural Design Patterns are about arrangement of classes and objects (e.g. Composite, Facade, Adapter)
- Behavioral Design Patterns give us ways to communicate between objects and classes (Command, Observer, Strategy, etc.)
Builder
Builder pattern simplifies object creation in very clean and readable way. It’s very helpful when we have some model classes with many parameters. We can make some of them optional or required, and we don’t force the user to use specific order (as in the constructor). By using Builder pattern we result with the elegant chain of the methods. The most common use is in AlertDialog.Builder()
class:
new AlertDialog.Builder(this)
.setTitle("Design Patterns")
.setMessage("Builder is awesome")
.create();
How can we create Builder class for our own usage?
Builder in practice
Let’s assume we have some model class for the user:
public class User {
private String firstName;
private String lastName;
private int age;
}
And instead of creating objects of this class using constructors, we want to create them using Builder pattern like this:
new User.Builder()
.setFirstName("Leonardo")
.setLastName("da Vinci")
.setAge(67)
.create();
How can we do that? Firstly, we need to create Builder
class inside User
class which will have the methods to build our object. The key to having chaining methods is that builder methods return Builder
class. Look at the example:
static class Builder {
private String firstName;
private String lastName;
private int age;
public Builder setFirstName(final String firstName) {
this.firstName = firstName;
return this;
}
public Builder setLastName(final String lastName) {
this.lastName = lastName;
return this;
}
public Builder setAge(final int age) {
this.age = age;
return this;
}
public User create() {
return new User(this);
}
}
For every parameter we have a setter — the difference is that those methods return Builder
type. At the end we have a method which uses constructor from User
class and returns the User
object — here is the place where our mess is kept hidden.
Then, we need to create constructor with all the parameters in model class User
:
public class User {
private String firstName;
private String lastName;
private int age;
private User(final Builder builder) {
firstName = builder.firstName;
lastName = builder.lastName;
age = builder.age;
}
}
Important thing here is that the User
constructor is private, so it can’t be accessed from the other class and we must use Builder
to create new object.
Of course, we can make some of the parameters required (as for now all are optional) by modifying our create()
method and throwing some exceptions, e.g.:
public User create() {
User user = new User(firstName, lastName, age);
if (user.firstName.isEmpty()) {
throw new IllegalStateException(
"First name can not be empty!");
}
return user;
}
That’s it. This way we created our User.Builder()
class!
Builder — protip
If you were patient enough to get through the whole blog post, I have one tip for you regarding Builder pattern: you can generate the whole Builder class using IntelliJ!
All you need to do is place the caret on the constructor in your class and choose Refactor -> Replace Constructor with Builder on the context menu. Builder class with all the methods will be auto generated, ready for use.
You can read more here: IntelliJ: Replace Constructor with Builder
Conclusion
Builder pattern is a great approach, not only for model classes but for every object which has more than three or four parameters. With a bit of additional work, we can increase the readability of our code. Design patterns are recognized as the best practice, so it’s big advantage if you know some of them and Builder is a good one to start with.
Stay tuned for more!