Existe-t-il un moyen d'automatiser l'écriture de modèles Builder dans IntelliJ?
Par exemple, étant donné cette classe simple:
class Film {
private String title;
private int length;
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return this.title;
}
public void setLength(int length) {
this.length = length;
}
public int getLength() {
return this.length;
}
}
existe-t-il un moyen d'obtenir le IDE pour générer ceci, ou similaire:
public class FilmBuilder {
Film film;
public FilmBuilder() {
film = new Film();
}
public FilmBuilder withTitle(String title) {
film.setTitle(title);
return this;
}
public FilmBuilder withLength(int length) {
film.setLength(length);
return this;
}
public Film build() {
return film;
}
}
Utilisez le constructeur de Remplacer avec Builder refactoring.
Pour utiliser cette fonction, cliquez sur la signature du constructeur dans votre code, cliquez avec le bouton droit de la souris et sélectionnez le menu "Refactor", puis cliquez sur "Remplacer le constructeur avec le constructeur ..." pour afficher la boîte de dialogue générant le code.
J'ai trouvé la génération de modèles de constructeur intégrée à IntelliJ un peu maladroite pour plusieurs raisons:
command+N
sous OS X).Le plugin InnerBuilder résout tous ces problèmes et ne nécessite aucune installation ni configuration. Voici un exemple de générateur généré par le plugin:
public class Person {
private String firstName;
private String lastName;
private int age;
private Person(Builder builder) {
firstName = builder.firstName;
lastName = builder.lastName;
age = builder.age;
}
public static final class Builder {
private String firstName;
private String lastName;
private int age;
public Builder() {
}
public Builder firstName(String firstName) {
this.firstName = firstName;
return this;
}
public Builder lastName(String lastName) {
this.lastName = lastName;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Person build() {
return new Person(this);
}
}
}
Voici comment surmonter les lacunes mentionnées par Mansoor Siddiqui :
1) Il doit utiliser un constructeur existant comme référence.
Ce qui est très facile à générer. Il suffit de frapper Alt + Ins sous Windows, appelez le menu Générer et choisissez Constructor
name__.
2) Ce n'est pas rapidement accessible via le menu "Générer" (commande + N sous OS X)
Allez simplement à Settings -> Keymap
, recherchez Builder
et attribuez-lui un raccourci de votre choix (si vous utilisez cette fonctionnalité très souvent, ce qui est rarement le cas). Vous pouvez assigner Alt + B par exemple.
Une autre alternative est Ctrl + Shift + A (Trouver une action). Commencez à taper Builder
et vous aurez immédiatement accès à la commande:
Vous pouvez utiliser ce raccourci pour obtenir rapidement l’accès à n’importe quelle fonction IntelliJ IDEA (cela vous aidera beaucoup lorsque vous ne vous souvenez pas exactement comment la commande est appelée et où la trouver).
3) Il ne génère que des classes Builder externes. Comme d'autres l'ont mentionné, il est très courant d'utiliser des classes internes statiques lors de la mise en œuvre du modèle de générateur.
Je préfère également mes constructeurs en tant que classes internes statiques. Malheureusement, il n’existe pas de solution simple, mais cela reste réalisable. Il vous suffit de définir vous-même la classe interne imbriquée (laissez-la vide), et lorsque vous appelez la boîte de dialogue Replace Constructor with Builder
, choisissez l'option Use existing
et sélectionnez votre classe interne. Fonctionne comme un charme! Cependant, il aurait été plus facile de rendre cette option configurable.
Si vous vous demandez si cela peut être utilisé pour créer une classe avec une classe de constructeur interne telle que décrite par Joshua Block -, vous devez tout d'abord définir une classe interne vide, puis cochez la case "Utiliser l'existant" et recherchez votre nouvelle classe. créé (classe intérieure) et cliquez sur "Refactor".
PS! Le curseur doit résider dans le constructeur (pré-écrit) pour pouvoir utiliser la fonction de refactoring "Remplacer le constructeur par le constructeur".
Le moyen IntelliJ pour y parvenir est, à mon humble avis, est compliqué. Il existe deux plugins (je préfère celui-ci: https://plugins.jetbrains.com/plugin/7354 ) qui servent beaucoup mieux.
Par exemple, je préfère avoir la classe Builder comme classe interne du PoJo. Pour atteindre cet objectif avec IntelliJ, vous avez besoin de quelques coups supplémentaires.
Un autre avantage pour le plugin est l'emplacement de la fonctionnalité (dans le menu contextuel Generate...
).
Lombok est le meilleur moyen de le faire! (Il a un plugin Intellij pour le support de la syntaxe https://plugins.jetbrains.com/plugin/6317-lombok-plugin )
Ajoutez simplement une annotation @Builder
et, derrière les murs, ajoutera une implémentation de générateur à l'intérieur de l'objet. De nos jours, Lombok est comme un standard de l'industrie :)
Avec Lombok:
import lombok.Builder;
import lombok.Singular;
import Java.util.Set;
@Builder
public class BuilderExample {
@Builder.Default private long created = System.currentTimeMillis();
private String name;
private int age;
@Singular private Set<String> occupations;
}
Sans Lombok:
import Java.util.Set;
public class BuilderExample {
private long created;
private String name;
private int age;
private Set<String> occupations;
BuilderExample(String name, int age, Set<String> occupations) {
this.name = name;
this.age = age;
this.occupations = occupations;
}
private static long $default$created() {
return System.currentTimeMillis();
}
public static BuilderExampleBuilder builder() {
return new BuilderExampleBuilder();
}
public static class BuilderExampleBuilder {
private long created;
private boolean created$set;
private String name;
private int age;
private Java.util.ArrayList<String> occupations;
BuilderExampleBuilder() {
}
public BuilderExampleBuilder created(long created) {
this.created = created;
this.created$set = true;
return this;
}
public BuilderExampleBuilder name(String name) {
this.name = name;
return this;
}
public BuilderExampleBuilder age(int age) {
this.age = age;
return this;
}
public BuilderExampleBuilder occupation(String occupation) {
if (this.occupations == null) {
this.occupations = new Java.util.ArrayList<String>();
}
this.occupations.add(occupation);
return this;
}
public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
if (this.occupations == null) {
this.occupations = new Java.util.ArrayList<String>();
}
this.occupations.addAll(occupations);
return this;
}
public BuilderExampleBuilder clearOccupations() {
if (this.occupations != null) {
this.occupations.clear();
}
return this;
}
public BuilderExample build() {
// complicated switch statement to produce a compact properly sized immutable set omitted.
Set<String> occupations = ...;
return new BuilderExample(created$set ? created : BuilderExample.$default$created(), name, age, occupations);
}
@Java.lang.Override
public String toString() {
return "BuilderExample.BuilderExampleBuilder(created = " + this.created + ", name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
}
}
}
À mon avis, le moyen le plus simple d'obtenir la classe statique interne au lieu d'une classe distincte est le suivant:
Pour ceux qui souhaitent remplacer "trop de paramètres" par un motif de générateur, "extraire un objet de paramètre", puis le constructeur de conversion en générateur mentionné dans d'autres réponses ici.
Générez le constructeur de la classe en cliquant avec le bouton droit de la souris sur la classe Generate> Constructor. Ensuite, sous Windows, appuyez sur les touches Ctrl + Maj + A pour rechercher une action et tapez "constructeur", sélectionnez "Remplacer le constructeur par le constructeur .."
En complément de la réponse de @ CrazyCoder, je pense qu’il est très utile de savoir que Dans la partie supérieure droite de Remplacer le constructeur par le générateur dialogue, il existe un bouton de configuration que vous pouvez utiliser pour renommer le préfixe des installateurs.