web-dev-qa-db-ja.com

プライベートゲッターではなくパブリックファイナルを使用する

私はこのように書かれたほとんどの不変の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;
    }
}
_

参照は最終的なものなので、オブジェクトは依然として不変であることに注意してください。それは私がより少ないコードを書くことを可能にし、より短い(5文字:getおよび_()_)アクセスを許可します。

私が見ることができる唯一の欠点は、あなたがgetFoo()の実装を変更して、奇妙なことをしたいのであれば、それができないことです。しかし現実的には、オブジェクトが不変であるため、これは決して起こりません。インスタンス化中に確認し、インスタンス化中に不変の防御コピーを作成して(たとえば、GuavaのImmutableListを参照)、fooまたはbarオブジェクトをget呼び出しの準備ができます。

私が見逃している欠点はありますか?

[〜#〜]編集[〜#〜]

私が見逃しているもう1つの欠点は、getまたはisで始まるメソッドに対するリフレクションを使用するシリアル化ライブラリーであると思いますが、それはかなりひどい習慣です...

53
Cory Kendall

私が考えることができる4つの欠点:

  1. 同じエンティティの読み取り専用で変更可能な形式にする場合、一般的なパターンは、保護されたメンバー変数を持つアクセサーのみを公開する不変クラスEntityを作成し、それを拡張してセッターを追加するMutableEntityを作成することです。あなたのバージョンはそれを防ぎます。
  2. ゲッターとセッターの使用は、JavaBeans規約に準拠しています。 JSTLやELなどのプロパティベースのテクノロジでBeanとしてクラスを使用する場合は、パブリックゲッターを公開する必要があります。
  3. 実装を変更して値を導出したり、データベースで値を検索したりする場合は、クライアントコードをリファクタリングする必要があります。アクセサー/ミューテーターアプローチでは、実装のみを変更できます。
  4. 最小の驚き-パブリックインスタンス変数が表示されたら、それを変更している可能性のあるユーザーをすぐに探し、カプセル化が失われたため、Pandoraのボックスを開いているのではないかと心配します。 http://en.wikipedia.org/wiki/Principle_of_least_astonishment

そうは言っても、あなたのバージョンは間違いなくもっと簡潔です。これが特定のパッケージ内でのみ使用される特殊なクラスである場合(パッケージのスコープはここでは良い考えかもしれません)、私はこれを1回限りのことと考えます。しかし、私はこのような主要なAPIを公開しません。

40
Brandon

ゲッター/セッターも削除して、元気です!

これは、Javaプログラマの間で非常に物議を醸しているトピックです。

とにかく、ゲッター/セッターの代わりにパブリック変数(!)を使用する2つの状況があります。

  1. public final私にとって、これは単なるゲッターよりもはるかに優れた「私は不変」のシグナルです。ほとんどのIDEは、オートコンプリート中に最終修飾子を「F」で示します。ゲッター/セッターとは異なり、setXXXがないことを検索する必要があります。
  2. public non-finalこれはデータクラスで気に入っています。私はすべてのフィールドを公開しています。ゲッター、セッター、コンストラクターはありません。いいえ、別に。ポージョ未満。これは私にすぐに「見て、私は愚かです。私はデータを保持しています。それがすべてです。適切なデータを私の中に入れるのはあなたの仕事です」と信号を送ります。 Gson/JAXB/etc。これらのクラスをうまく処理します。彼らは書くことの至福です。彼らの目的や能力については間違いありません。そして最も重要なのは、変数を変更しても副作用がないことです。私見では、これにより、あいまいさがほとんどない非常に簡潔なデータモデルが得られますが、ゲッターとセッターには、内部でマジックが発生することがあるという大きな問題があります。
27
kritzikratzi

素人の言葉で:

  • カプセル化違反数行のコードを保存するため。これはOODの目的に反します。
  • クライアントコードは、クラスメンバーの名前にハードカップリングになります。カップリングが悪い。 OODの主な目的は、結合を防ぐことです。
  • あなたも非常に確かクラスを変更可能にする必要はありません。状況は変わります。変化は一定である唯一のものです。
9

私が手短に見ることができる1つの考えられる欠点は、クラス内のデータの内部表現に縛られていることです。これは大した問題ではないかもしれませんが、セッターを使用して、fooとbarが別の場所で定義された他のクラスから返されると決めた場合、MyObjectを使用するクラスを変更する必要はありません。 MyObjectに触れるだけで済みます。ただし、ネイキッドな値を使用する場合、MyObject iが使用したすべての場所に触れる必要があります。

6
ipaul