IntelliJ에서 빌더 패턴 코드 생성


82

IntelliJ에서 작성기 패턴 작성을 자동화하는 방법이 있습니까?

예를 들어 다음과 같은 간단한 클래스가 있습니다.

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

답변:


106

생성자를 빌더로 교체 리팩토링을 사용 하십시오 .

이 기능을 사용하려면 코드에서 생성자의 서명을 클릭 한 다음 마우스 오른쪽 버튼을 클릭하고 "리팩터링"메뉴를 선택한 다음 "생성자를 빌더로 대체 ..."를 클릭하여 코드를 생성하는 대화 상자를 불러옵니다.


12
"setX ()"를 "withX ()", Serge로 변경하는 방법이 있습니까?
ae6rt

5
아니면 setX ()를 x ()로 변경할 수 있습니까?
Kurru

좋은! 존재하는 새로운 것은 없습니다. 감사합니다
vikingsteve

16
빌더 생성 창의 오른쪽 상단 모서리에있는 기어를 클릭하고 "Setters Prefix 이름 바꾸기"를 선택하여 setter 메서드의 이름을 변경할 수 있습니다. 그런 다음 "with"로 변경하거나 접두사를 완전히 제거 할 수 있습니다.
Chris B

3
IntelliJ가 Builder 클래스를 내부 클래스로 자동으로 만들 수 있습니까?
키트

23

IntelliJ의 빌트인 빌더 패턴 생성이 몇 가지 이유로 약간 어색하다는 것을 알았습니다.

  1. 기존 생성자를 참조로 사용해야합니다.
  2. "생성"메뉴 ( command+NOS 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

1
@jFrenetic에서 몇 가지 좋은 점을 지적했지만 궁극적으로 이러한 해결 방법을 사용하더라도 기본 제공 방식이 너무 번거 롭다는 것을 알았습니다. 플러그인으로, 그것은 말 그대로 그냥 alt+shift+B, enter및 BAM, 당신은 당신의 빌더가 있습니다. : D
Mansoor Siddiqui

1
OMG 이것은 꿈이 이루어졌습니다. 빌트인 빌더는 나를 위해하지 않았습니다. 저는 빌더를 PoJo의 내부 클래스로 사용하는 것을 선호합니다. 감사합니다!
Somaiah Kumbera

16

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옵션을 선택하고 내부 클래스를 선택하면됩니다. 매력처럼 작동합니다! 하지만이 옵션을 구성 가능하게 만드는 것이 더 쉬웠을 것입니다.


11

이것이 Joshua Block이 설명 하는 내부 빌더 클래스를 사용하여 클래스를 생성하는 데 사용할 수 있는지 궁금하다면 먼저 빈 내부 클래스를 정의한 다음 "기존 클래스 사용"을 선택하고 새로 생성 된 (내부 클래스 ) "리팩터링"을 누르십시오.

추신! "생성자를 빌더로 교체"리팩토링 기능을 사용하려면 커서가 생성자 (미리 작성된) 내에 있어야합니다.


이러한 플러그인이 빌더 패턴의 중요한 부분을 잊어 버린다는 것은 흥미 롭습니다. 생성자에서 필수 매개 변수를 정의해야합니다. 그렇지 않으면 누락 된 매개 변수 오류를 정적으로 포착하는 것에서 런타임에만 포착하는 것으로 이동했습니다.
EJ Campbell

@EJCampbell 그것은 빌더를 사용하는 목적 중 하나 를 무력화시킬 입니다. 이것은 필요한 경우에도 매개 변수에 이름을 첨부하는 방법을 제공하여 코드를 더 읽기 쉽게 만드는 것입니다. 이것은 생성자가 상당히 많은 수의 매개 변수를 취할 때 도움이됩니다. Java가 C # 및 Swift와 같이 호출에서 실제 매개 변수의 이름을 지정하도록 허용했다면 필요하지 않습니다.
AJB

5

이에 대한 IntelliJ 방식은 IMHO입니다. 목적을 훨씬 더 잘 제공하는 두 가지 플러그인 ( https://plugins.jetbrains.com/plugin/7354 )이 있습니다.

예를 들어, 저는 Builder 클래스를 PoJo의 내부 클래스로 사용하는 것을 선호합니다. IntelliJ로이를 달성하려면 몇 번의 추가 스트로크가 필요합니다.

플러그인의 또 다른 장점은 Generate...컨텍스트 메뉴 에서 기능의 위치입니다 .


4

롬복은 가장 쉬운 방법입니다! ( https://plugins.jetbrains.com/plugin/6317-lombok-plugin 구문 지원을위한 Intellij 플러그인이 있습니다. )

@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


lombok은 추가 단계가있는 코드 생성입니다. 이 때문에 많은 정적 분석 도구가 혼란 스럽습니다. 왜냐하면 그들이 읽은 최종 코드가 java처럼 보이지 않기 때문입니다.
ThisCompSciGuy

2

제 생각에는 별도의 클래스 대신 내부 정적 클래스를 얻는 가장 간단한 방법은 다음과 같습니다.

  1. 아직 생성자가없는 경우 생성자 생성 대화 상자를 사용하여 생성하십시오.
  2. 그런 다음 생성자를 빌더로 대체를 사용 하십시오.
  3. Move 리팩토링 (핫키 : F6)을 사용하여 새로 생성 된 클래스를 초기 클래스로 다시 이동합니다 .

1
이 플러그인은 단지 하나의 단계에서 정확히이를 것으로 보인다 : plugins.jetbrains.com/plugin/7354-innerbuilder
jivimberg

0

@CrazyCoder의 답변을 보완하기 위해 생성자를 빌더바꾸기 대화 상자 의 오른쪽 상단에 setter의 접두사 이름을 바꾸는 데 사용할 수있는 구성 버튼이 있다는 것을 아는 것이 매우 유용하다고 생각합니다 .


0

"너무 많은 매개 변수"를 빌더 패턴으로 바꾸고 싶은 사람들은 "매개 변수 객체 추출"을 수행 한 다음 생성자를 다른 답변에서 언급 한 빌더로 변환하십시오.


0

클래스 생성> 생성자를 마우스 오른쪽 버튼으로 클릭하여 클래스 생성자를 생성합니다. 그런 다음 Windows에서 Ctrl + Shift + A를 눌러 작업을 찾고 "빌더"를 입력하고 "생성자를 빌더로 대체"를 선택합니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.