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;
}
}
コンストラクタをビルダーに置き換える リファクタリングを使用します。
この関数を使用するには、コード内のコンストラクターの署名をクリックし、右クリックして[リファクタリング]メニューを選択し、[コンストラクターをビルダーで置換...]をクリックして、コードを生成するダイアログボックスを表示します。
IntelliJのビルトインビルダーパターン生成は、いくつかの理由で少し不格好であることがわかりました。
command+N
OS Xで)。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);
}
}
}
Mansoor Siddiquiが言及した 短所 を克服する方法は次のとおりです。
1)既存のコンストラクターを参照として使用する必要があります。
これは非常に簡単に生成できます。打つだけ Alt + Ins Windowsで[生成]メニューを呼び出し、Constructor
を選択します。
2)[生成]メニュー(OS Xではcommand + N)からすぐにアクセスできない
Settings -> Keymap
に移動し、Builder
を検索して、選択したショートカットを割り当てます(この機能を頻繁に使用する場合はめったにありません)。割り当てることができます Alt + B 例えば。
別の選択肢は Ctrl + Shift + A (検索アクション)。 Builder
と入力し始めると、すぐにコマンドにアクセスできます:
このショートカットを使用して、IntelliJ IDEA機能にすばやくアクセスできます(これは、コマンドの名前と場所を正確に覚えていない場合に役立ちます)。
3)外部Builderクラスのみを生成します。他の人が言及したように、ビルダーパターンを実装するとき、静的内部クラスを使用することは非常に一般的です。
また、静的な内部クラスとしてビルダーを好みます。残念ながら、それを行う簡単な方法はありませんが、それでも実行可能です。ネストされた内部クラスを自分で定義する(空のままにする)だけで、Replace Constructor with Builder
ダイアログを呼び出すときに、Use existing
オプションを選択して内部クラスを選択します。チャームのように機能します!ただし、このオプションを構成可能にする方が簡単でした。
Joshua Blockによる説明 のように内部ビルダークラスを持つクラスを作成するためにこれを使用できるかどうか疑問に思っている場合は、最初に空の内部クラスを定義する必要があります。新しく作成した(内部クラス)の場合、「リファクタリング」をクリックします。
PS! 「コンストラクタをビルダーに置き換える」リファクタリング関数を使用するには、カーソルがコンストラクタ内にある必要があります(事前に作成済み)。
これへのIntelliJの方法は、IMHOです。 2つのプラグインがあります(私はこれを好みます: https://plugins.jetbrains.com/plugin/7354 )。
たとえば、BuilderクラスをPoJoの内部クラスとして使用することを好みます。 IntelliJでそれを実現するには、追加のストロークはほとんど必要ありません。
プラグインのもう1つのプラスは、機能の場所です(Generate...
コンテキストメニュー)。
ロンボクはそれを行う最良の方法です! (構文サポート用の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 + ")";
}
}
}
私の意見では、個別ではなく内部静的クラスを取得する最も簡単な方法は次のとおりです。
「パラメーターが多すぎます」をビルダーパターンに置き換えたい場合は、「パラメーターオブジェクトを抽出」してから、コンストラクターをビルダーに変換します。
クラスGenerate> Constructorを右クリックして、クラスのコンストラクターを生成します。次に、Windowsでは、CtrlキーとShiftキーを押しながらAキーを押してアクションを見つけ、「ビルダー」と入力して、「コンストラクターをビルダーに置き換える」を選択します。
@CrazyCoderの答えを補完するものとして、 Constructoror with Builder ダイアログの右上に、セッターのプレフィックスの名前を変更するために使用できる設定ボタンがあることを知っておくと非常に便利だと思います。