JavaBeans 대신 변경 불가능한 POJO를 사용하면 안되는 이유는 무엇입니까?


79

지금까지 몇 가지 Java 응용 프로그램을 구현했지만 지금까지는 데스크톱 응용 프로그램 만 구현했습니다. 나는 JavaBeans라고도 불리는 뮤 테이터 (setters 와 getter )가있는 객체를 사용하는 대신 애플리케이션에서 데이터를 전달하기 위해 불변 객체를 사용하는 것을 선호합니다 .

그러나 Java 세계에서는 JavaBeans를 사용하는 것이 훨씬 더 일반적으로 보이며 대신 JavaBeans를 사용해야하는 이유를 이해할 수 없습니다. 개인적으로 코드는 항상 상태를 변경하는 대신 변경 불가능한 객체 만 처리하면 더 좋아 보입니다.

불변 객체는 Item 15 : Minimize mutability , Effective Java 2ed 에서도 권장됩니다 .

JavaBean으로Person 구현 된 객체가 있으면 다음과 같습니다.

public class Person {
    private String name;
    private Place birthPlace;

    public Person() {}

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

    public setBirthPlace(Place birthPlace) {
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}

불변 객체 Person로 구현 된 것과 동일 합니다.

public class Person {
    private final String name;
    private final Place birthPlace;

    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}

또는 structin C :

public class Person {
    public final String name;
    public final Place birthPlace;

    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }
}

구현 세부 사항을 숨기기 위해 변경 불가능한 개체에 게터를 사용할 수도 있습니다. 그러나 나는 단지 그것을 사용하기 때문에 나는 struct"getters"를 건너 뛰고 그것을 단순하게 유지 하는 것을 선호한다.

간단히 말해, JavaBeans를 사용하는 것이 더 좋은 이유를 이해하지 못합니다. 또는 변경 불가능한 POJO를 계속 사용할 수 있고 계속 사용해야하는 경우

많은 Java 라이브러리가 JavaBeans를 더 잘 지원하는 것처럼 보이지만 변경 불가능한 POJO에 대한 더 많은 지원이 시간이 지남에 따라 더 인기를 얻게 될까요?


1
* 불변성 최소화가 아니라 항목 15 : 가변성 최소화 를 의미한다고 생각합니다 . "
matt b

@matt : 감사합니다 =) 지금 업데이트했습니다.
Jonas

7
불변성 접근 방식은 훌륭하며 많은 스레드 문제를 줄여줍니다. +1
whiskeysierra

1
JPA를 사용하는 경우 기본 생성자가 필요합니다
Neil McGuigan 2013 년

답변:


78

다음 경우에 JavaBeans 선호

  • 기대하는 환경과 상호 작용해야합니다.
  • 인스턴스화시 모든 초기화를 수행하는 것이 불편할 수있는 속성이 많습니다.
  • 어떤 이유로 든 복사하기가 비싸거나 불가능하지만 변형이 필요한 상태가 있습니다.
  • 어떤 시점에서 속성에 액세스하는 방법을 변경해야 할 수도 있다고 생각합니다 (예 : 저장된 값에서 계산 된 값으로 이동, 액세스 권한 부여 등).
  • JavaBeans를 사용하는 것이 "객체 지향적"이라고 생각하지 않고 주장하는 코딩 표준을 따르고 자합니다.

불변 POJO를 선호하는 경우

  • 적은 수의 간단한 속성이 있습니다.
  • JavaBean 규칙을 가정하는 환경과 상호 작용할 필요가 없습니다.
  • 객체를 복제 할 때 상태를 복사하는 것은 쉽습니다 (또는 최소한 가능).
  • 객체를 복제 할 계획이 전혀 없습니다.
  • 위와 같이 속성에 액세스하는 방법을 수정할 필요가 없다고 확신합니다.
  • 코드가 "객체 지향적"이 아닌지에 대한 징징 대는 소리 (또는 비웃음)를 듣는 것도 괜찮습니다.

목록에 +1, 이름에 거의 -1 :) 결국 모든 사람들은 그것이 올바른 의견이라는 것을 압니다 . 물론 모든 사람은 Discworld 감각으로 정의됩니다.
extraneon

12
경계 검사 및 입력 유효성 검사는 생성자에서 수행 할 수 있습니다. 입력이 유효하지 않거나 범위를 벗어난 경우 개체를 만들고 싶지 않습니다.
Jonas

24
bean의 두 번째 요점은 bean이 아니라 Builder 패턴에 유리합니다. 여전히 변경 불가능한 객체를 생성 할 수 있습니다.

4
변경 불가능한 POJO를 사용한 스레딩은 언급하지 않았는데, 이것이 사용하는 가장 큰 이유 중 하나입니다. 또 다른 중요한 항목은 단순성입니다. 객체가 변경되지 않으면 장기적으로 작업하기가 더 쉽습니다. 또한 불변의 POJO를 사용하면 일반적으로 객체 복제에 대해 걱정할 필요가 없으며 그냥 전달할 수 있습니다.
deterb

