web-dev-qa-db-ja.com

JavaBeansの代わりに不変のPOJOを使用すべきではないのはなぜですか?

私はいくつかのJava=アプリケーションを実装しました。これまでのところデスクトップアプリケーションのみです。アプリケーションでデータを渡すために不変オブジェクトを使用する方が、ミューテーター(セッターおよびgetter)、JavaBeansとも呼ばれます。

しかし、Javaの世界では、JavaBeansを使用する方がはるかに一般的であるように思われ、なぜそれらを代わりに使用する必要があるのか​​理解できません。常に状態を変化させるのではなく、オブジェクト。

不変オブジェクトはアイテム15:可変性の最小化Effective Java 2edでも推奨されています。

オブジェクトPersonJavaBeanとして実装すると、次のようになります。

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;
    }
}

そして、同じPersonimmutableオブジェクトとして実装されています:

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;
    }
}

またはCのstructに近い:

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

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

実装の詳細を隠すために、不変オブジェクトにゲッターを含めることもできます。しかし、それをstructとしてのみ使用するので、「ゲッター」をスキップし、シンプルに保つことを好みます。

単純に、なぜJavaBeansを使用する方が良いのか、または不変のPOJOを使い続けることができるのか、そして続けるべきなのかがわかりません。

Javaライブラリの多くは、JavaBeansのサポートが優れているようですが、不変のPOJOのサポートが増えるにつれて、時間の経過とともに人気が高まるのではないでしょうか?

79
Jonas

いつJavaBeanを優先するか

  • それらを期待する環境と対話する必要があります
  • インスタンス化時にすべての初期化を行うのは不便な多くのプロパティがあります
  • 何らかの理由でコピーが高価または不可能であるが、変更が必要な状態にある
  • ある時点で、プロパティへのアクセス方法を変更する必要があると考えます(たとえば、保存された値から計算された値への移行、アクセス許可など)。
  • javaBeansを使用するほうがなんとなく「オブジェクト指向」であると無意識に主張するコーディング標準に準拠したい

不変POJOを優先する

  • 少数の単純なプロパティがあります
  • javaBeanの規則を前提とする環境と対話する必要はありません
  • オブジェクトを複製するときに状態をコピーするのは簡単です(または少なくとも可能です)
  • オブジェクトのクローンを作成する予定はまったくありません
  • 上記のようにプロパティへのアクセス方法を変更する必要がないことは確かです
  • コードが十分に「オブジェクト指向」ではないことについての愚痴(または冷笑)を聞いてもかまいません

Threadという言葉がこのディスカッションのどこにも現れていないことに驚きました。

不変クラスの主な利点の1つは、変更可能な共有状態がないため、本質的にスレッドセーフであるということです。

これにより、コーディングが簡単になるだけでなく、副作用として2つのパフォーマンス上の利点も得られます。

  • 同期の必要性が少なくなります。

  • 後続のコンパイラー最適化を容易にすることができるfinal変数を使用するためのより多くのスコープ。

私は本当にJavaBeanスタイルのクラスではなく不変のオブジェクトに向かって動いています。ゲッターとセッターを介してオブジェクトの内部を公開することは、おそらくデフォルトの選択ではないはずです。

38

まあそれはあなたがやろうとしていることに依存します。永続的なレイヤーで作業していて、データベースからPOJOに行をフェッチし、プロパティを変更して保存したい場合は、特に多くのプロパティがある場合、JavaBeanスタイルを使用する方が良いでしょう。

あなたの人が、ファーストネーム、ミドルネーム、姓、生年月日、家族、教育、仕事、給与などの多くのフィールドを持っていると考えてください。

そして、その人はたまたま結婚し、彼女の姓を変更することを受け入れたばかりの女性であり、データベースを更新する必要があります。

不変のPOJOを使用している場合は、彼女を表すPersonオブジェクトをフェッチしてから、変更していないすべてのプロパティと新しい姓を渡す新しいPersonオブジェクトを作成し、新しい姓を保存します。

Java Beanの場合は、setLastName()を実行して保存できます。

それは「可変オブジェクトを使用しない」ではなく「可変性を最小化する」ことです。状況によっては、変更可能なオブジェクトの方がうまく機能します。オブジェクトを変更可能にすることがプログラムに適しているかどうかを判断するのは、実際にはあなたの仕事です。常に「不変オブジェクトを使用する必要がある」と言う必要はありません。代わりに、自分自身を傷つけ始める前に、不変にすることができるクラスの数を確認してください。

16

他の回答を要約すると私は思います:

  • 不変性は正確性を促進します(構造体は参照で渡すことができ、障害のある/悪意のあるクライアントによって何も破壊されないことがわかります)とコードの簡素化
  • 可変性により同質性が促進されます:Springおよびその他のフレームワークは、引数なしでオブジェクトを作成し、オブジェクトプロパティを設定し、voilàを設定します。また、同じクラスを使用してデータを提供し、変更を保存するためのインターフェイスを簡単にします(get(id): Clientsave(MutableClient)は不要で、MutableClientはクライアントの子孫です。

中間点(作成、プロパティの設定、不変にする)があった場合、フレームワークはより不変のアプローチを奨励するでしょう。

とにかく、私は不変オブジェクトを「読み取り専用Java Beans」」と考えることをお勧めします。

7
helios

Java 7から、両方の世界で最高の不変のBeanを使用できます。コンストラクターでアノテーション@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;
    }
}
3
Larry

正直に言うと、不変オブジェクトがそれほど普及することはないと思います。

私には利点はありますが、HibernateやSpringのようなフレームワークは現在非常に流行しており(そしてそれには正当な理由もあります)、それらはBeanで本当に最もよく機能します。

だから不変性が悪いとは思いませんが、それは確かに現在のフレームワークとの統合オプションを制限するでしょう。

[〜#〜] edit [〜#〜]コメント回答を少し明確にするように求められます。

不変性が非常に有用であり、実際に使用されている問題領域があります。しかし、現在のデフォルトは変更可能であるように思われます。これは、ほとんどの場合予想されるものであり、明確な利点がある場合にのみ不変です。

また、Springで引数付きのコンストラクタを使用することは確かに可能ですが、これはレガシーコードやサードパーティのコードを美しい真新しいSpringコードで使用する方法として意図されているようです。少なくともそれは私がドキュメントから拾ったものです。

2
extraneon