Tạo mã mẫu Builder trong IntelliJ


82

Có cách nào để tự động viết các mẫu Builder trong IntelliJ không?

Ví dụ, với lớp đơn giản này:

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

có cách nào mà tôi có thể lấy IDE để tạo ra cái này không, hoặc tương tự:

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

Câu trả lời:


106

Sử dụng Trình tạo cấu trúc thay thế bằng tái cấu trúc Bộ xây dựng .

Để sử dụng chức năng này, hãy nhấp vào chữ ký của phương thức khởi tạo trong mã của bạn, sau đó nhấp chuột phải và chọn menu "Refactor", sau đó nhấp vào "Replace Constructor with Builder ..." để hiển thị hộp thoại tạo mã.


12
Có cách nào để thay đổi "setX ()" thành "withX ()" không, Serge?
ae6rt

5
Hoặc bạn có thể thay đổi setX () thành x () không?
Kurru

Đẹp! Chưa bao giờ mới tồn tại. Cảm ơn
vikingsteve

16
Bạn có thể thay đổi tên của các phương thức setter bằng cách nhấp vào bánh răng ở góc trên bên phải của cửa sổ tạo trình tạo và chọn "Đổi tên tiền tố Setter". Sau đó, bạn có thể thay đổi nó thành "with" hoặc chỉ xóa tiền tố hoàn toàn.
Chris B

3
Có thể làm cho IntelliJ tự động tạo lớp Builder như một lớp bên trong không?
kit

23

Tôi thấy việc tạo mẫu trình tạo dựng sẵn trong IntelliJ hơi rắc rối vì một vài lý do:

  1. Nó cần sử dụng một phương thức khởi tạo hiện có làm tham chiếu.
  2. Nó không thể truy cập nhanh thông qua menu "Tạo" ( command+Ntrên OS X).
  3. Nó chỉ tạo ra các lớp Builder bên ngoài. Như những người khác đã đề cập, rất phổ biến khi sử dụng các lớp bên trong tĩnh khi triển khai mẫu trình tạo.

Các InnerBuilder cắm địa chỉ tất cả những thiếu sót, và không yêu cầu phải cài đặt hay cấu hình. Đây là một Trình tạo mẫu được tạo bởi 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);
        }
    }
}

3
Vui lòng xem câu trả lời của tôi để biết giải pháp tích hợp cho tất cả các vấn đề bạn đã đề cập.
jFrenetic

1
Bạn đưa ra một số điểm tốt @jFrenetic, nhưng cuối cùng tôi vẫn thấy cách tiếp cận tích hợp quá cồng kềnh, ngay cả với những cách giải quyết đó. Với plugin, đó là nghĩa đen chỉ alt+shift+B, entervà BAM, bạn phải xây dựng của bạn. : D
Mansoor Siddiqui.

1
OMG đây là một giấc mơ trở thành sự thật. Trình tạo dựng sẵn đã không làm điều đó đối với tôi - tôi thích có trình xây dựng như một lớp bên trong của PoJo. Cảm ơn một mẹo đáng yêu!
Somaiah Kumbera

16

Dưới đây là cách khắc phục những thiếu sótMansoor Siddiqui đề cập :

1) Nó cần sử dụng một hàm tạo hiện có làm tham chiếu.

Điều này rất dễ tạo ra. Chỉ cần nhấn Alt+ Instrên Windows để gọi menu Tạo và chọn Constructor.

2) Không thể truy cập nhanh thông qua menu "Tạo" (lệnh + N trên OS X)

Chỉ cần truy cập Settings -> Keymap, tìm kiếm Buildervà gán cho nó một phím tắt bạn chọn (nếu bạn sử dụng chức năng này rất thường xuyên, điều này hiếm khi xảy ra). Bạn có thể gán Alt+ Bchẳng hạn.

Một thay thế khác là Ctrl+ Shift+ A(Tìm Hành động). Bắt đầu nhập Buildervà ngay lập tức bạn sẽ có quyền truy cập vào lệnh:

Hộp thoại Tìm Hành động

Bạn có thể sử dụng phím tắt này để nhanh chóng truy cập vào bất kỳ tính năng IntelliJ IDEA nào (điều này giúp ích rất nhiều khi bạn không nhớ chính xác lệnh được gọi là gì và tìm nó ở đâu).

3) Nó chỉ tạo ra các lớp Builder bên ngoài. Như những người khác đã đề cập, rất phổ biến khi sử dụng các lớp bên trong tĩnh khi triển khai mẫu trình tạo.

