Construtores tradicionais muitas vezes resultam em código difícil de ler e entender quando possuem múltiplos parâmetros. Construtores semânticos oferecem uma solução para este problema "nomeando" os construtores de forma descritiva e clara. Isso não apenas melhora a legibilidade, mas também facilita a manutenção do código, pois o propósito de cada instância fica claro pelo nome do método.
Quando uma classe possui múltiplos parâmetros de diferentes tipos, existe grande chance de ocorrerem construtores ambíguos e propensos a erros. Por exemplo, considere a classe VerificadorAssinaturaDigital, que realiza a verificação de uma assinatura digital contra um arquivo binário:
public class VerificadorAssinaturaDigital {
private final String nomeArquivoConteudo;
private final byte[] binarioArquivoConteudoAssinado;
private final String nomeArquivoAssinatura;
private final byte[] binarioArquivoAssinatura;
public VerificadorAssinaturaDigital(final String nomeArquivoConteudo, final byte[] binarioArquivoConteudoAssinado, final String nomeArquivoAssinatura, final byte[] binarioArquivoAssinatura) {
this.nomeArquivoConteudo = nomeArquivoConteudo;
this.binarioArquivoConteudoAssinado = binarioArquivoConteudoAssinado;
this.nomeArquivoAssinatura = nomeArquivoAssinatura;
this.binarioArquivoAssinatura = binarioArquivoAssinatura;
}
public VerificadorAssinaturaDigital(final String nomeArquivoConteudo, final byte[] binarioArquivoConteudoAssinado) {
this.nomeArquivoConteudo = nomeArquivoConteudo;
this.binarioArquivoConteudoAssinado = binarioArquivoConteudoAssinado;
}
}
Ao instanciar a classe VerificadorAssinaturaDigital, pode ser difícil lembrar a ordem e o propósito de cada parâmetro, especialmente em projetos maiores ou quando a classe tem muitos parâmetros:
VerificadorAssinaturaDigital verificador = new VerificadorAssinaturaDigital("documento", binarioDocumentoConteudoAssinado, "arquivoAssinaturaDocumento", binarioArquivoAssinatura);
Aqui, não é imediatamente óbvio quais são os valores passados ou seu propósito. Este problema é amplificado à medida que o número de parâmetros aumenta, potencialmente levando a erros e dificultando a leitura do código.
Métodos de Fábrica Estáticos
"Métodos de fábrica estáticos, como descrito por Joshua Bloch em seu livro Effective Java, possuem nomes ao contrário dos construtores tradicionais." Esta técnica consiste em tornar o construtor privado e utilizar métodos estáticos para retornar uma nova instância do objeto, mas com nomes descritivos que indicam objetivamente a finalidade da criação. Por exemplo, na classe VerificadorAssinaturaDigital, poderíamos definir métodos de fábrica assim:
public class VerificadorAssinaturaDigital {
private final String nomeArquivoConteudo;
private final byte[] binarioArquivoConteudoAssinado;
private final String nomeArquivoAssinatura;
private final byte[] binarioArquivoAssinatura;
private VerificadorAssinaturaDigital(final String nomeArquivoConteudo, final byte[] binarioArquivoConteudoAssinado, final String nomeArquivoAssinatura, final byte[] binarioArquivoAssinatura) {
this.nomeArquivoConteudo = nomeArquivoConteudo;
this.binarioArquivoConteudoAssinado = binarioArquivoConteudoAssinado;
this.nomeArquivoAssinatura = nomeArquivoAssinatura;
this.binarioArquivoAssinatura = binarioArquivoAssinatura;
}
// assinatura embutida no próprio arquivo
public static VerificadorAssinaturaDigital criarParaAssinaturaPdf(final String nomeArquivoConteudo, final byte[] binarioArquivoConteudoAssinado) {
return new VerificadorAssinaturaDigital(nomeArquivoConteudo, binarioArquivoConteudoAssinado);
}
// assinatura separada do arquivo assinado
public static VerificadorAssinaturaDigital criarParaAssinaturaCms(final String nomeArquivoConteudo, final byte[] binarioArquivoConteudoAssinado, final String nomeArquivoAssinatura, final byte[] binarioArquivoAssinatura) {
return new VerificadorAssinaturaDigital(nomeArquivoConteudo, binarioArquivoConteudoAssinado, nomeArquivoAssinatura, binarioArquivoAssinatura);
}
}
Uma vez que é possível "nomear" os construtores, tornando-os semânticos, ao bater o olho no nome do método é possível saber para qual propósito aquele objeto será construído:
VerificadorAssinaturaDigital verificador = VerificadorAssinaturaDigital.criarParaAssinaturaPdf("documento", binarioDocumentoConteudoAssinado);
VerificadorAssinaturaDigital verificador = VerificadorAssinaturaDigital.criarParaAssinaturaCms("documento", binarioDocumentoConteudoAssinado, "arquivoAssinaturaDocumento", binarioArquivoAssinatura);
Benefícios dos Construtores Semânticos
Os construtores semânticos oferecem várias vantagens significativas em comparação com os construtores tradicionais:
- Legibilidade: Os métodos de fábrica estáticos têm nomes descritivos que tornam o código mais fácil de ler e entender.
- Manutenção: Facilita a manutenção, pois os métodos nomeados explicitamente deixam claro o propósito de cada instância, reduzindo a chance de erros.
- Flexibilidade: Permite adicionar novos métodos de fábrica sem alterar o construtor original, promovendo a extensibilidade do código.
- Clareza: A utilização de métodos de fábrica elimina a ambiguidade sobre quais parâmetros estão sendo passados, especialmente em classes com muitos atributos.
Conclusão
Construtores semânticos proporcionam uma maneira mais legível e intuitiva de criar objetos. Utilizando métodos de fábrica estáticos com nomes descritivos, esses construtores melhoram significativamente a clareza e a manutenção do código. Eles facilitam a leitura, reduzem a ambiguidade e diminuem a chance de erros. Além disso, promovem a flexibilidade na adição de novos métodos de criação sem modificar o construtor original.
Referências
- Bloch, Joshua. Effective Java. 3ª edição, Addison-Wesley Professional, 2018
Top comments (0)