이러한 개체가 변경되지 않도록 순환 참조가있을 수있는 개체 그래프를 어떻게 작성합니까? 이것이 가능한가? 예를 들어 클래스 A와 B는 변경 불가능하지만 A는 B에 대한 참조가 필요하고 B는 A에 대한 참조가 필요합니다. 이렇게 할 수있는 방법이 있습니까?
chakrit

39

이 토론에서 Thread 라는 단어 가 나오지 않는다는 사실에 놀랐습니다 .

변경 불가능한 클래스의 주요 이점 중 하나는 변경 가능한 공유 상태가 없기 때문에 본질적으로 스레드로부터 더 안전하다는 것입니다.

이렇게하면 코딩이 더 쉬워 질뿐만 아니라 부작용으로 두 가지 성능 이점이 제공됩니다.

  • 동기화가 덜 필요합니다.

  • 최종 변수를 사용할 수있는 더 많은 범위를 제공하여 후속 컴파일러 최적화를 용이하게 할 수 있습니다.

JavaBean 스타일 클래스가 아닌 변경 불가능한 객체로 이동하려고합니다. getter 및 setter를 통해 개체의 내장을 노출하는 것은 아마도 기본 선택이 아닐 것입니다.


18

무엇을하려고하는지에 따라 다릅니다. 영구 계층으로 작업하고 데이터베이스에서 POJO로 일부 행을 가져오고 속성을 변경하고 다시 저장하려는 경우 특히 속성이 많은 경우 JavaBean 스타일을 사용하는 것이 더 좋습니다.

당신의 사람은 이름, 중간, 성, 생년월일, 가족, 교육, 직업, 급여 등과 같은 많은 분야를 가지고 있다고 생각하십시오.

그리고 그 사람은 방금 결혼했고 그녀의 성을 변경하는 것을 수락 한 여성입니다. 그리고 당신은 데이터베이스를 업데이트해야합니다.

변경 불가능한 POJO를 사용하는 경우 그녀를 나타내는 Person 객체를 가져온 다음 변경하지 않은 모든 속성과 새 성을 전달하는 새 Person 객체를 만들고 저장합니다.

Java bean 인 경우 setLastName ()을 수행하고 저장할 수 있습니다.

'변경 가능한 객체를 사용하지 않음'이 아니라 '가변성 최소화'입니다. 일부 상황은 변경 가능한 객체에서 더 잘 작동합니다. 객체를 변경 가능하게 만드는 것이 프로그램에 더 잘 맞는지 여부를 결정하는 것은 실제로 여러분의 임무입니다. 항상 '불변 객체를 사용해야합니다'라고 말해서는 안됩니다. 대신 자신을 다치게하기 전에 불변으로 만들 수있는 클래스 수를 확인하십시오.


1
그러나 귀하의 예는 "실제"응용 프로그램에서 수행해야 할 작업이 거의 없습니다. 일반적으로 업데이트 된 데이터 개체는 유효성 검사 프레임 워크 (Hibernate Validator, Spring Validator 등)에 전달되어야합니다. 여기서 개체는 다른 개발자가 작성할 수있는 다양한 작업을 받게됩니다. 객체가 변경 가능한 경우 전달 된 동일한 데이터로 작업하고 있는지 알 수 없습니다 (사용자가 이전에 실행 한 일부 유효성 검사가 객체를 변경 한 경우). 이는 유효성 검사 프로세스를 덜 결정적이며 엄격한 순서에 더 많이 의존하며 병렬화 할 수 없게 만듭니다.
dsmith

또한 "실제"애플리케이션에는 도메인 개체를 포함하는 일종의 인 메모리 또는 분산 캐시 (EHCache 등)가있을 것입니다. 개체가 변경 불가능하다는 것을 알고 있다면 읽기 중 복사의 오버 헤드를 발생시킬 필요가 없습니다. 캐시 무결성에 대해 걱정하지 않고 메모리 내 개체를 안전하게 검색하고 사용할 수 있습니다. IMHO, 이런 종류의 비즈니스 도메인 개체의 경우 항상 불변 개체를 원합니다. 변경 가능한 객체는 로컬 범위와 여기에 들어갈 문자가없는 몇 가지 다른 특수한 경우에 적합합니다.
dsmith

7

다른 답변을 요약하면 다음과 같습니다.

  • 불변성은 정확성 (구조는 참조로 전달 될 수 있으며 결함이있는 / 악의적 인 클라이언트에 의해 파괴되지 않을 것임을 알 수 있음) 및 코드 단순성을 촉진합니다.
  • Mutability는 동질성을 촉진합니다 . Spring과 다른 프레임 워크는 인수없이 객체를 생성하고 객체 속성을 설정하며 voi là . 또한 데이터를 제공하고 수정 사항을 저장하기 위해 동일한 클래스를 사용하여 인터페이스를 더 쉽게 만듭니다 ( get(id): Clientsave(MutableClient), 클라이언트의 일부 자손 인 MutableClient).

중간 지점 (생성, 속성 설정, 불변으로 만들기)이 있다면 프레임 워크는 더 많은 불변 접근을 권장 할 것입니다.

어쨌든 나는 당신이 좋은 소년이고 위험한 setProperty 메소드를 건드리지 않는다면 모든 것이 괜찮을 것이라는 점을 강조하면서 불변 객체를 "읽기 전용 Java Beans"로 생각하는 것이 좋습니다.


두 세계의 장점은 라이브러리와 프레임 워크가 불변의 접근 방식으로 이동하는 것이라는 데 동의합니다. 불변의 장점은 내재적이지만 가변의 장점은 부수적입니다.
dsmith

3

Java 7에서는 두 세계의 장점 인 불변의 빈을 가질 수 있습니다. 생성자에서 @ConstructorProperties 주석을 사용하십시오.

public class Person {
    private final String name;
    private final Place birthPlace;

    @ConstructorProperties({"name", "birthPlace"})
    public Person(String name, Place birthPlace) {
        this.name = name;
        this.birthPlace = birthPlace;
    }

    public String getName() {
        return name;
    }

    public Place getBirthPlace() {
        return birthPlace;
    }
}


1

솔직히 말해서 불변 객체가 그렇게 인기를 끌 것이라고 생각하지 않습니다.

나는 장점을 알지만, Hibernate와 Spring과 같은 프레임 워크는 현재 매우 유행하고 있고 (그리고 좋은 이유도있다), 그들은 정말로 빈에서 가장 잘 작동한다.

따라서 불변성이 나쁘다고 생각하지 않지만 현재 프레임 워크와의 통합 옵션을 확실히 제한 할 것입니다.

편집 의견은 내 대답을 약간 명확히하라는 메시지를 표시합니다.

불변성이 매우 유용하고 실제로 사용되는 문제 영역이 가장 확실합니다. 하지만 현재의 기본값은 대부분 예상되는대로 변경 가능하며 명확한 이점이있는 경우에만 변경 불가능한 것 같습니다.

그리고 Spring에서 인자와 함께 생성자를 사용하는 것이 실제로 가능하지만 그것은 아름다운 새 Spring 코드와 함께 레거시 및 / 또는 타사 코드를 사용하는 방법으로 의도 된 것 같습니다. 적어도 그것은 내가 문서에서 얻은 것입니다.


2
IoC / DI의 아이디어는 상태 설정 / 주입을 기반으로합니다. 이것이 Spring에서 불변성이 그다지 인기가없는 이유입니다. 그러나 Joda-Time은 불변성의 좋은 예입니다.
lunohodov

생성자 인수를 사용하여 스프링에 종속성을 주입 할 수도 있습니다. 많은 사람들이 그렇게하지 않는 것 같습니다 (아마도 많은 종속성이있을 때 10 개 이상의 매개 변수 생성자를 갖는 것은 무섭기 때문입니다).
Andrei Fierbinteanu

6
@lunohodov : DI / IoC에 Google Guice를 사용했으며 생성자에 종속성 주입을 수행하는 데 문제가 없습니다.
Jonas

일반적으로 데이터가 변경 불가능한 객체에 대한 변경 불가능한 참조 또는 변경 불가능한 객체에 대한 변경 가능한 참조를 사용하여 저장되는 경우 (특히 다중 스레드 환경에서) 작업하는 것이 가장 쉽습니다. 변경 가능한 객체에 대해 자유롭게 변경 가능한 참조를 사용하면 상황이 더 복잡해집니다. 경우주의 XY같은 객체를 참조하고 하나가 변경하고자 X.something, 하나는 유지할 수 정체성 X와 변화를 Y.something, 또는 남겨 Y.something변경하고 변경 정체성 X의,하지만 변경하는 동안 한 X의 정체성과 Y의 상태를 유지할 수 없습니다 X. 상태
supercat

불변 객체 사용을 강요하는 사람들은 때때로 객체 신원의 중요성을 인식하지 못하고, 변경 가능한 객체는 불변 객체가 할 수없는 방식으로 불변의 신원을 가질 수 있다는 사실을 인식하지 못합니다.
supercat 2013

0

Java 프로그래밍 측면에서 불변 : 한 번 생성 된 것은 예상되거나 예상치 못한 상태 변경이 없어야합니다!

이 기술은 다른 개체가 상태 변경을 유도 할 수없는 방어 프로그래밍에 유용합니다.

변경을 기대하지 않는 예 : 레이어에서 참조를 가져와 객체에 대해 작동하고 고의로 또는 무의식적으로 변경하는 외부 시스템 (단일 또는 다중 스레드). 이제 POJO, 컬렉션 또는 개체 참조가 될 수 있으며 변경을 기대하지 않거나 데이터를 보호하려고합니다. 당신은 확실히 방어 기술로 개체를 불변으로 만들 것입니다.

변경이 예상되는 예 : 올바른 프로그래밍 절차를 방해하므로 불변성이 필요하지 않습니다.

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