Tôi cũng thích các trình xây dựng của mình là các lớp bên trong tĩnh. Thật không may, không có cách nào đơn giản để làm điều đó, nhưng nó vẫn khả thi. Bạn chỉ cần tự định nghĩa lớp bên trong lồng nhau (để trống) và khi bạn gọi Replace Constructor with Builderhộp thoại, hãy chọn Use existingtùy chọn và chọn lớp bên trong của bạn. Hoạt động như một sự quyến rũ! Mặc dù, sẽ dễ dàng hơn nếu bạn có thể định cấu hình tùy chọn này.


11

Nếu bạn đang tự hỏi liệu điều này có thể được sử dụng để tạo một lớp với một lớp trình tạo bên trong như mô tả của Joshua Block hay không - trước tiên bạn phải xác định một lớp bên trong trống, sau đó chọn "Sử dụng hiện có" và tìm kiếm lớp bên trong mới được tạo của bạn (lớp bên trong ) và nhấn "Refactor".

Tái bút! Con trỏ phải nằm bên trong hàm tạo (được viết trước) để sử dụng chức năng tái cấu trúc "Replace Constructor with Builder".


Thật thú vị khi các plugin này quên mất một phần quan trọng của mẫu trình tạo: bạn vẫn nên xác định các tham số bắt buộc trong hàm tạo. Nếu không, bạn đã chuyển từ bắt tĩnh các lỗi tham số bị thiếu sang chỉ bắt trong thời gian chạy.
EJ Campbell

@EJCampbell Điều đó sẽ đánh bại một trong những mục đích của việc sử dụng Builder, đó là làm cho mã dễ đọc hơn bằng cách cung cấp một cách để đính kèm tên vào các tham số, ngay cả khi chúng được yêu cầu. Điều này giúp ích khi một hàm tạo nhận một số lượng khá lớn các tham số. Sẽ không cần thiết nếu Java cho phép chúng ta đặt tên cho các tham số thực tế trong lệnh gọi, giống như C # và Swift.
ajb

5

Cách IntelliJ để đạt được điều này, IMHO, là phức tạp. Có hai plugin (tôi thích cái này hơn: https://plugins.jetbrains.com/plugin/7354 ) phục vụ mục đích tốt hơn nhiều.

Ví dụ: tôi thích có lớp Builder làm lớp bên trong của PoJo. Để đạt được điều đó với IntelliJ, bạn cần thêm một vài thao tác.

Một điểm cộng khác cho plugin là vị trí của chức năng (trong Generate...menu ngữ cảnh).


4

Lombok là cách dễ nhất để làm điều đó! (Nó có một plugin Intellij để hỗ trợ cú pháp https://plugins.jetbrains.com/plugin/6317-lombok-plugin )

Chỉ cần thêm một @Builder chú thích và đằng sau các bức tường, nó sẽ thêm một triển khai trình xây dựng bên trong đối tượng.

Với 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;
}

Không có Lombok:

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

Nguồn: https://projectlombok.org/features/Builder


lombok là tạo mã với các bước bổ sung. bởi vì điều này gây nhầm lẫn cho một số công cụ phân tích tĩnh vì mã cuối cùng mà chúng đọc được trông không giống java.
ThisCompSciGuy

2

Theo tôi, cách đơn giản nhất để lấy lớp tĩnh bên trong thay vì lớp riêng biệt là:

  1. Nếu bạn chưa có một hàm tạo, hãy tạo một hàm tạo bằng cách sử dụng Tạo hộp thoại hàm tạo
  2. Sau đó sử dụng Replace Constructor bằng Builder
  3. Di chuyển lớp mới tạo trở lại lớp ban đầu bằng cách sử dụng Move refactoring (Phím nóng: F6)

1
Plugin này dường như để đạt được chính xác này chỉ trong một bước: plugins.jetbrains.com/plugin/7354-innerbuilder
jivimberg

0

Để bổ sung cho câu trả lời của @ CrazyCoder, tôi nghĩ rằng rất hữu ích khi biết rằng ở phía trên bên phải của hộp thoại Replace Constructor with Builder có một nút cấu hình mà bạn có thể sử dụng để đổi tên tiền tố của setters.


0

Đối với những người muốn thay thế "quá nhiều tham số" bằng một mẫu trình tạo, hãy thực hiện "trích xuất đối tượng tham số" và sau đó chuyển đổi phương thức khởi tạo thành trình tạo được đề cập trong các câu trả lời khác ở đây.


0

Tạo phương thức khởi tạo của lớp bằng cách nhấp chuột phải vào lớp Generate> Constructor. Sau đó, trên Windows, nhấn Ctrl + Shift + A để tìm hành động và nhập "trình tạo", chọn "Thay thế hàm tạo bằng trình xây dựng .."


0

Tôi nhận thấy Trình tạo bên trong hiệu quả là lựa chọn tốt nhất vì nó thêm các kiểm tra rỗng và có thể bắt đầu chỉ với các thành viên được xác định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.