개인 게터가 아닌 공개 결선 사용


51

불변의 POJO는 다음과 같이 작성되었습니다.

public class MyObject {
    private final String foo;
    private final int bar;

    public MyObject(String foo, int bar) {
        this.foo = foo;
        this.bar = bar;
    }

    public String getFoo() {
        return foo;
    }

    public int getBar() {
        return bar;
    }
}

그러나 나는 이것을 다음과 같이 쓰는 경향이 있습니다.

public class MyObject {
    public final String foo;
    public final int bar;

    public MyObject(String foo, int bar) {
        this.foo = foo;
        this.bar = bar;
    }
}

참조는 최종적이므로 Object는 여전히 불변입니다. 더 적은 코드를 작성하고 더 짧은 (5 자 : getand and ()) 액세스를 허용합니다.

내가 볼 수있는 유일한 단점은 getFoo()미친 짓을하기 위해 길 아래로 구현을 변경하려는 경우 할 수 없다는 것입니다. 그러나 현실적으로 이것은 Object가 불변이기 때문에 발생하지 않습니다. 당신은 인스턴스화 중에 확인 (구아바의 참조 인스턴스화하는 동안 불변의 방어 복사본을 만들 수 있습니다 ImmutableList예를 들어), 그리고 얻을 foo또는 bar준비 개체를 get호출.

내가 놓친 단점이 있습니까?

편집하다

필자가 놓친 또 다른 단점은 getor로 시작하는 메소드에 대한 리플렉션을 사용하는 직렬화 라이브러리라고 생각 is하지만 꽤 끔찍한 사례입니다 ...


도대체? final변수를 객체를 불변으로 만들지 않습니다. 나는 일반적으로 final콜백이 해당 필드에 액세스 할 수 있도록 콜백을 만들기 전에 필드를 정의하는 디자인을 사용 합니다. 물론 모든 메소드를 포함한 모든 메소드를 호출 할 수 있습니다 setX.
Tomáš Zato

@ TomášZato가에 더 setX 방법 없다 String, int또는 MyObject. 첫 번째 버전에서는 final클래스 내의 생성자 이외의 메서드 bar = 7;가 예를 들어 시도하지 않도록하는 것 입니다. 두 번째 버전에서는 final소비자가 다음을 수행하지 못하도록해야합니다 MyObject x = new MyObject("hi", 5); x.bar = 7;..
코리 켄달

1
"귀하 의 참조는 최종적인 것이므로 Object여전히 불변입니다. "는 오해의 소지가 있습니다 final Object. 오해해서 죄송합니다.
Tomáš Zato

3
기본 값을 변경할 수있는 경우 private + accessors 도로는이를 막지 못합니다 — myObj.getFoo().setFrob(...).
베니 체르니 아프 스키 파 스킨

답변:


38

내가 생각할 수있는 네 가지 단점 :

  1. 동일한 엔터티의 읽기 전용 및 변경 가능한 형식을 원한다면 공통적 인 패턴은 보호 된 멤버 변수가있는 접근 자만 노출하는 변경 불가능한 클래스 Entity를 갖는 다음이를 확장하고 setter를 추가하는 MutableEntity를 만드는 것입니다. 귀하의 버전은 그것을 방지합니다.
  2. getter 및 setter 사용은 JavaBeans 규칙을 준수합니다. JSTL이나 EL과 같은 속성 기반 기술에서 빈으로 클래스를 사용하려면 공개 게터를 노출해야합니다.
  3. 구현을 변경하여 값을 파생 시키거나 데이터베이스에서 찾아 보려면 클라이언트 코드를 리팩터링해야합니다. 접근 자 / 돌연변이 방식을 사용하면 구현 만 변경할 수 있습니다.
  4. 최소한 놀랍게도-공개 인스턴스 변수를 볼 때 누가 변수를 변경하고 있는지 즉시 찾아 캡슐화가 손실되어 판도라 상자를 열지 않을까 걱정합니다. http://en.wikipedia.org/wiki/Principle_of_least_astonishment

