[design-patterns] IntelliJ에서 빌더 패턴 코드 생성

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



답변

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

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


답변

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


답변

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이 설명 하는 내부 빌더 클래스를 사용하여 클래스를 생성하는 데 사용할 수 있는지 궁금하다면 먼저 빈 내부 클래스를 정의한 다음 “기존 클래스 사용”을 선택하고 새로 생성 된 (내부 클래스 ) “리팩터링”을 누르십시오.

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


답변

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

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

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


답변

롬복은 가장 쉬운 방법입니다! ( 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


답변

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

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