태그 보관물: design-patterns

design-patterns

세터가 “this”를 반환하는 것은 나쁜 습관입니까? return this; } 이 패턴은 다음과

자바의 setter가 “this”를 반환하게하는 것이 좋은 생각입니까?

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

이 패턴은 다음과 같이 setter를 연결할 수 있기 때문에 유용 할 수 있습니다.

list.add(new Employee().setName("Jack Sparrow").setId(1).setFoo("bacon!"));

이 대신에 :

Employee e = new Employee();
e.setName("Jack Sparrow");
...and so on...
list.add(e);

…하지만 일종의 표준 규칙에 위배됩니다. 세터가 다른 것을 유용하게 만들 수 있기 때문에 가치가 있다고 생각합니다. 이 패턴이 JMock, JPA와 같은 일부 장소를 사용하는 것을 보았지만 드물게 보이며 일반적 으로이 패턴이 어디서나 사용되는 매우 잘 정의 된 API에만 사용됩니다.

최신 정보:

내가 설명한 것은 분명히 유효하지만 실제로 찾고있는 것은 이것이 일반적으로 수용 가능한지 여부와 함정이나 관련 모범 사례가 있는지에 대한 생각입니다. 빌더 패턴에 대해 알고 있지만 설명하고있는 것보다 조금 더 관련이 있습니다. Josh Bloch가 설명했듯이 객체 생성을 위해 관련된 정적 빌더 클래스가 있습니다.



답변

나는 그것에 특별히 문제가 있다고 생각하지 않습니다. 그것은 단지 스타일의 문제입니다. 다음과 같은 경우에 유용합니다.

  • 한 번에 많은 필드를 설정해야합니다 (건설시 포함).
  • 코드를 작성할 때 어떤 필드를 설정해야하는지 알고
  • 필드를 설정하려는 여러 가지 조합이 있습니다.

이 방법의 대안은 다음과 같습니다.

  1. 하나의 메가 생성자 (단점 : 많은 null 또는 기본값을 전달할 수 있으며 어떤 값이 무엇에 해당하는지 알기가 어렵습니다)
  2. 오버로드 된 여러 생성자 (단점 : 몇 개 이상 있으면 다루기 힘들다)
  3. 팩토리 / 정적 메소드 (단점 : 오버로드 된 생성자와 동일-몇 개 이상 있으면 다루기 힘들다)

한 번에 몇 가지 속성 만 설정하려는 경우 ‘this’를 반환 할 가치가 없다고 말하고 싶습니다. 나중에 상태 / 성공 표시기 / 메시지와 같은 다른 것을 반환하기로 결정하면 확실히 떨어집니다.


답변

나쁜 습관이 아닙니다. 점점 일반적인 관행입니다. 원하지 않는 경우 대부분의 언어는 반환 된 객체를 처리 할 필요가 없으므로 “일반적인”세터 사용법 구문을 변경하지 않지만 세터를 서로 연결할 수 있습니다.

이것을 일반적으로 빌더 패턴 또는 유창한 인터페이스 라고합니다 .

Java API에서도 일반적입니다.

String s = new StringBuilder().append("testing ").append(1)
  .append(" 2 ").append(3).toString();

답변

요약:

  • 이를 “유창한 인터페이스”또는 “메소드 체인”이라고합니다.
  • 이것은 “표준”Java는 아니지만 요즘 더 많이 볼 수 있지만 (jQuery에서 잘 작동합니다)
  • JavaBean 스펙을 위반하므로 다양한 도구 및 라이브러리, 특히 JSP 빌더 및 Spring과 충돌합니다.
  • JVM이 정상적으로 수행하는 일부 최적화를 방해 할 수 있습니다.
  • 어떤 사람들은 코드를 정리한다고 생각하고 어떤 사람들은 “거대한”생각