즉, 귀하의 버전은 확실히 더 간결합니다. 이것이 특정 패키지 내에서만 사용되는 특수 클래스 (패키지 범위가 여기에 좋은 아이디어 일 수 있음)라면 일회성으로 이것을 고려할 수 있습니다. 그러나 나는 이와 같은 주요 API를 노출시키지 않을 것입니다.


3
큰 답변; 나는 그들 중 일부와 의견이 맞지 않지만이 사이트가 토론을위한 최고의 포럼인지 잘 모르겠습니다. 요컨대, 1) 변경 불가능한 것으로 간주되는 변경 가능한 양식을 사용하여 다른 사람들을 깨뜨릴 수 있습니다 (아마도 필자는 예제에서 클래스에 마지막을 추가해야합니다), 2) 동의합니다 .3) 더 이상 POJO가 아니라고 주장합니다. 경우, 4) 나는 지금 동의하지만, 이것과 같은 토론이 가장 놀라운 것을 바꿀 수 있습니다 :).
코리 켄달

2
5) 배열과 같이 본질적으로 변경 가능한 클래스 / 유형을 안전하게 노출 할 수 없습니다. 안전한 방법은 매번 게터에서 사본을 반환하는 것입니다.
Clockwork-Muse

사람들이 바보가 아니라고 생각한다면 @ Clockwork-Muse를 할 수 있습니다. someObj.thisList.add ()에 액세스 할 때 다른 객체 상태를 수정하고 있음이 분명합니다. someObj.getThisList (). add ()를 사용하면 알 수 없습니다. 문서를 요청하거나 소스를 찾아야하지만 메소드 선언만으로는 말할 수 없습니다.
kritzikratzi

2
@ kritzikratzi-문제는 코드가 바보에 빠질 것이라고 보장 할 수 없다는 것입니다. 어떤 점에서 그것은 (심지어! 자신을 끝나게 수 있음), 그리고 놀라운 큰 문제가 될 수 있습니다.
Clockwork-Muse

1
음, 변경 가능한 유형을 변경 불가능한 유형에서 상속 하게 하는 것은 본질적으로 잘못되었습니다. 불변의 타입은 "나는 변하지 않는다.
중복 제거기

26

게터 / 세터도 제거하면 괜찮습니다!

이것은 Java 프로그래머들 사이에서 논란의 여지가 많은 주제입니다.

어쨌든 getters / setters 대신 공용 변수를 사용하는 두 가지 상황이 있습니다.

  1. public final 나에게 이것은 게터보다 "나는 변하지 않는다"는 신호를 보낸다. 대부분의 IDE는 자동 완성 동안 최종 수정자를 'F'로 표시합니다. getter / setter와 달리 setXXX가 없는지 검색해야합니다.
  2. 공개 비 최종 데이터 클래스에 이것을 좋아합니다. 모든 필드를 공개적으로 공개합니다. 게터, 세터, 생성자가 없습니다. 더 아무것도. 포조보다 작습니다. 나에게 이것은 즉시 "이것은 바보입니다. 나는 데이터를 보유하고 있습니다. 그게 전부입니다. 올바른 데이터를 내 안에 두는 것이 당신의 임무입니다". Gson / JAXB / 등 이 클래스를 잘 처리하십시오. 그들은 쓰는 행복입니다. 그들의 목적이나 능력에 대해서는 의심의 여지가 없습니다. 가장 중요한 것은 변수를 변경할 때 부작용이 없다는 것입니다. IMHO는 모호성이 거의없는 매우 간결한 데이터 모델을 만들어내는 반면, 게터와 세터는 가끔 마법이 발생하는 큰 문제가 있습니다.

5
한 번에 약간의 정신을 보니 반갑습니다 :)
Navin

