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.