web-dev-qa-db-ja.com

不変タイプ:パブリックファイナルフィールドとゲッター

不変であるはずの文字列を格納するための小さなContainer-Classが必要です。 String自体は不変タイプなので、次のようなことを考えました。

public final class Immu
{
  public final String foo;
  public final String bar;

  public Immu(final String foo, final String bar)
  {
    this.foo = foo;
    this.bar = bar;
  }
}

多くの人がパブリックフィールドの使用にまったく反対し、代わりにゲッターを使用しているようです。この場合、文字列自体は不変なので、これは単なる定型文です。

これについて私が見逃しているかもしれない他の考え?

55
Daniel

私はあなたが最も簡単で明確だと信じていることをします。限られた数のクラスでのみ使用されるデータ値クラスがある場合。 espパッケージのローカルクラス。それから私はゲッター/セッターを避け、パッケージのローカルまたはパブリックフィールドを使用します。

他のモジュール/開発者が使用することを期待するクラスがある場合、ゲッター/セッターモデルに従うことは、長期的にはより安全なアプローチになる可能性があります。

54
Peter Lawrey

問題は、統一アクセス原則です。後でfooを修正して、修正するのではなくメソッドを通じて取得する必要がある場合があります。ゲッターの代わりにフィールドを公開した場合は、APIを中断する必要があります。

25

この答えは不要です:

何故なの

interface Immu { String getA() ; String getB ( ) }

Immu immu ( final String a , final String b )
{
       /* validation of a and b */
       return new Immu ( )
       {
              public String getA ( ) { return a ; }

              public String getB ( ) { return b ; }
       }
}
14
emory

必要に応じて、equals()、hashCode()、toString()などの絶対的な基本とともに、コンストラクターを備えた基本的に不変のデータ構造であるクラスのホームプロジェクトでpublic-final-field(anti?)パターンを使用します。 (言葉のさまざまな異なる言語の解釈のため、「構造体」という言葉は避けています。)

他のコードと矛盾している可能性が高く、When In RomeやLeast Surpriseなどの原則が優先されるため、このアプローチを他の誰かのコードベース(作業、パブリックプロジェクトなど)に持ち込むことはしません。

とは言っても、ダニエルC.ソブラルとアイオオベの回答に関して、私の態度は、予期せぬ進展のためにクラスの設計が問題となった場合、IDEフィールドとアクセサーを追加し、何百もない限り、壊れた参照を修正するのに5分から10分を超えません。

[編集:効果的Javaは、不変のフィールドでは「害が少ない」ことに注意しながら、アイデアにかなり強く反対します。]

6
ChrisA

私はこのスレッドが実際の議論を期待しているのを見つけましたが、ここで見た答えはそれほど役に立ちませんでした。もう少し調査して考えた結果、次の点を考慮する必要があると思います。

  • public finalは不変の型に対して最もきれいに見えます。
  • これが意図されていなくても、可変タイプはアクセサーによって変更される可能性があります-並行環境では、これは多くの頭痛の種につながる可能性があります。
  • 引数のないコンストラクタはありません。これは、ファクトリーメソッド(LMAX Disruptorなど)が必要な場合に重要です。同様に、リフレクションを介してオブジェクトをインスタンス化すると、より複雑になります。
  • ゲッターとセッターには副作用があります。 public finalを使用すると、隠された魔法は発生せず、オブジェクトは本質的に愚かであることをプログラマーに明確に伝えます:)
  • ラッパーまたは派生クラスインスタンスをアクセサーに返すことはできません。次に、これは、フィールドに値が割り当てられるときに知っておくべきことです。私の意見では、コンテナクラスは誰に何を返すかについて心配するべきではありません。

開発の途中で、ガイドラインに妨げられずにプロジェクトが分離されている場合、または関係するすべてのプロジェクトを制御している場合は、不変タイプにpublic finalを使用することをお勧めします。後でゲッターが必要だと判断した場合、EclipseはRefactor-> Encapsulate Field...を提供し、これらを自動的に作成してフィールドへのすべての参照を調整します。

5
Managarm

誰かがAPIを介してコードを使用するかどうかは明確ではありません。後で必要になる場合は、入力を検証する機会もありません。

0
n0rm1e

public finalを使用することは、このような小さな仕事には問題ないかもしれませんが、これは標準的な方法として採用することはできません

以下の状況を考慮してください。

Public class Portfolio {
   public final String[] stocks;
}

もちろん、このオブジェクトは不変であるため、コンストラクターによって初期化され、直接アクセスされます。その中の問題をあなたに言わなければなりませんか?それは明らかです!

クライアントが以下のようなコードを書くことを検討してください-

Portfolio portfolio = PortfolioManager.get(“Anand”);
Portfolio.stocks[0] = “FB”;
portfolio.calculate();

これは可能ですか?クライアントライブラリは、オブジェクトの状態を操作したり、ランタイム表現内でハッキングしたりできます。これは大きなセキュリティリスクであり、もちろんSONARのようなツールはそれを前もってキャッチします。ただし、ゲッターセッターを使用している場合にのみ管理できます。

ゲッターを使用している場合は、非常にうまく書くことができます

   Public class Portfolio {
      private final String[] stocks;
      public String[] getStocks() {
          return Arrays.coptOf(this.stocks);
      }
   }

これにより、潜在的なセキュリティの脅威から保護されます。

上記の例を見て、public finalはお勧めしません配列を使用している場合。そのような場合、それが基準になることはありません。私のような人は、すべてのデータ型で統一された標準になることができないコードプラクティスを使用しないでください。あなたはどうですか?

0
Anand Vaidya