programing

불변 유형 : 공개 최종 필드 대 게터

projobs 2021. 1. 19. 22:04
반응형

불변 유형 : 공개 최종 필드 대 게터


불변 해야하는 일부 문자열을 저장하려면 작은 컨테이너 클래스가 필요합니다. String 자체는 변경 불가능한 유형이므로 다음과 같이 생각했습니다.

public final class Immu
{
  public final String foo;
  public final String bar;

  public Immu(final String foo, final String bar)
  {
    this.foo = foo;
    this.bar = bar;
  }
}

많은 사람들이 공개 필드 사용에 반대하고 대신 Getter를 사용하는 것 같습니다. IMHO 이것은 String 자체가 변경 불가능하기 때문에이 경우 상용구 일 것입니다.

이것에 대해 내가 놓칠 수있는 다른 생각?


나는 당신이 가장 간단하고 명확하다고 믿는 것을 할 것입니다. 제한된 수의 클래스에서만 사용되는 데이터 값 클래스가있는 경우. 특히 패키지 로컬 클래스입니다. 그런 다음 getter / setter를 피하고 패키지 로컬 또는 공용 필드를 사용합니다.

다른 모듈 / 개발자가 사용할 것으로 예상하는 클래스가있는 경우 getter / setter 모델을 따르는 것이 장기적으로 더 안전한 접근 방식 일 수 있습니다.


문제는 균일 한 액세스 원칙입니다. 나중에 수정 foo하는 대신 메서드를 통해 가져 오도록 수정해야 할 수 있으며, getter 대신 필드를 노출 한 경우 API를 중단해야합니다.


이 대답은 생략됩니다.

왜 안돼

interface Immu { String getA() ; String getB ( ) }

Immu immu ( final String a , final String b )
{
       /* validation of a and b */
       return new Immu ( )
       {
              public String getA ( ) { return a ; }

              public String getB ( ) { return b ; }
       }
}

필요한 경우 equals (), hashCode (), toString () 등과 같은 절대 기본 사항과 함께 기본적으로 생성자가있는 변경 불가능한 데이터 구조 인 클래스에 대해 홈 프로젝트에서 public-final-field (anti?) 패턴을 사용합니다. . (나는 다양한 언어 해석 때문에 "struct"라는 단어를 피하고 있습니다.)

다른 코드와 일치하지 않을 가능성이 높고 When In Rome 또는 Least Surprise와 같은 원칙이 우선하기 때문에 다른 사람의 코드베이스 (작업, 공개 프로젝트 등)에이 접근 방식을 적용하지 않을 것입니다.

즉, Daniel C. Sobral과 aioobe의 답변과 관련하여 예상치 못한 개발로 인해 클래스 디자인이 문제가되는 경우 IDE에서 필드를 사유화하고 접근자를 추가하는 것이 30 초의 작업입니다. 수백 개의 참조가없는 한 끊어진 참조를 수정하는 데 5 ~ 10 분 이상 걸립니다. 결과적으로 실패한 모든 것은 처음에 있어야했던 단위 테스트를받습니다. :-)

[편집 : 효과적인 Java는 변경 불가능한 필드에서 "덜 해롭다"는 점을 지적하면서이 아이디어에 상당히 반대합니다.]


나는이 스레드가 실제 주장을 희망하는 것을 찾았지만 여기에서 본 답변은 그다지 도움이되지 않았습니다. 좀 더 연구하고 생각한 후에 다음을 고려해야한다고 생각합니다.

  • public final 불변 유형에 대해 가장 깨끗해 보입니다.
  • 변경 가능한 유형은 의도하지 않은 경우에도 접근 자에 의해 변경 될 수 있습니다. 동시 환경에서는 많은 골칫거리가 될 수 있습니다.
  • 인수가없는 생성자는있을 수 없습니다. 이는 공장 방법 (예 : LMAX Disruptor)이 필요한 경우 중요합니다. 비슷한 방식으로 리플렉션을 통해 개체를 인스턴스화하는 것이 더 복잡해집니다.
  • 게터와 세터는 부작용이있을 수 있습니다. 를 사용 public final하면 프로그래머에게 숨겨진 마법이 발생하지 않으며 객체가 본질적으로 멍청하다는 것을 분명히 알 수 있습니다. :)
  • 접근 자에게 래퍼 또는 파생 클래스 인스턴스를 반환 할 수 없습니다. 다시 말하지만 이것은 필드에 값이 할당 될 때 알아야 할 사항입니다. 제 생각에 컨테이너 클래스는 누구에게 무엇을 돌려 줄지에 대해 걱정해서는 안됩니다.

개발 중이고 가이드 라인이없고 프로젝트가 격리되어 있거나 관련된 모든 프로젝트를 제어 할 수있는 public final경우 불변 유형에 사용 하는 것이 좋습니다 . 나중에 getter가 필요하다고 결정하면 Eclipse는 자동으로 생성하고 필드에 대한 모든 참조를 조정하는 Refactor-> Encapsulate Field...제공 합니다.


누군가가 API를 통해 코드를 사용할 것인지는 명확하지 않습니다. 또한 나중에 필요할 경우 입력을 검증 할 기회가 없습니다.


캡슐화, 불변성, 최적화 및 기타 모든 큰 단어는 잊으십시오. 좋은 자바 코드를 작성하려는 경우 자바 친화적이기 때문에 단순히 getter를 사용하는 것이 좋습니다. 가장 중요한 것은 인터넷 검색에 많은 시간을 절약한다는 것입니다.

For example, you probably would not expect using streams when you write the code, but later you found

listOfImmus.stream().map(immu -> imm.foo).collect(Collectors.toSet()); // with field
listOfImmus.stream().map(Immu::getFoo).collect(Collectors.toSet());    // with getter

Supplier<String> s = () -> immu.foo;  // with field
Supplier<String> s = immu::foo; // with getter

// final fields are hard to mock if not impossible. 
Mockito.when(immuMock.getFoo()).thenReturn("what ever");

//one day, your code is used in a java Beans which requires setter getter..
¯\_(ツ)_/¯

This list can be long or short or may be none of them makes any sense to your use case. But you have to spend time convincing yourself (or your code reviewers) why you can or should rebel against java orthodoxy.

It is better to just write the getter/setter and spent the time for something more useful: like complaining java

ReferenceURL : https://stackoverflow.com/questions/6927763/immutable-type-public-final-fields-vs-getter

반응형