Antes de falar do Builder especificamente, precisamos entender qual é a motivação para utilizar padrões de projetos. Provavelmente você já enfrentou um problema "cabeludo" e perdeu vários dias tentando resolvê-lo, enquanto se lamentava ao pensar que ninguém havia passado por este problema antes. Mas você estava enganado. Muito enganado. Provavelmente muitas pessoas já enfrentaram situações iguais ou muito parecidas que você já enfrentou, e algumas dessas pessoas ficaram tão frustadas quanto você ao perder horas (ou até dias) tentando resolve-las. Só que um grupo chamado GoF decidiu criar alguns padrões para resolver problemas cotidianos. Por que? Simplesmente para melhorar a vida das pessoas. Tornar o código mais limpo, mais elegante e de fácil manutenção. Quando aplicamos padrões de projeto em nosso código, estamos tornando-o muito mais profissional, e menos suscetível a erros.Geralmente é uma boa ideia a utilização dos padrões de projeto em nossos sistemas.
Mas vamos ao que interessa, que é o tal do Buider. Um código vale mais do que mil palavras, então vamos começar com o seguinte cenário:
public class Person {
private String name;
private int age;
private String adress;
private String lastName;
private String phoneNumber;
private String jobDescription;
public Person(String name, int age, String adress, String lastName,
String phoneNumber, String jobDescription) {
this.name = name;
this.age = age;
this.address = address;
this.lastName = lastName;
this.phoneNumber = phoneNumber;
this.jobDescription = jobDescription;
}
}
E nosso programa principal se pareceria com isso:public class Main {
public static void main(String[] args) {
Person p = new Person("Paul", 32, "Street one",
"MCcain","555-4444","Java Programmer");
//do something
}
}
Nossa, quantos parâmetros! Eu realmente não quero lembrar de todos esses parâmetros ao instanciar um objeto Person, são muitos! Além do mais, é difícil ter que ficar verificando a ordem correta de cada um deles. É muito fácil, por exemplo, trocar o argumento "Street one" por "MCcain", o que causaria inconsistência no objeto Person, já que teríamos configurado o endereço como sendo seu sobrenome e seu sobrenome como o endereço de sua residência.
Será que não teria uma maneira mais "intuitiva" ao construir objetos Person? Felizmente, a resposta é SIM! O pessoal do GoF também achou muito chato isso e resolveu criar o padrão Builder, que traduzindo do inglês seria um "construtor". E sim, é ele que vai nos ajudar a criar novos objetos Person. Como? Veja abaixo:
public class Person {
private final String name;
private final int age;
private final String address;
private final String lastName;
private final String phoneNumber;
private final String jobDescription;
private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.address = builder.address;
this.lastName = builder.lastName;
this.phoneNumber = builder.phoneNumber;
this.jobDescription = builder.jobDescription;
}
public static class Builder {
private String name;
private int age;
private String address;
private String lastName;
private String phoneNumber;
private String jobDescription;
//vamos exigir que o parâmetro obrigatório seja
//somente o nome da pessoa
public Builder(String name) {
this.name = name;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Builder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public Builder phoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public Builder jobDescription(String jobDescription) {
this.jobDescription = jobDescription;
return this;
}
public Person build() {
return new Person(this);
}
}
}
E nossa classe principal ficaria assim:
public class Main {
public static void main(String[] args) {
Person p = new Person.Builder("Paul")
.age(32)
.address("Street 1")
.jobDescription("Java Programmer")
.lastName("MCcain")
.phoneNumber("555-4444")
.build();
}
}
Olha que bacana. Ficou muito mais fácil e lógico instanciar um objeto Person, muito mais intuitivo, não acham? Perceba que o objeto Person é imutável neste caso. Não importa a ordem em que acessamos os parâmetros, eles sempre serão alocados da maneira correta. E lendo este código, fica muito mais fácil ver que estamos setando cada atributo individualmente, numa espécie de bind (recurso encontrado na linguagem Python, por exemplo). Por mais que tivemos que escrever mais código, o resultado final ficou muito melhor do que o primeiro exemplo. Mas daí vem a questão, vou ter que montar toda uma estrutura para resolver um problema aparentemente simples? Como usar um canhão para matar uma formiga? A questão é que seu software SEMPRE irá mudar, esteja preparado para isso. E quanto melhor estruturá-lo, menos dores de cabeça teremos ao precisar modificá-lo. Lembre-se, a única constante que temos no desenvolvimento de software é a palavra MUDANÇA. Outro fator é que provavelmente outras pessoas irão mexer em seu código, você quer mesmo que elas pensem que você não foi inteligente o suficiente por não utilizar um padrão de projeto, deixando seu código feio, sujo e difícil manutenção? É claro que não quer.
Bom, como tudo na vida é perfeito, vou listar também as desvantagens em utilizar o padrão Builder:
- Como o construtor de Person é private, a única forma de obter um Person é construir um builder antes;
- Classes com poucos atributos não justifica o uso do padrão. Mas lembre-se, mais tarde sua classe poderá mudar;
- Cuidar ao adicionar novos atributos, pois terá que adicioná-los tanto no Builder quanto na própria classe, e fazer a atribuição correta no construtor.
Tirem suas conclusões e vejam o que é melhor, não necessariamente essa é a única solução, mas é uma ótima solução caso queira "profissionalizar" seu código.
Bom, por hoje é só! Chega de Java por hoje, amanhã estarei indo para minha terra querida. Desejo à todos um ótimo feriado, pulem bastante Carnaval (mas com responsabilidade!).
Até a próxima! =)