2
하루가지나면서 모델이 발전하고 이전 필드 중 하나가 다른 필드에서 파생 될 수 있습니다. 이전 버전과의 호환성을 유지하려면 이전 필드는 그대로 유지해야하지만 getter 및 setter 코드를 변경하는 대신이 이전 필드를 사용하여 다른 위치에서 새 모델 표현을 따르도록 변경해야합니다. 쓰기 쉽다. 그렇다. 확실히 ... 장기적으로 유지해야 할 악몽 ... 이것이 C # 속성 접근 자에 여전히 getter / setter 또는 더 나은 이유이다.
Newtopian

9

평신도의 말로 :

  • 몇 줄의 코드를 저장하기 위해 캡슐화위반 합니다. OOD의 목적을 무너 뜨립니다.
  • 클라이언트 코드가됩니다 하드 결합 반원의 이름으로. 커플 링이 나쁘다. OOD의 전체 목적은 커플 링을 방지하는 것입니다.
  • 또한 클래스가 변경 될 필요가 없다는 것을 확신 합니다. 모든것은 변한다. 변화는 변하지 않는 유일한 것입니다.

6
이것이 어떻게 캡슐화 위반입니까? 두 버전 모두 서로처럼 외부 환경에 노출됩니다 (읽기 전용 액세스 가능). 그러나 어려운 결합과 변화의 유연성에 대해서는 맞습니다.
KChaloux

4
@KChaloux "캡슐화 위반"을 "컴파일 실패 및 수정에 시간을 낭비해야 함"과 혼동하면 먼저 발생합니다. 두 번째는 나중에 발생합니다. 명확히하기 위해 : 현재 캡슐화가 이미 위반되었습니다. 현재 클래스의 내부는 더 이상 캡슐화되지 않습니다. 그러나 미래에 클래스가 변경되면 클라이언트 코드가 나중에 중단됩니다. 과거에 캡슐화가 중단 되었기 때문입니다. 캡슐화가 없기 때문에 오늘 캡슐화, 내일 클라이언트 코드라는 두 가지 "중단"이 있습니다.
Tulains Córdova

8
기술적으로 getters / etc를 사용할 때. 클라이언트 코드는 대신 메소드 이름에 하드 결합됩니다. 오래된 코드가 여전히 의존하기 때문에 "더 이상 사용되지 않는"태그 / 주석이있는 이전 버전의 메소드를 포함해야하는 라이브러리 수를 살펴보십시오. 그렇게해야합니다).
JAB

5
실용적 : 프로그래머는 공개 게터 / 세터의 이름을 바꾸지 않고 개인 필드 이름을 실제로 얼마나 자주 리팩터링합니까? 내가 알 수 있듯이, 필드 이름에서 getter 및 setter를 생성하는 IDE 도구의 결과 만 해당 컨벤션에 해당되는 경우에도 커뮤니티 전체에 동일한 이름을 지정하는 컨벤션이 있습니다. 이론 : 그러나 객체 지향 모델링 관점에서 볼 때, 공개 는 내부 구현 세부 사항이 아니라 공개 계약의 일부입니다. 누군가가 최종 현장을 공개하기로 결정했다면 이것이 계약을 이행하겠다고 약속 한 것이 아닙니까?
Thomas Jung

3
@ user949300 배울 수 있도록 알려주십시오.
Tulains Córdova

6

내가 손에 넣을 수있는 한 가지 가능한 단점은 클래스의 데이터의 내부 표현과 관련이 있다는 것입니다. 이것은 아마도 큰 문제는 아니지만 setter를 사용하고 다른 곳에서 정의 된 다른 클래스에서 foo와 bar가 반환되도록 결정하면 MyObject를 소비하는 클래스를 변경할 필요가 없습니다. MyObject 만 터치하면됩니다. 그러나 나체 값을 사용하는 경우 MyObject에서 사용한 모든 곳을 터치해야합니다.

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