IntelliJ中的生成器模式代码生成


82

有什么方法可以自动在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;
    }
}

Answers:


106

使用带有构建器重构的替换构造器

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


12
有没有办法将“ setX()”更改为“ withX()”,Serge?
ae6rt

5
还是可以将setX()更改为x()?
2014年

真好!从来没有新的存在。谢谢
vikingsteve

16
您可以通过单击创建构建器窗口右上角的齿轮,然后选择“重命名设置器前缀”来更改设置器方法的名称。然后,您可以将其更改为“ with”,或者完全删除前缀。
克里斯·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 '16

1
您在@jFrenetic上提出了一些要点,但即使采用这些解决方法,我最终仍然发现内置方法过于繁琐。有了这个插件,它真的只是alt+shift+Benter和BAM,你有你的建设者。:D
Mansoor Siddiqui

1
天哪,这是一个梦想成真。内置的构建器对我没有帮助-我更喜欢将构建器作为PoJo的内部类。感谢一个可爱的提示!
Somaiah Kumbera '18

16

以下是克服Mansoor Siddiqui所提到的缺点的方法

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

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

2)无法通过“生成”菜单快速访问(在OS X上为command + N)

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

另一种选择是Ctrl+ Shift+ A(执行操作)。开始输入Builder,您将立即访问命令:

查找动作对话框

您可以使用此快捷方式快速访问任何IntelliJ IDEA功能(当您不记得确切的命令名称和查找位置时,此功能将非常有用)。

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

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


11

如果您想知道这是否可用于创建约书亚·布洛克(Joshua Block)描述的带有内部构建器类的类-您只需先定义一个空的内部类,然后选中“使用现有”并搜索您新创建的(内部类),然后点击“重构”。

PS!游标必须驻留在构造函数中(预先编写),才能使用“用构建器替换构造函数”重构功能。


有趣的是,这些插件忘记了构建器模式的重要组成部分:您仍应在构造器中定义所需的参数。否则,您已经从静态捕获丢失的参数错误转移到仅在运行时捕获。
EJ Campbell

@EJCampbell这会破坏一个使用生成器,这是为了让代码更易读,提供了一种名称附加到的参数,即使要他们需要的目的。这在构造函数采用大量参数时会有所帮助。如果Java允许我们在调用中命名实际参数(例如C#和Swift这样做),则没有必要。
2016年

5

IntelliJ的解决方法是恕我直言。那里有两个插件(我更喜欢这个插件: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



0

对于那些想要用构建器模式替换“太多参数”的用户,请执行“提取参数对象”,然后将转换构造器转换为构建器,在此处其他答案中提到。


0

通过右键单击类Generate> Constructor来生成类的构造函数。然后,在Windows上,按Ctrl + Shift + A可以找到操作并键入“ builder”,然后选择“用builder替换构造函数。”


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.