Подтвердить что ты не робот

Создание кода шаблона 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;
    }
}
4b9b3361

Ответ 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

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

  1. Если у вас еще нет конструктора, сгенерируйте его с помощью Создать диалог конструктора
  2. Затем используйте Заменить конструктор на Builder
  3. Переместите вновь созданный класс обратно в исходный с помощью рефакторинга 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 "Заменить конструктор с помощью строителя.."