언급되지 않은 몇 가지 다른 점 :

  • 이는 각 기능이 한 가지만 수행해야한다는 원칙에 위배됩니다. 이것을 믿거 나 믿지 않을 수도 있지만 Java에서는 잘 작동한다고 생각합니다.

  • IDE는 기본적으로이를 생성하지 않습니다.

  • 마지막으로 여기 실제 데이터 포인트가 있습니다. 이와 같은 라이브러리를 사용하는 데 문제가 있습니다. Hibernate의 쿼리 빌더는 기존 라이브러리에서 이에 대한 예입니다. Query의 set * 메소드가 쿼리를 리턴하므로 서명을 사용하여 사용법을 알려주는 것만으로는 불가능합니다. 예를 들면 다음과 같습니다.

    Query setWhatever(String what);
  • 모호성을 소개합니다 : 메소드가 현재 객체 (패턴)를 수정합니까, 아니면 Query가 실제로 불변 (매우 인기 있고 귀중한 패턴)이며 메소드가 새로운 것을 반환합니다. 라이브러리를 사용하기 어렵게 만들고 많은 프로그래머가이 기능을 이용하지 않습니다. 세터가 세터 인 경우 사용 방법이 더 명확합니다.


답변

나는 이것을 위해 ‘with’방법을 사용하는 것을 선호합니다 :

public String getFoo() { return foo; }
public void setFoo(String foo) { this.foo = foo; }
public Employee withFoo(String foo) {
  setFoo(foo);
  return this;
}

그러므로:

list.add(new Employee().withName("Jack Sparrow")
                       .withId(1)
                       .withFoo("bacon!"));

경고 :이 withX구문은 일반적으로 불변 개체에 “세터”를 제공하는 데 사용되므로 이러한 메서드를 호출하면 기존 인스턴스를 변경하지 않고 새 개체를 만들 것으로 기대할 수 있습니다. 아마도 더 합리적인 표현은 다음과 같습니다.

list.add(new Employee().chainsetName("Jack Sparrow")
                       .chainsetId(1)
                       .chainsetFoo("bacon!"));

chainsetXyz () 명명 규칙을 사용하면 거의 모든 사람이 행복해야합니다.


답변

'this'setter에서 돌아 가지 않고 두 번째 옵션을 사용하지 않으려면 다음 구문을 사용하여 속성을 설정할 수 있습니다.

list.add(new Employee()
{{
    setName("Jack Sparrow");
    setId(1);
    setFoo("bacon!");
}});

제쳐두고 C #에서는 약간 깨끗하다고 ​​생각합니다.

list.Add(new Employee() {
    Name = "Jack Sparrow",
    Id = 1,
    Foo = "bacon!"
});

답변

getter / setter의 관례를 위반할뿐만 아니라 Java 8 메소드 참조 프레임 워크도 손상시킵니다. MyClass::setMyValueA는 BiConsumer<MyClass,MyValue>, 그리고 myInstance::setMyValueA는 Consumer<MyValue>. setter return이있는 경우 this더 이상 유효한 인스턴스가 Consumer<MyValue>아닌의 인스턴스이며 Function<MyValue,MyClass>void 설정이라고 가정하면 해당 setter에 대한 메소드 참조를 사용하는 모든 항목이 중단됩니다.


답변

Java를 모르지만 C ++ 에서이 작업을 수행했습니다. 다른 사람들은 그것이 줄을 정말로 길고 읽기가 어렵게한다고 말했지만, 나는 이것을 여러 번 그렇게했습니다.

list.add(new Employee()
    .setName("Jack Sparrow")
    .setId(1)
    .setFoo("bacon!"));

이것은 더 낫습니다 :

list.add(
    new Employee("Jack Sparrow")
    .Id(1)
    .foo("bacon!"));

적어도 나는 생각합니다. 그러나 당신은 저를 downvote하고 당신이 원한다면 나에게 끔찍한 프로그래머라고 불러도 좋습니다. 그리고 당신이 Java로 이것을 할 수 있는지 모르겠습니다.