Design Patterns in Android – Builder

Builder

Builder pattern simplifica a criação de objectos de uma forma muito limpa e legível. É muito útil quando temos algumas classes de modelos com muitos parâmetros. Podemos fazer alguns deles opcionais ou obrigatórios, e não forçamos o usuário a usar uma ordem específica (como no construtor). Ao usarmos o padrão Builder resultamos com a elegante cadeia dos métodos. O uso mais comum é em AlertDialog.Builder() class:

new AlertDialog.Builder(this)
.setTitle("Design Patterns")
.setMessage("Builder is awesome")
.create();

Como podemos criar classe Builder para nosso próprio uso?

Builder na prática

Vamos assumir que temos alguma classe modelo para o usuário:

public class User {
private String firstName;
private String lastName;
private int age;
}

E ao invés de criar objetos desta classe usando construtores, queremos criá-los usando o padrão Builder assim:

new User.Builder()
.setFirstName("Leonardo")
.setLastName("da Vinci")
.setAge(67)
.create();

Como podemos fazer isso? Primeiro, precisamos criar Builder class inside User class which will have the methods to build our object. A chave para ter métodos em cadeia é que os métodos do construtor retornem Builder class. Veja o exemplo:

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);
}
}

Para cada parâmetro nós temos um setter – a diferença é que esses métodos retornam Builder type. No final temos um método que usa o construtor de User class e retorna o objeto User – aqui é o lugar onde nossa bagunça é mantida escondida.

Então, precisamos criar construtor com todos os parâmetros da classe model 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;
}
}

Importante aqui é que o User construtor é privado, então não pode ser acessado da outra classe e devemos usar Builder para criar um novo objeto.

Obviamente, podemos fazer alguns dos parâmetros necessários (como por enquanto todos são opcionais) modificando nosso método create() e lançando algumas exceções, por exemplo:

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;
}

É isso aí. Desta forma criamos o nosso User.Builder() class!

Builder – protip

Se você foi paciente o suficiente para passar por todo o post do blog, eu tenho uma dica para você com relação ao padrão Builder: você pode gerar toda a classe Builder usando IntelliJ!

Tudo que você precisa fazer é colocar o caret no construtor da sua classe e escolher Refactor -> Replace Constructor with Builder no menu de contexto. A classe Builder com todos os métodos será gerada automaticamente, pronta para uso.

Você pode ler mais aqui: IntelliJ: Replace Constructor with Builder

Conclusion

Builder pattern é uma ótima abordagem, não só para classes de modelos mas para cada objeto que tenha mais de três ou quatro parâmetros. Com um pouco de trabalho adicional, podemos aumentar a legibilidade do nosso código. Padrões de projeto são reconhecidos como a melhor prática, então é uma grande vantagem se você conhece alguns deles e Builder é um bom começo com.