[java] 자바에서 명명 된 매개 변수 관용구

Java에서 Named Parameter 관용구를 구현하는 방법은 무엇입니까? (특히 생성자)

JavaBeans에서 사용되는 구문이 아닌 Objective-C와 같은 구문을 찾고 있습니다.

작은 코드 예제가 좋습니다.

감사.



답변

생성자에서 키워드 인수를 시뮬레이션하기 위해 내가 본 최고의 Java 관용구는 Effective Java 2nd Edition에 설명 된 Builder 패턴 입니다.

기본 아이디어는 다른 생성자 매개 변수에 대한 setter (일반적으로 getter가 아님)가있는 Builder 클래스를 갖는 것입니다. 도있다 build()방법. Builder 클래스는 빌드하는 데 사용되는 클래스의 (정적) 중첩 클래스 인 경우가 많습니다. 외부 클래스의 생성자는 종종 비공개입니다.

최종 결과는 다음과 같습니다.

public class Foo {
  public static class Builder {
    public Foo build() {
      return new Foo(this);
    }

    public Builder setSize(int size) {
      this.size = size;
      return this;
    }

    public Builder setColor(Color color) {
      this.color = color;
      return this;
    }

    public Builder setName(String name) {
      this.name = name;
      return this;
    }

    // you can set defaults for these here
    private int size;
    private Color color;
    private String name;
  }

  public static Builder builder() {
      return new Builder();
  }

  private Foo(Builder builder) {
    size = builder.size;
    color = builder.color;
    name = builder.name;
  }

  private final int size;
  private final Color color;
  private final String name;

  // The rest of Foo goes here...
}

Foo의 인스턴스를 만들려면 다음과 같이 작성합니다.

Foo foo = Foo.builder()
    .setColor(red)
    .setName("Fred")
    .setSize(42)
    .build();

주요주의 사항은 다음과 같습니다.

  1. 패턴 설정은 매우 장황합니다 (보시다시피). 많은 곳에서 인스턴스화하려는 클래스를 제외하고는 그만한 가치가 없을 것입니다.
  2. 모든 매개 변수가 정확히 한 번 지정되었는지 컴파일 타임 검사가 없습니다. 런타임 검사를 추가하거나 선택적 매개 변수에만 이것을 사용하고 필수 매개 변수를 Foo 또는 Builder의 생성자에 일반 매개 변수로 만들 수 있습니다. (사람들은 일반적으로 동일한 매개 변수가 여러 번 설정되는 경우에 대해 걱정하지 않습니다.)

이 블로그 게시물 (내가 아님) 도 확인하실 수 있습니다 .


답변

이것은 언급 할 가치가 있습니다.

Foo foo = new Foo() {{
    color = red;
    name = "Fred";
    size = 42;
}};

소위 이중 중괄호 이니셜 라이저 . 실제로 인스턴스 이니셜 라이저가있는 익명 클래스입니다.


답변

여기에서 조언을 따를 수도 있습니다 :
http://www.artima.com/weblogs/viewpost.jsp?thread=118828

int value; int location; boolean overwrite;
doIt(value=13, location=47, overwrite=true);

호출 사이트에서는 장황하지만 전반적으로 오버 헤드가 가장 낮습니다.


답변

자바 8 스타일 :

public class Person {
    String name;
    int age;

    private Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    static PersonWaitingForName create() {
        return name -> age -> new Person(name, age);
    }

    static interface PersonWaitingForName {
        PersonWaitingForAge name(String name);
    }

    static interface PersonWaitingForAge {
        Person age(int age);
    }

    public static void main(String[] args) {

        Person charlotte = Person.create()
            .name("Charlotte")
            .age(25);

    }
}
  • 명명 된 매개 변수
  • 인수 순서 수정
  • 정적 검사-> 이름없는 사람이 불가능합니다.
  • 같은 유형의 인수를 우연히 전환하기가 어렵습니다 (텔레 스코프 생성자에서 가능한 것처럼)


답변

Java는 생성자 또는 메소드 인수에 대해 Objective-C와 유사한 명명 된 매개 변수를 지원하지 않습니다. 게다가 이것은 실제로 Java 방식이 아닙니다. Java에서 일반적인 패턴은 자세한 이름이 지정된 클래스 및 멤버입니다. 클래스와 변수는 명사 여야하고 명명 된 메서드는 동사 여야합니다. 나는 당신이 창의력을 발휘하고 Java 명명 규칙에서 벗어날 수 있고 해키 방식으로 Objective-C 패러다임을 에뮬레이션 할 수 있다고 생각하지만 이것은 코드 유지 관리를 담당하는 평균 Java 개발자가 특별히 높이 평가하지 않을 것입니다. 어떤 언어로 작업 할 때 특히 팀에서 작업 할 때 언어 및 커뮤니티의 관습을 고수해야합니다.


답변

Java 6을 사용하는 경우 변수 매개 변수를 사용하고 정적을 가져 와서 훨씬 더 나은 결과를 생성 할 수 있습니다. 이에 대한 자세한 내용은 다음에서 찾을 수 있습니다.

http://zinzel.blogspot.com/2010/07/creating-methods-with-named-parameters.html

요컨대, 다음과 같은 것을 가질 수 있습니다.

go();
go(min(0));
go(min(0), max(100));
go(max(100), min(0));
go(prompt("Enter a value"), min(0), max(100));


답변

이 스타일은 다른 언어에있는 getset 접두사 없이 명명 된 매개 변수속성 기능을 모두 처리한다는 점을 지적하고 싶습니다 . Java 영역에서는 일반적이지 않지만 특히 다른 언어를 처리 한 경우 이해하기 어렵지 않고 더 간단합니다.

public class Person {
   String name;
   int age;

   // name property
   // getter
   public String name() { return name; }

   // setter
   public Person name(String val)  {
    name = val;
    return this;
   }

   // age property
   // getter
   public int age() { return age; }

   // setter
   public Person age(int val) {
     age = val;
     return this;
   }

   public static void main(String[] args) {

      // Addresses named parameter

      Person jacobi = new Person().name("Jacobi").age(3);

      // Addresses property style

      println(jacobi.name());
      println(jacobi.age());

      //...

      jacobi.name("Lemuel Jacobi");
      jacobi.age(4);

      println(jacobi.name());
      println(jacobi.age());
   }
}