Construindo objetos através de Builders

Tempo de leitura: menos de 1 minuto

lego

E aí pessoal, como vão as boas práticas de desenvolvimento?
Quando comecei a programar Java, um professor me disse que um objeto bem construído deveria ter todos atributos obrigatórios inicializados pelo construtor da classe.

Então vejamos, imagine que tenhamos a seguinte classe:

[code language=”java”]
public class Pessoa {
private String cpf;
private Integer idade;
private String nome;
private String orgaoEmissor;
private String rg;
private String tituloEleitor;
}
[/code]

Se seguirmos a orientação do meu professor, teríamos que ter um construtor na classe que inicializasse todos os atributos de uma única vez. Seria algo assim:

[code language=”java”]
public Pessoa(final String pNome,
final Integer pIdade,
final String pRg,
final String pOrgaoEmissor,
final String pCpf,
final String pTituloEleitor) {
     nome = pNome;
     idade = pIdade;
     rg = pRg;
     orgaoEmissor = pOrgaoEmissor;
     cpf = pCpf;
     tituloEleitor = pTituloEleitor;
}
[/code]

Agora, imagina você precisando instanciar essa classe, são 6 parâmetros que você vai precisar passar na inicialização, além disso, você precisará saber a ordem certas dos parâmetros, já que 5 parâmetros são do tipo String. Caso você confunda e passe o CPF no lugar do RG, isso vai fazer com que seu objeto gere resultados incoerentes.

Uma forma de minimizar esse problema é usar um design pattern chamado Builder. Esse pattern tem por objetivo, auxilar na construção de um objeto com muitos parâmetros, como nosso exemplo.

Vejamos como ficaria a classe do nosso exemplo usando esse pattern:

[code language=”java”]
public class Pessoa{
private String nome;
private Integer idade;
private String rg;
private String orgaoEmissor;
private String cpf;
private String tituloEleitor;

public Pessoa(final PessoaBuilder pBuilder) {
nome = pBuilder.nome;
idade = pBuilder.idade;
rg = pBuilder.rg;
orgaoEmissor = pBuilder.orgaoEmissor;
cpf = pBuilder.cpf;
tituloEleitor = pBuilder.tituloEleitor;
}

public static class PessoaBuilder {
private String nome;
private Integer idade;
private String rg;
private String orgaoEmissor;
private String cpf;
private String tituloEleitor;

public PessoaBuilder(final String pNome) {
nome = pNome;
}

public PessoaBuilder idade(final Integer pIdade) {
idade = pIdade;
return this;
}

public PessoaBuilder rg(final String pRg) {
rg = pRg;
return this;
}

public PessoaBuilder orgaoEmissor(
final String pOrgaoEmissor) {
orgaoEmissor = pOrgaoEmissor;
return this;
}

public PessoaBuilder cpf(final String pCpf) {
cpf = pCpf;
return this;
}

public PessoaBuilder tituloEleitor(
final String pTituloEleitor) {
tituloEleitor = pTituloEleitor;
return this;
}

public Pessoa build() {
return new Pessoa(this);
}
}
}
[/code]

O exemplo é extenso, né? Mas não é nenhum bicho de sete cabeças.
Não existe maneira certa de criar um builder, nesse exemplo, o builder foi criado como uma inner class em Pessoal, mas nada impede a separação em classes distintas.

Cada método exerce a função de um setter, acumulando os valores no builder. Quando o método build é chamado, aí sim o objeto Pessoa é criado.

Vejamos se agora ficou mais fácil instanciar Pessoa:

[code language=”java”]
public Pessoa getPessoa() {
return Pessoa.criarPessoa("Eder")
.idade(32)
.cpf("012.345.678-90")
.rg("12.345.456-9")
.orgaoEmissor("SSP/SP")
.tituloEleitor("1234567890")
.build();
}
[/code]

O que fizemos aqui, foi complicar um pouquinho a classe, escrevendo mais código, mas facilitamos imensamente o uso.

Vantagens:

  • Não precisamos mais saber a ordem dos campos na inicialização;
  • Não há necessidade de preencher todos os campos, de qualquer forma, conseguimos garantir que o objeto estará sempre em estado válido;
  • A forma de uso fica muito mais intuitiva.

Outros exemplos:

[code language=”java”]
Response.created(createdUri).build();
Response.ok(f, mt).build();
Response.status(Responses.NOT_FOUND).entity(message)
.type("text/plain").build();
[/code]

Até mais pessoal!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *