이 질문은 Hibernate Annotation Placement Question 과 다소 관련이 있습니다.
그러나 나는 어느 것이 더 좋은지 알고 싶습니다 . 속성을 통한 액세스 또는 필드를 통한 액세스? 각각의 장단점은 무엇입니까?
답변
필요할 때마다 접근 자에 비즈니스 로직을 추가 할 수 있기 때문에 접근자를 선호합니다. 예를 들면 다음과 같습니다.
@Entity
public class Person {
@Column("nickName")
public String getNickName(){
if(this.name != null) return generateFunnyNick(this.name);
else return "John Doe";
}
}
또한 다른 JSON을 믹스에 던지면 (예 : JSON 변환 lib 또는 BeanMapper 또는 Dozer 또는 getter / setter 속성을 기반으로하는 다른 bean 매핑 / 복제 라이브러리와 같이) lib가 지속성과 동기화되어 있음을 보장합니다 관리자 (둘 다 getter / setter를 사용하십시오).
답변
두 가지 모두에 대한 논거가 있지만 대부분의 사용자 요구 사항은 “논리를 추가해야하는 경우”또는 “xxxx가 캡슐화를 중단합니다”라는 특정 사용자 요구 사항에서 비롯됩니다. 그러나 아무도 이론에 대해 실제로 의견을 말하지 않았으며 합리적으로 합리적인 주장을 제시했습니다.
Hibernate / JPA는 객체를 유지할 때 실제로하는 일-객체의 상태를 유지합니다. 즉, 쉽게 재현 할 수있는 방식으로 보관해야합니다.
캡슐화 란 무엇입니까? 캡슐화는 응용 프로그램 / 클라이언트가 데이터에 안전하게 액세스하는 데 사용할 수있는 인터페이스로 데이터 (또는 상태)를 캡슐화하여 일관성 있고 유효하게 유지하는 것을 의미합니다.
이것을 MS Word와 같이 생각하십시오. MS Word는 문서 모델을 메모리에 저장합니다 (문서 상태). 버튼, 도구, 키보드 명령 등 사용자가 문서를 수정하는 데 사용할 수있는 인터페이스를 제공합니다. 그러나 해당 문서를 유지 (저장)하도록 선택하면 키 누르기 세트가 아닌 내부 상태가 저장됩니다. 마우스 클릭으로 생성됩니다.
객체의 내부 상태를 저장하면 캡슐화가 중단되지 않습니다. 그렇지 않으면 캡슐화의 의미와 그 이유를 실제로 이해하지 못합니다. 그것은 실제로 객체 직렬화와 같습니다.
이러한 이유로, 대부분의 경우, 액세서가 아닌 필드를 유지하는 것이 적절합니다. 이는 객체가 저장된 방식대로 데이터베이스에서 객체를 정확하게 재생성 할 수 있음을 의미합니다. 원본을 만들 때와 데이터베이스에 저장하기 전에 원본에서 수행되었으므로 유효성 검사가 필요하지 않습니다 (하나님이 금지하지 않는 한 DB에 잘못된 데이터를 저장하고 있습니다! 마찬가지로 객체가 저장되기 전에 이미 계산되었으므로 값을 계산할 필요가 없습니다. 오브젝트는 오브젝트가 저장되기 전에 수행 된 방식대로 보여야합니다. 실제로 게터 / 세터에 추가 항목을 추가하면 실제로 원본의 정확한 사본이 아닌 것을 다시 만들 위험이 높아 집니다.
물론이 기능은 이유로 추가되었습니다. 접근자를 유지하기위한 유효한 사용 사례가있을 수 있지만 일반적으로 드물게 나타납니다. 예를 들어 계산 된 값을 유지하지 않으려는 경우가 있지만 값의 getter에서 요청시 값을 계산하지 않는 이유를 질문하거나 게터에서 게으르게 초기화하는 것이 좋습니다. 개인적으로 나는 어떤 유스 케이스도 생각할 수 없으며, 여기에 대한 답변 중 “소프트웨어 엔지니어링”답변은 없습니다.
답변
각 속성에 대해 getter / setter를 제공하지 않아도되므로 필드 액세스를 선호합니다.
Google을 통한 빠른 설문 조사에 따르면 필드 액세스가 대부분 (예 : http://java.dzone.com/tips/12-feb-jpa-20-why-accesstype )이라고합니다.
필드 액세스는 Spring에서 권장하는 관용구라고 생각하지만 백업을위한 참조를 찾을 수 없습니다.
거기에 성능을 측정하려고 시도하고 “차이가 없다”는 결론에 도달 관련 SO 질문 이 있습니다.
답변
속성 접근자를 사용하는 상황이 있습니다. 8 개의 구체적인 서브 클래스로 상속 할 수있는 구현의 장점이 많은 GENERIC 추상 클래스가 있다고 상상해보십시오.
public abstract class Foo<T extends Bar> {
T oneThing;
T anotherThing;
// getters and setters ommited for brevity
// Lots and lots of implementation regarding oneThing and anotherThing here
}
이제이 클래스에 어떻게 주석을 달아야합니까? 답은이 시점에서 대상 엔터티를 지정할 수 없으므로 필드 또는 속성 액세스로 주석을 달 수 없습니다. 구체적인 구현에 주석을 달아야합니다. 그러나 지속 속성이이 슈퍼 클래스에 선언되어 있으므로 서브 클래스에서 속성 액세스를 사용해야합니다.
필드 액세스는 추상 일반 슈퍼 클래스가있는 응용 프로그램의 옵션이 아닙니다.
답변
나는 속성 접근자를 선호하고 사용하는 경향이 있습니다.
- 필요한 경우 (허용 된 답변에 언급 된대로) 논리를 추가 할 수 있습니다.
foo.getId()
프록시를 초기화하지 않고 전화를 걸 수 있습니다 ( HHH-3718 이 해결 될 때까지 최대 절전 모드를 사용할 때 중요합니다 ).
약점:
- 코드를 읽기 쉽도록 만듭니다. 예를 들어, 전체 클래스를 탐색하여
@Transient
주변에 있는지 확인해야합니다.
답변
실제로는 특정한 경우에 따라 다릅니다. 두 가지 옵션을 모두 사용할 수 있습니다. IMO는 세 가지 사례로 요약됩니다.
- setter에는 데이터베이스에서 인스턴스를로드 할 때 실행해서는 안되는 몇 가지 논리가 있습니다. 예를 들어, 일부 값 유효성 검사는 setter에서 발생하지만 db에서 오는 데이터는 유효해야합니다 (그렇지 않으면 도달하지 못함 (:);이 경우 필드 액세스가 가장 적합합니다).
- setter에는 db에서 인스턴스를로드하는 동안에도 항상 호출해야하는 로직이 있습니다. 예를 들어, 초기화되는 속성은 계산 된 일부 필드의 계산에 사용됩니다 (예 : 속성-화폐 금액, 계산 된 속성-동일한 인스턴스의 총 여러 통화 속성). 이 경우 속성 액세스가 필요합니다.
- 위의 경우 중 어느 것도 해당되지 않습니다-두 옵션 모두 적용 가능합니다. 일관성을 유지하십시오 (이 상황에서 필드 액세스가 선택되면 비슷한 상황에서 항상 사용하십시오).
답변
값을 설정하는 것 (예 : 암호화 또는 계산)보다 세터에서 더 많은 작업을 수행하려는 경우 게터에 대한 필드 액세스 및 NOT 주석 (프로퍼티 액세스)을 강력히 권장합니다.
속성 액세스의 문제점은 객체가로드 될 때 setter도 호출된다는 것입니다. 이것은 우리가 암호화를 도입하고 싶을 때까지 몇 달 동안 나에게 잘 작동했습니다. 우리의 유스 케이스에서는 setter에서 필드를 암호화하고 getter에서 필드를 해독하려고했습니다. 속성 액세스의 문제는 Hibernate가 객체를로드 할 때 필드를 채우기 위해 setter를 호출하여 암호화 된 값을 다시 암호화한다는 것입니다. 이 포스트는 또한 이것을 언급합니다 :
Java Hibernate : 그것을 호출하는 사람에 따라 다른 속성 세트 함수 동작
필드 액세스와 속성 액세스의 차이점을 기억하기 전까지는 두통이 발생했습니다. 이제 모든 주석을 속성 액세스에서 필드 액세스로 옮겼으며 이제 제대로 작동합니다.