Création du générateur Java pour une classe dans IntelliJ

1. Introduction

Le modèle de conception Builder est l'un des modèles de création les plus largement utilisés. Cela nous aide à construire des objets complexes.

L'écriture manuelle des constructeurs est lourde et sujette aux erreurs. Par conséquent, nous devrions utiliser des outils dédiés pour les générer automatiquement chaque fois que possible.

Dans ce didacticiel, nous explorerons différentes façons de créer automatiquement des classes de générateur dans IntelliJ IDE. Nous allons jeter un œil aux fonctionnalités intégrées fournies par IntelliJ, ainsi qu'aux plugins tiers.

2. Configuration initiale

Tout au long de cet article, nous utiliserons la version 2019.1.3 de l'édition IntelliJ IDEA Community, qui est la version la plus récente au moment de la rédaction. Cependant, toutes les techniques présentées dans les exemples devraient également fonctionner correctement avec toute autre version d'IDEA.

Commençons par définir la classe Book pour laquelle nous allons générer un générateur:

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

3. Utilisation de la fonctionnalité intégrée d'IntelliJ

Pour générer un générateur pour la classe Book à l' aide des outils intégrés d'IntelliJ, nous avons besoin d'un constructeur approprié.

Créons-en un:

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

Maintenant, nous sommes prêts à créer un constructeur. Par conséquent, plaçons le curseur sur le constructeur créé et ouvrons le popup Refactor This en appuyant sur Ctrl + Alt + Shift + T (sur PC) et sélectionnez Replace Constructor with Builder refactoring:

Nous pouvons en outre ajuster certaines des options de la classe de générateur, comme son nom et son package cible:

En conséquence, nous avons généré la classe 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. Préfixe de setters personnalisés

Il est courant d'utiliser un préfixe with pour les méthodes de définition dans les classes de générateur.

Pour changer le préfixe par défaut, nous devons choisir l' icône Rename Setters Prefix dans le coin supérieur droit de la fenêtre d'options :

3.2. Générateur interne statique

Certains d'entre nous préféreront peut-être implémenter des générateurs en tant que classes internes statiques comme décrit par Joshua Bloch dans Effective Java .

Si tel est le cas, nous devons prendre quelques étapes supplémentaires pour y parvenir en utilisant la fonctionnalité Remplacer le constructeur par le constructeur d' IntelliJ .

Tout d'abord, nous devons créer manuellement une classe interne vide et rendre le constructeur privé:

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 }

De plus, nous devons choisir Utiliser l'existant dans la fenêtre d'options et pointer vers notre classe nouvellement créée:

4. Utilisation du plugin InnerBuilder

Voyons maintenant comment nous pouvons générer un générateur pour la classe Book à l' aide du plugin InnerBuilder.

Une fois que nous avons installé le plugin, nous pouvons ouvrir le pop-up Générer en appuyant sur Alt + Insérer (sur PC) et en choisissant l' option Builder… :

Alternativement, nous pouvons appeler le plugin InnerBuilder directement en appuyant sur Alt + Shift + B (sur PC):

Comme nous le voyons, il existe quelques options parmi lesquelles nous pouvons choisir pour personnaliser le générateur généré.

Voyons le générateur généré lorsque toutes les options sont décochées:

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

Le plugin InnerBuilder implémente les générateurs en tant que classes internes statiques par défaut.

5. Utilisation du plug-in Builder Generator

Enfin, voyons comment fonctionne Builder Generator.

De même, comme pour InnerBuilder, nous pouvons soit appuyer sur Alt + Insertion (sur PC) et choisir l' option Builder , soit utiliser le raccourci Alt + Maj + B.

As we can see, we have three options to choose from for customizing the BookBuilder:

Let's leave all the options unchecked and see the generated builder class:

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

The first option that Builder Generator plugin provides to customize the created builder class – Inner builder – is rather self-explanatory.

Two others, however, are more interesting, and we'll explore them in the following sections.

5.1. ‘but' Method Option

If we choose this option, the plugin will add a but() method to the BookBuilder class:

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.

Il est généralement préférable d'utiliser ce type d'outils pour générer automatiquement nos générateurs . Chacune des options que nous avons présentées a ses avantages et ses inconvénients. L'approche choisie est plutôt une question de goût et de préférences individuelles.