Criando o Java Builder para uma classe no IntelliJ
1. Introdução
OBuilder design pattern é um dos padrões de criação mais amplamente usados. Isso nos ajuda a construir objetos complexos.
Escrever construtores à mão é complicado e sujeito a erros. Portanto, devemos usar ferramentas dedicadas para gerá-los automaticamente sempre que possível.
Neste tutorial, exploraremos diferentes maneiras de criar classes construtoras automaticamente no IDEIntelliJ. Vamos dar uma olhada nos recursos integrados que o IntelliJ oferece fora da caixa, bem como nos plug-ins de terceiros.
2. Configuração inicial
Ao longo deste artigo, usaremos a versão 2019.1.3 da edição da comunidade IntelliJ IDEA, que é a versão mais recente no momento da escrita. However, all the techniques presented in the examples should work fine with any other version of IDEA as well.
Vamos começar definindo a classeBook para a qual geraremos um construtor:
public class Book {
private String title;
private Author author;
private LocalDate publishDate;
private int pageCount;
// standard constructor(s), getters and setters
}
3. Usando a funcionalidade integrada do IntelliJ
Para gerar um construtor para a classeBook usando as ferramentas integradas do IntelliJ, precisamos de um construtor apropriado.
Vamos criar um:
public Book(String title, Author author, LocalDate publishDate, int pageCount) {
this.title = title;
this.author = author;
this.publishDate = publishDate;
this.pageCount = pageCount;
}
Agora, estamos prontos para criar um construtor. Portanto, vamos colocar o cursor no construtor criado e abrir o pop-upRefactor This pressionandoCtrl+Alt+Shift+T (no PC) e selecionarReplace Constructor with Builder refatoração:
Podemos ajustar ainda mais algumas opções da classe construtora, como nome e pacote de destino:
Como resultado, geramos a classeBookBuilder:
public class BookBuilder {
private String title;
private Author author;
private LocalDate publishDate;
private int pageCount;
public BookBuilder setTitle(String title) {
this.title = title;
return this;
}
public BookBuilder setAuthor(Author author) {
this.author = author;
return this;
}
public BookBuilder setPublishDate(LocalDate publishDate) {
this.publishDate = publishDate;
return this;
}
public BookBuilder setPageCount(int pageCount) {
this.pageCount = pageCount;
return this;
}
public Book createBook() {
return new Book(title, author, publishDate, pageCount);
}
}
3.1. Prefixo de setters personalizados
É uma prática comum usar um prefixowith para métodos setter em classes builder.
To change the default prefix, we need to choose the Rename Setters Prefix icon in the upper right corner of the options window:
3.2. Construtor interno estático
Some of us may prefer to implement builders as static inner classes as described by Joshua Bloch in Effective Java.
Se for esse o caso, precisamos realizar algumas etapas extras para conseguir isso usando o recursoReplace Constructor with Builder do IntelliJ.
Primeiro de tudo, precisamos criar manualmente uma classe interna vazia e tornar o construtor privado:
public class Book {
private String title;
private Author author;
private LocalDate publishDate;
private int pageCount;
public static class Builder {
}
private Book(String title, Author author, LocalDate publishDate, int pageCount) {
this.title = title;
this.author = author;
this.publishDate = publishDate;
this.pageCount = pageCount;
}
// standard getters and setters
}
Além disso, temos que escolherUse existing na janela de opções e apontar para nossa classe recém-criada:
4. Usando o plug-in InnerBuilder
Vamos agora ver como podemos gerar um construtor para a classeBook usando o pluginInnerBuilder.
Depois de instalar o plugin, podemos abrir o pop-upGenerate pressionandoAlt+Insert (no PC) e escolhendo a opçãoBuilder…:
Alternativamente, podemos chamar o plugin InnerBuilder diretamente pressionandoAlt+Shift+B (no PC):
Como vemos, existem algumas opções que podemos escolher para personalizar o construtor gerado.
Vamos ver o construtor gerado quando todas as opções estão desmarcadas:
public static final class Builder {
private String title;
private Author author;
private LocalDate publishDate;
private int pageCount;
public Builder() {
}
public Builder title(String val) {
title = val;
return this;
}
public Builder author(Author val) {
author = val;
return this;
}
public Builder publishDate(LocalDate val) {
publishDate = val;
return this;
}
public Builder pageCount(int val) {
pageCount = val;
return this;
}
public Book build() {
return new Book(this);
}
}
O plugin InnerBuilder implementa construtores como classes internas estáticas por padrão.
5. Usando o plug-in Builder Generator
Finalmente, vamos ver comoBuilder Generator funciona.
Da mesma forma, como no InnerBuilder, podemos pressionarAlt+Insert (no PC) e escolher a opçãoBuilder ou usar o atalhoAlt+Shift+B.
Como podemos ver, temos três opções de escolha para personalizar oBookBuilder:
Vamos deixar todas as opções desmarcadas e ver a classe builder gerada:
public final class BookBuilder {
private String title;
private Author author;
private LocalDate publishDate;
private int pageCount;
private BookBuilder() {
}
public static BookBuilder aBook() {
return new BookBuilder();
}
public BookBuilder withTitle(String title) {
this.title = title;
return this;
}
public BookBuilder withAuthor(Author author) {
this.author = author;
return this;
}
public BookBuilder withPublishDate(LocalDate publishDate) {
this.publishDate = publishDate;
return this;
}
public BookBuilder withPageCount(int pageCount) {
this.pageCount = pageCount;
return this;
}
public Book build() {
Book book = new Book();
book.setTitle(title);
book.setAuthor(author);
book.setPublishDate(publishDate);
book.setPageCount(pageCount);
return book;
}
}
A primeira opção que o plugin Builder Generator fornece para personalizar a classe builder criada -Inner builder – é bastante autoexplicativa.
Dois outros, no entanto, são mais interessantes e vamos explorá-los nas seções a seguir.
5.1. Método ‘but 'Option
Se escolhermos esta opção, o plugin adicionará um métodobut() à classeBookBuilder:
public BookBuilder but() {
return aBook().withTitle(title).withAuthor(author)
.withPublishDate(publishDate).withPageCount(pageCount);
}
Agora, vamos imaginar que queremos criar três livros com o mesmo autor e o mesmo número de páginas, mas com títulos e datas de publicação diferentes. We may create a base builder with common properties already set and then use the but() method to create new BookBuilders (and Books later on) out of it.
Vamos dar uma olhada em um exemplo:
BookBuilder commonBuilder = BookBuilder.aBook().withAuthor(johnDoe).withPageCount(123);
Book my_first_book = commonBuilder.but()
.withPublishDate(LocalDate.of(2017, 12, 1))
.withTitle("My First Book").build();
Book my_second_book = commonBuilder.but()
.withPublishDate(LocalDate.of(2018, 12, 1))
.withTitle("My Second Book").build();
Book my_last_book = commonBuilder.but()
.withPublishDate(LocalDate.of(2019, 12, 1))
.withTitle("My Last Book").build();
5.2. Use uma opção de campo único
Se escolhermos esta opção, o construtor gerado manterá uma referência ao objetoBook criado em vez de todas as propriedades do livro:
public final class BookBuilder {
private Book book;
private BookBuilder() {
book = new Book();
}
public static BookBuilder aBook() {
return new BookBuilder();
}
public BookBuilder withTitle(String title) {
book.setTitle(title);
return this;
}
public BookBuilder withAuthor(Author author) {
book.setAuthor(author);
return this;
}
public BookBuilder withPublishDate(LocalDate publishDate) {
book.setPublishDate(publishDate);
return this;
}
public BookBuilder withPageCount(int pageCount) {
book.setPageCount(pageCount);
return this;
}
public Book build() {
return book;
}
}
Esta é uma abordagem um pouco diferente para criar uma classe de construtor que pode ser útil em certas situações.
6. Conclusão
Neste tutorial, exploramos diferentes maneiras de gerar classes de construtor no IntelliJ.
It’s usually better to use these kinds of tools to automatically generate our builders. Cada uma das opções que apresentamos tem seus prós e contras. Qual abordagem realmente escolhemos é uma questão de gosto e preferências individuais.