Создание кода шаблона Builder в IntelliJ
Есть ли способ автоматизировать запись шаблонов Builder в IntelliJ?
Например, учитывая этот простой класс:
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;
}
}
есть способ, которым я мог бы заставить IDE генерировать это или подобное:
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;
}
}
Ответы
Ответ 1
Используйте Replace Constructor with Builder для рефакторинга.
Чтобы использовать эту функцию, нажмите на подпись конструктора в своем коде, затем щелкните правой кнопкой мыши и выберите меню "Рефакторинг", затем нажмите "Заменить конструктор с помощью Builder...", чтобы открыть диалоговое окно для генерации кода.
Ответ 2
Я обнаружил, что встроенное построение шаблона построителя в IntelliJ было немного неуклюжим по нескольким причинам:
- В качестве ссылки должен использоваться существующий конструктор.
- Он не быстро доступен через меню "Создать" (
command+N
в OS X).
- Он генерирует только внешние классы Builder. Как отмечали другие, очень часто приходится использовать статические внутренние классы при реализации шаблона построителя.
Плагин InnerBuilder устраняет все эти недостатки и не требует настройки или конфигурации. Здесь образец Builder, сгенерированный плагином:
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);
}
}
}
Ответ 3
Вот как преодолеть недостатки, упомянутые Мансуром Сиддики:
1) Нужно использовать существующий конструктор в качестве ссылки.
Который очень легко генерировать. Просто нажмите Alt + Ins в Windows, чтобы вызвать меню "Генерирование", и выберите Constructor
.
2) Он не доступен быстро через меню "Создать" (команда + N в OS X)
Просто зайдите в Settings -> Keymap
, найдите Builder
и назначьте ему ярлык на ваш выбор (если вы часто используете эту функцию, что редко бывает). Например, вы можете назначить Alt + B.
Другой альтернативой является Ctrl + Shift + A (Найти действие). Начните вводить Builder
, и вы сразу получите доступ к команде:
![Find Action dialog]()
Вы можете использовать этот ярлык для быстрого доступа к любой функции IntelliJ IDEA (это очень помогает, когда вы точно не помните, как вызывается команда и где ее найти).
3) Он генерирует только внешние классы Builder. Как уже упоминали другие, очень часто используют статические внутренние классы при реализации шаблона компоновщика.
Я также предпочитаю своих строителей как статические внутренние классы. К сожалению, не существует простого способа сделать это, но это все еще возможно. Вам просто нужно определить вложенный внутренний класс самостоятельно (оставить его пустым), и когда вы вызываете диалоговое окно Replace Constructor with Builder
, выберите опцию Use existing
и выберите свой внутренний класс. Работает как шарм! Хотя было бы проще сделать этот параметр настраиваемым.
Ответ 4
Если вам интересно, можно ли это использовать для создания класса с классом внутреннего класса как описанным в блоке Джошуа, вам просто нужно определить пустой внутренний класс сначала проверьте "Использовать существующий" и найдите свой вновь созданный (внутренний класс) и нажмите "Рефакторинг".
PS! Курсор должен находиться внутри конструктора (предварительно написанного), чтобы использовать функцию рефакторинга Replace Constructor with Builder.
Ответ 5
Интеллигентный способ это, ИМХО, запутанный. Есть два плагина (я предпочитаю этот: https://plugins.jetbrains.com/plugin/7354), которые служат цели намного лучше.
Например, я предпочитаю иметь класс Builder в качестве внутреннего класса PoJo. Чтобы добиться этого с IntelliJ, вам нужно несколько дополнительных ударов.
Еще одним плюсом для плагина является расположение функциональности (в контекстном меню Generate...
).
Ответ 6
На мой взгляд, самый простой способ получить внутренний статический класс вместо отдельного:
- Если у вас еще нет конструктора, сгенерируйте его с помощью Создать диалог конструктора
- Затем используйте Заменить конструктор на Builder
- Переместите вновь созданный класс обратно в исходный с помощью рефакторинга Move (горячая клавиша: F6)
Ответ 7
Ломбок - лучший способ сделать это! (Он имеет плагин Intellij для поддержки синтаксиса https://plugins.jetbrains.com/plugin/6317-lombok-plugin)
Просто добавьте аннотацию @Builder
, и за стенами она добавит реализацию построителя внутри объекта.
С Ломбоком:
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;
}
Без Ломбока:
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 + ")";
}
}
}
Источник: https://projectlombok.org/features/Builder
Ответ 8
В качестве дополнения к ответу @CrazyCoder я считаю очень полезным знать, что
в верхней правой части диалогового окна Replace Constructor with Builder есть кнопка конфигурации, которую вы можете использовать для переименования префикса сеттеров.
Ответ 9
Для тех, кто хочет заменить "слишком много параметров" на шаблон построителя, выполните "извлечение объекта параметра", а затем конструктор преобразования в строитель, упомянутый в других ответах здесь.
Ответ 10
Создайте конструктор класса, щелкнув правой кнопкой мыши на классе Generate > Constructor. Затем в Windows нажмите Ctrl + Shift + A, чтобы найти действие и введите "builder", выберите
Msgstr "Заменить конструктор с помощью строителя.."