Генерація коду шаблону будівельника в IntelliJ


83

Чи є спосіб автоматизувати написання шаблонів 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;
    }
}

Відповіді:


108

Використовуйте Замінити конструктор на рефакторинг Builder .

Щоб скористатися цією функцією, клацніть на підписі конструктора у коді, клацніть правою кнопкою миші та виберіть меню «Рефактор», а потім натисніть «Замінити конструктор на Builder ...», щоб відкрити діалогове вікно для генерації коду.


12
Чи є спосіб змінити "setX ()" на "withX ()", Серж?
ae6rt

5
Або ви можете змінити setX () на просто x ()?
Курру

Приємно! Ніколи нового, що існувало. Дякую
vikingsteve

16
Ви можете змінити назву методів встановлення, натиснувши на шестерню у верхньому правому куті вікна створення конструктора та вибравши "Перейменувати префікс сетерів". Потім ви можете змінити його на "з" або просто повністю видалити префікс.
Chris B

3
Чи можна змусити IntelliJ автоматично створювати клас Builder як внутрішній клас?
комплект

23

Я виявив, що вбудоване покоління побудови шаблонів в IntelliJ було трохи незграбним з кількох причин:

  1. Для посилання потрібно використовувати існуючий конструктор.
  2. До нього не швидко дістатися через меню "Створити" ( command+Nна OS X).
  3. Він генерує лише зовнішні класи Builder. Як зазначали інші, дуже часто використовується статичний внутрішній клас при реалізації шаблону будівельника.

InnerBuilder плагін адреси всіх цих недоліків, і не вимагає установки або настройки. Ось зразок конструктора, згенерований плагіном:

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
Будь ласка, перегляньте мою відповідь щодо вбудованого рішення всіх згаданих проблем.
jFrenetic 02

1
Ви робите кілька хороших зауважень @jFrenetic, але я все-таки вважаю, що вбудований підхід занадто громіздкий, навіть з цими обхідними шляхами. За допомогою плагіна, це буквально alt+shift+B, enterі БАМ, у вас є свій будівельник. : D
Mansoor Siddiqui

1
OMG це мрія, яка здійснилася. Вбудований конструктор не зробив цього для мене - я вважаю за краще, щоб будівельник був внутрішнім класом PoJo. Дякуємо чудовій підказці!
Somaiah Kumbera

16

Ось як подолати недоліки, згадані Мансуром Сіддікі :

1) Для посилання потрібно використовувати існуючий конструктор.

Що дуже легко генерувати. Просто натисніть Alt+ Insу Windows, щоб викликати меню «Створити» та вибрати Constructor.

2) До нього не швидко дістатися через меню "Створити" (команда + N на OS X)

Просто перейдіть до Settings -> Keymap, знайдіть Builderі призначте йому ярлик на ваш вибір (якщо ви використовуєте цю функцію дуже часто, що рідко буває). Наприклад, ви можете призначити Alt+ B.

Інша альтернатива - Ctrl+ Shift+ A(Знайти дію). Почніть друкувати, Builderі ви одразу отримаєте доступ до команди:

Діалогове вікно пошуку дії

Ви можете використовувати цей ярлик для швидкого доступу до будь-якої функції IntelliJ IDEA (це дуже допомагає, коли ви не пам’ятаєте, як саме називається команда та де її знайти).

3) Він генерує лише зовнішні класи Builder. Як зазначали інші, дуже часто використовується статичний внутрішній клас при реалізації шаблону будівельника.

Я також віддаю перевагу своїм будівельникам як статичним внутрішнім класам. На жаль, прямого способу цього не існує, але це все ще можливо. Вам просто потрібно самостійно визначити вкладений внутрішній клас (залишити його порожнім), і коли ви викликаєте Replace Constructor with Builderдіалогове вікно, виберіть Use existingопцію та виберіть свій внутрішній клас. Працює як шарм! Хоча було б простіше зробити цей параметр налаштованим.


12

Якщо ви задаєтеся питанням, чи можна це використовувати для створення класу з внутрішнім класом конструктора, як описано Джошуа Блоком - вам просто потрібно спочатку визначити порожній внутрішній клас, а потім встановити прапорець "Використовувати існуючий" та шукати ваш щойно створений (внутрішній клас ) і натисніть "Refactor".

PS! Курсор повинен знаходитися всередині конструктора (заздалегідь записаний), щоб використовувати функцію рефакторингу "Замінити конструктор на Builder"


Цікаво, що ці плагіни забувають важливу частину шаблону конструктора: ви все одно повинні визначити необхідні параметри в конструкторі. В іншому випадку ви перейшли від статичного лову відсутніх помилок param до лову лише під час виконання.
EJ Campbell,

@EJCampbell Це перемогло б одну з цілей використання Builder, яка полягає в тому, щоб зробити код більш читабельним, надавши спосіб приєднання імен до параметрів, навіть якщо вони потрібні. Це допомагає, коли конструктор приймає досить велику кількість параметрів. Не було б необхідності, якщо б Java дозволяла нам називати фактичні параметри у виклику, як C # та Swift.
ajb

5

Шлях IntelliJ до цього, IMHO, заплутаний. Є два плагіни (я віддаю перевагу цьому: https://plugins.jetbrains.com/plugin/7354 ), які служать цілям набагато краще.

Наприклад, я вважаю за краще мати клас Builder як внутрішній клас PoJo. Щоб досягти цього за допомогою IntelliJ, вам потрібно кілька додаткових обведень.

Ще одним плюсом плагіна є розташування функціоналу (у Generate...контекстному меню).


4

Ломбок - це найпростіший спосіб зробити це! (Він має плагін 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


lombok - це генерація коду з додатковими кроками. через це плутає ряд інструментів статичного аналізу, оскільки остаточний код, який вони читають, не схожий на java.
ThisCompSciGuy

2

На мій погляд, найпростішим способом отримати внутрішній статичний клас замість окремого є:

  1. Якщо у вас ще немає конструктора, створіть його за допомогою допомогою діалогового вікна «Створити конструктор»
  2. Потім використовуйте Замінити конструктор на Builder
  3. Перемістіть щойно створений клас назад до початкового, використовуючи функцію « Перемістити рефакторинг» (гаряча клавіша: F6)

1
Здається, цей плагін досягає саме цього всього за один крок: plugins.jetbrains.com/plugin/7354-innerbuilder
jivimberg

0

Як доповнення до відповіді @ CrazyCoder, я думаю, дуже корисно знати, що у верхній правій частині діалогового вікна Замінити конструктор на Builder є кнопка конфігурації, за допомогою якої можна перейменувати префікс сетерів.


0

Для тих, хто хоче замінити "занадто багато параметрів" шаблоном конструктора, зробіть "витяг об'єкта параметра", а потім перетворіть конструктор у конструктор, згаданий в інших відповідях тут.


0

Створіть конструктор класу, клацнувши правою кнопкою миші на класі Створити> Конструктор. Потім у Windows натисніть Ctrl + Shift + A, щоб знайти дію та введіть "builder", виберіть "Замінити конструктор на builder .."


0

Я виявив, що Effective Inner Builder є найкращим варіантом, оскільки він додає нульові перевірки і може починатися лише з визначених членів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.