Erstellen des Java Builder für eine Klasse in IntelliJ

1. Einleitung

Das Builder-Entwurfsmuster ist eines der am häufigsten verwendeten Erstellungsmuster. Es hilft uns, komplexe Objekte zu konstruieren.

Das Schreiben von Buildern von Hand ist umständlich und fehleranfällig. Daher sollten wir spezielle Tools verwenden, um sie nach Möglichkeit automatisch zu generieren.

In diesem Tutorial werden verschiedene Möglichkeiten zum automatischen Erstellen von Builder-Klassen in der IntelliJ IDE untersucht. Wir werden uns die integrierten Funktionen von IntelliJ sowie die Plugins von Drittanbietern ansehen.

2. Ersteinrichtung

In diesem Artikel verwenden wir die Version 2019.1.3 der IntelliJ IDEA Community Edition, die zum Zeitpunkt des Schreibens die neueste Version ist. Alle in den Beispielen vorgestellten Techniken sollten jedoch auch mit jeder anderen Version von IDEA funktionieren.

Beginnen wir mit der Definition der Book- Klasse, für die wir einen Builder generieren:

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

3. Verwenden der integrierten Funktionalität von IntelliJ

Um mit den in IntelliJ integrierten Tools einen Builder für die Book- Klasse zu generieren , benötigen wir einen geeigneten Konstruktor.

Lassen Sie uns eine erstellen:

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

Jetzt können wir einen Builder erstellen. Setzen Sie daher den Cursor auf den erstellten Konstruktor und öffnen Sie das Popup Refactor This, indem Sie Strg + Alt + Umschalt + T (auf dem PC) drücken und Konstruktor durch Builder- Refactoring ersetzen auswählen :

Wir können einige der Optionen für die Builder-Klasse weiter anpassen, z. B. den Namen und das Zielpaket:

Als Ergebnis haben wir die BookBuilder- Klasse generiert :

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. Benutzerdefiniertes Setter-Präfix

Es ist üblich, in Builder-Klassen ein with- Präfix für Setter-Methoden zu verwenden.

Um das Standardpräfix zu ändern, müssen Sie das Symbol Setzerpräfix umbenennen in der oberen rechten Ecke des Optionsfensters auswählen :

3.2. Statischer innerer Erbauer

Einige von uns ziehen es möglicherweise vor, Builder als statische innere Klassen zu implementieren, wie von Joshua Bloch in Effective Java beschrieben .

In diesem Fall müssen wir einige zusätzliche Schritte unternehmen, um dies mithilfe der IntelliJ-Funktion " Konstruktor durch Builder ersetzen" zu erreichen .

Zunächst müssen wir manuell eine leere innere Klasse erstellen und den Konstruktor privat machen:

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 }

Außerdem müssen wir im Optionsfenster die Option Vorhandene verwenden auswählen und auf unsere neu erstellte Klasse verweisen:

4. Verwenden des InnerBuilder-Plugins

Lassen Sie uns nun sehen, wie wir mit dem InnerBuilder-Plugin einen Builder für die Book- Klasse generieren können.

Sobald wir das Plugin installiert haben, können wir das Popup " Generieren" öffnen , indem wir Alt + Einfügen (auf dem PC) drücken und die Option " Builder ..." auswählen :

Alternativ können wir das InnerBuilder-Plugin direkt aufrufen, indem wir Alt + Umschalt + B (auf dem PC) drücken :

Wie wir sehen, können wir aus einigen Optionen auswählen, um den generierten Builder anzupassen.

Sehen wir uns den Builder an, der generiert wird, wenn alle Optionen deaktiviert sind:

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

Das InnerBuilder-Plugin implementiert Builder standardmäßig als statische innere Klassen.

5. Verwenden des Builder Generator Plugins

Lassen Sie uns abschließend sehen, wie der Builder-Generator funktioniert.

Ähnlich wie bei InnerBuilder können wir entweder Alt + Einfügen (auf dem PC) drücken und die Builder- Option auswählen oder die Tastenkombination Alt + Umschalt + B verwenden .

Wie wir sehen können, stehen drei Optionen zum Anpassen des BookBuilder zur Auswahl :

Lassen Sie alle Optionen deaktiviert und sehen Sie sich die generierte Builder-Klasse an:

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

Die erste Option, die das Builder Generator-Plugin zum Anpassen der erstellten Builder-Klasse bietet - Inner Builder - ist ziemlich selbsterklärend.

Zwei andere sind jedoch interessanter, und wir werden sie in den folgenden Abschnitten untersuchen.

5.1. 'aber' Methodenoption

Wenn wir diese Option wählen, fügt das Plugin der BookBuilder- Klasse eine but () -Methode hinzu :

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.

Es ist normalerweise besser, diese Art von Tools zu verwenden, um unsere Builder automatisch zu generieren . Jede der von uns vorgestellten Optionen hat ihre Vor- und Nachteile. Welchen Ansatz wir tatsächlich wählen, ist eher eine Frage des Geschmacks und der individuellen Vorlieben.