web-dev-qa-db-ja.com

IntelliJでのビルダーパターンコードの生成

IntelliJでBuilderパターンの作成を自動化する方法はありますか?

たとえば、次の単純なクラスがある場合:

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

コンストラクタをビルダーに置き換える リファクタリングを使用します。

この関数を使用するには、コード内のコンストラクターの署名をクリックし、右クリックして[リファクタリング]メニューを選択し、[コンストラクターをビルダーで置換...]をクリックして、コードを生成するダイアログボックスを表示します。

94
CrazyCoder

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

Mansoor Siddiquiが言及した 短所 を克服する方法は次のとおりです。

1)既存のコンストラクターを参照として使用する必要があります。

これは非常に簡単に生成できます。打つだけ Alt + Ins Windowsで[生成]メニューを呼び出し、Constructorを選択します。

2)[生成]メニュー(OS Xではcommand + N)からすぐにアクセスできない

Settings -> Keymapに移動し、Builderを検索して、選択したショートカットを割り当てます(この機能を頻繁に使用する場合はめったにありません)。割り当てることができます Alt + B 例えば。

別の選択肢は Ctrl + Shift + A (検索アクション)。 Builderと入力し始めると、すぐにコマンドにアクセスできます:

Find Action dialog

このショートカットを使用して、IntelliJ IDEA機能にすばやくアクセスできます(これは、コマンドの名前と場所を正確に覚えていない場合に役立ちます)。

3)外部Builderクラスのみを生成します。他の人が言及したように、ビルダーパターンを実装するとき、静的内部クラスを使用することは非常に一般的です。

また、静的な内部クラスとしてビルダーを好みます。残念ながら、それを行う簡単な方法はありませんが、それでも実行可能です。ネストされた内部クラスを自分で定義する(空のままにする)だけで、Replace Constructor with Builderダイアログを呼び出すときに、Use existingオプションを選択して内部クラスを選択します。チャームのように機能します!ただし、このオプションを構成可能にする方が簡単でした。

13
jFrenetic

Joshua Blockによる説明 のように内部ビルダークラスを持つクラスを作成するためにこれを使用できるかどうか疑問に思っている場合は、最初に空の内部クラスを定義する必要があります。新しく作成した(内部クラス)の場合、「リファクタリング」をクリックします。

PS! 「コンストラクタをビルダーに置き換える」リファクタリング関数を使用するには、カーソルがコンストラクタ内にある必要があります(事前に作成済み)。

9
PålOliver

これへのIntelliJの方法は、IMHOです。 2つのプラグインがあります(私はこれを好みます: https://plugins.jetbrains.com/plugin/7354 )。

たとえば、BuilderクラスをPoJoの内部クラスとして使用することを好みます。 IntelliJでそれを実現するには、追加のストロークはほとんど必要ありません。

プラグインのもう1つのプラスは、機能の場所です(Generate... コンテキストメニュー)。

5
nucatus

ロンボクはそれを行う最良の方法です! (構文サポート用のIntellijプラグインがあります https://plugins.jetbrains.com/plugin/6317-lombok-plugin

@Builder注釈を追加するだけで、壁の後ろにオブジェクト内にビルダー実装が追加されます。

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

ロンボクなし:

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

2
veysiertekin

私の意見では、個別ではなく内部静的クラスを取得する最も簡単な方法は次のとおりです。

  1. コンストラクターがまだない場合は、 コンストラクターダイアログの生成 を使用してコンストラクターを生成します
  2. 次に、 コンストラクタをビルダーに置き換える を使用します
  3. Move refactoring (Hotkey:F6)を使用して、新しく作成したクラスを最初のクラスに戻します
2
Gaket

「パラメーターが多すぎます」をビルダーパターンに置き換えたい場合は、「パラメーターオブジェクトを抽出」してから、コンストラクターをビルダーに変換します。

0
rogerdpack

クラスGenerate> Constructorを右クリックして、クラスのコンストラクターを生成します。次に、Windowsでは、CtrlキーとShiftキーを押しながらAキーを押してアクションを見つけ、「ビルダー」と入力して、「コンストラクターをビルダーに置き換える」を選択します。

0
Vijay Nandwana

@CrazyCoderの答えを補完するものとして、 Constructoror with Builder ダイアログの右上に、セッターのプレフィックスの名前を変更するために使用できる設定ボタンがあることを知っておくと非常に便利だと思います。

0
tibtof