Създаване на Java Builder за клас в IntelliJ

1. Въведение

Дизайнът на Builder е един от най-често използваните творчески модели. Помага ни да конструираме сложни обекти.

Писането на строители на ръка е тромаво и предразполага към грешки. Затова трябва да използваме специални инструменти, за да ги генерираме автоматично, когато е възможно.

В този урок ще проучим различни начини за автоматично създаване на класове на конструктори в IntelliJ IDE. Ще разгледаме вградените функции, които IntelliJ предоставя от кутията, както и приставките на трети страни.

2. Първоначална настройка

В цялата статия ще използваме версия 2019.1.3 на изданието на IntelliJ IDEA Community, което е най-новата версия по време на писането. Всички техники, представени в примерите, обаче трябва да работят добре и с всяка друга версия на IDEA.

Нека започнем с дефинирането на класа Book, за който ще генерираме конструктор:

public class Book { private String title; private Author author; private LocalDate publishDate; private int pageCount; // standard constructor(s), getters and setters }

3. Използване на вградената функционалност на IntelliJ

За да генерираме конструктор за класа Book, използвайки вградените инструменти на IntelliJ, се нуждаем от подходящ конструктор.

Нека създадем такъв:

public Book(String title, Author author, LocalDate publishDate, int pageCount) { this.title = title; this.author = author; this.publishDate = publishDate; this.pageCount = pageCount; }

Сега сме готови да създадем конструктор. Следователно, нека поставим курсора върху създадения конструктор и отворим изскачащия прозорец Refactor чрез натискане на Ctrl + Alt + Shift + T (на компютър) и изберете Replace Constructor с Builder refactoring:

По-нататък можем да коригираме някои от опциите за класа на конструктора, като неговото име и целевия пакет:

В резултат на това генерирахме класа на BookBuilder :

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. Префикс на персонализирани сетери

Често срещана практика е да се използва с префикс за методи за задаване в класове на конструктор.

За да променим префикса по подразбиране, трябва да изберем иконата Rename Setters Prefix в горния десен ъгъл на прозореца с опции :

3.2. Статичен вътрешен конструктор

Някои от нас може да предпочетат да внедрят строители като статични вътрешни класове, както е описано от Joshua Bloch в Effective Java .

Ако случаят е такъв, трябва да предприемем няколко допълнителни стъпки, за да постигнем това, като използваме функцията Replace Constructor на IntelliJ с Builder .

На първо място, трябва ръчно да създадем празен вътрешен клас и да направим конструктора частен:

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 }

Освен това трябва да изберем Използвай съществуващия в прозореца с опции и да посочим нашия новосъздаден клас:

4. Използване на приставка InnerBuilder

Нека сега видим как можем да генерираме конструктор за класа Book, използвайки приставката InnerBuilder.

След като инсталираме приставката, можем да отворим изскачащия прозорец Генериране , като натиснете Alt + Insert (на компютър) и изберете опцията Builder ... :

Като алтернатива можем да извикаме приставката InnerBuilder директно чрез натискане на Alt + Shift + B (на компютър):

Както виждаме, има няколко опции, от които можем да избираме, за да персонализираме генерирания конструктор.

Нека видим конструктора, генериран, когато всички опции са отметнати:

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); } }

Приставката InnerBuilder по подразбиране изпълнява конструктори като статични вътрешни класове.

5. Използване на плъгин Builder Generator

И накрая, нека видим как работи Builder Generator.

По същия начин, както за InnerBuilder, можем да натиснем Alt + Insert (на компютър) и да изберем опцията Builder или да използваме Alt + Shift + B пряк път.

Както виждаме, имаме три възможности за избор за персонализиране на BookBuilder :

Нека оставим всички опции непроверени и да видим генерирания клас на строител:

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; } }

Първата опция, която плъгинът на Builder Generator предлага за персонализиране на създадения клас на builder - Inner builder - е по-скоро обяснителна.

Две други обаче са по-интересни и ще ги разгледаме в следващите раздели.

5.1. 'но' Вариант на метода

Ако изберем тази опция, приставката ще добави метод but () към класа BookBuilder :

public BookBuilder but() { return aBook().withTitle(title).withAuthor(author) .withPublishDate(publishDate).withPageCount(pageCount); }

Now, let's imagine we want to create three books with the same author and the same number of pages but with different titles and publish dates. 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.

Let's take a look at an example:

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 a Single Field Option

If we choose this option, the generated builder will hold a reference to the created Book object instead of all the book's properties:

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; } }

This is a bit different approach to create a builder class that might come in handy in certain situations.

6. Conclusion

In this tutorial, we've explored different ways to generate builder classes in IntelliJ.

Обикновено е по-добре да използвате тези видове инструменти за автоматично генериране на нашите строители . Всяка от представените от нас опции има своите плюсове и минуси. Кой подход всъщност избираме е по-скоро въпрос на вкус и индивидуални предпочитания.