IntelliJ中的Builder模式代码生成

时间:2012-04-27 09:52:25

标签: design-patterns intellij-idea code-generation builder-pattern

有没有办法在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;
    }
}

11 个答案:

答案 0 :(得分:92)

使用Replace Constructor with Builder重构。

要使用此功能,请在代码中单击构造函数的签名,然后右键单击并选择“Refactor”菜单,然后单击“使用Builder替换构造函数...”以打开对话框以生成代码。

答案 1 :(得分:20)

我发现IntelliJ中的内置构建器模式生成有点笨重,原因如下:

  1. 需要使用现有的构造函数作为参考。
  2. 无法通过“生成”菜单(OS X上的command+N)快速访问。
  3. 它只生成外部Builder类。正如其他人所提到的,在实现构建器模式时使用静态内部类非常常见。
  4. InnerBuilder plugin解决了所有这些缺点,无需设置或配置。这是插件生成的示例生成器:

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

答案 2 :(得分:13)

以下是如何克服 Mansoor Siddiqui提到的shortcomings

  

1)它需要使用现有的构造函数作为参考。

这很容易生成。只需在Windows上按 Alt + Ins 调用生成菜单,然后选择Constructor

  

2)通过" Generate"无法快速访问。 menu(OS X上的命令+ N)

只需转到Settings -> Keymap,搜索Builder并为其指定一个快捷方式(如果您经常使用此功能,这种情况很少见)。例如,您可以指定 Alt + B

另一种选择是 Ctrl + Shift + A (查找动作)。开始输入Builder,您就可以立即访问命令:

Find Action dialog

您可以使用此快捷方式快速访问任何IntelliJ IDEA功能(当您不记得该命令的确切内容以及在何处找到它时,这会有很大帮助。)

  

3)它只生成外部Builder类。正如其他人所提到的,在实现构建器模式时使用静态内部类非常常见。

我也更喜欢我的构建器作为静态内部类。不幸的是,没有直接的方法来做到这一点,但它仍然可行。您只需自己定义嵌套的内部类(保持为空),并在调用Replace Constructor with Builder对话框时,选择Use existing选项并选择内部类。奇迹般有效!虽然,将此选项配置起来会更容易。

答案 3 :(得分:9)

如果您想知道这是否可用于创建内部构建器类为described by Joshua Block的类 - 您只需先定义一个空内部类,然后选中"使用现有"并搜索你新创建的(内部类)并点击" Refactor"。

PS!游标必须驻留在构造函数内(预先编写),以便使用"将构造函数替换为Builder"重构功能。

答案 4 :(得分:5)

IntelliJ的方法是恕我直言,这是令人费解的。有两个插件(我更喜欢这个插件:https://plugins.jetbrains.com/plugin/7354)更好地服务于目的。

例如,我更喜欢将Builder类作为PoJo的内部类。要使用IntelliJ实现这一点,您需要额外的笔画。

该插件的另一个好处是功能的位置(在Generate...上下文菜单中)。

答案 5 :(得分:1)

龙目岛是做到这一点的最佳方法! (它具有用于语法支持https://plugins.jetbrains.com/plugin/6317-lombok-plugin的Intellij插件)

只需添加一个@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

答案 6 :(得分:0)

作为@ CrazyCoder答案的补充,我认为知道这一点非常有用 在Replace Constructor with Builder对话框的右上角,有一个配置按钮,可用于重命名setter的前缀。

答案 7 :(得分:0)

对于那些想要更换&#34;太多参数&#34;使用构建器模式,执行&#34;提取参数对象&#34;然后将转换构造函数转换为此处其他答案中提到的构建器。

答案 8 :(得分:0)

通过右键单击Generate&gt; Constructor类生成类的构造函数。然后,在Windows上,按Ctrl + Shift + A查找操作并键入“builder”,然后选择 “用构建器替换构造函数。”

答案 9 :(得分:0)

在我看来,获取内部静态类而不是单独的最简单方法是:

  1. 如果您还没有构造函数,请使用Generate a constructor dialog
  2. 生成一个构造函数
  3. 然后,使用Replace Constructor with Builder
  4. 使用Move refactoring将新创建的类移回初始类(热键:F6)

答案 10 :(得分:0)

我发现Effective Inner Builder是最好的选择,因为它添加了空检查并且可以仅从定义的成员开始。