web-dev-qa-db-ja.com

Java-完全に静的なクラスを持つことは悪い考えですか?

現在、より大きなソロプロジェクトに取り組んでおり、インスタンスを作成する理由が見当たらないクラスがいくつかあります。

たとえば、現在の私のサイコロクラスは、すべてのデータを静的に格納し、そのメソッドもすべて静的です。サイコロを振って新しい値を取得したい場合は、Dice.roll()を使用するだけなので、初期化する必要はありません。

このような1つのメイン関数のみを持ついくつかの同様のクラスがあり、すべてのイベント(プレーヤーが移動したとき、現在のターンなど)を担当する一種の「コントローラー」クラスに取り組み始めますそれは)そして私はこのクラスのために同じ考えに従うことができることがわかりました。これらの特定のクラスに対して複数のオブジェクトを作成する予定はないので、完全に静的にすることは悪い考えでしょうか?

Javaに関しては、これは「悪い習慣」と見なされているのかと思っていました。私が見たことから、コミュニティはこのトピックに関して一種の分裂しているように見えますか?とにかく、私はこれについてのいくつかの議論が大好きで、リソースへのリンクも素晴らしいです!

16
HexTeke

本当にstaticである静的クラスに問題はありません。つまり、メソッドの出力が変化する原因となる内部状態はありません。

Dice.roll()が単に1から6の新しい乱数を返す場合、状態は変化していません。確かに、あなたはRandomインスタンスを共有しているかもしれませんが、状態の変化が定義上そうであるとは思わないでしょう。出力は常にランダムです。また、スレッドセーフであるため、ここでは問題はありません。

最終的な「ヘルパー」またはプライベートコンストラクターと静的メンバーを持つその他のユーティリティクラスがよく見られます。プライベートコンストラクターにはロジックが含まれておらず、誰かがクラスをインスタンス化できないようにするためだけに機能します。最後の修飾子は、これが派生したいクラスではないという考えを本家に持ち込みます。これは単なるユーティリティクラスです。適切に行われれば、それ自体が静的で最終的なものではないシングルトンや他のクラスメンバーは存在しないはずです。

これらのガイドラインに従い、シングルトンを作成していない限り、これで問題はまったくありません。コントローラークラスについて言及すると、これはほぼ確かに状態の変更を必要とするため、静的メソッドのみを使用しないことをお勧めします。静的ユーティリティクラスに大きく依存することはできますが、静的ユーティリティクラスmakeは使用できません。


クラスの状態の変化とは何ですか?まあ、乱数は定義から非決定的であるため、戻り値が頻繁に変化するため、1秒間乱数を除外しましょう。

純粋な関数は決定論的な関数です。つまり、特定の入力に対して、1つの出力と1つの出力しか得られません。静的メソッドを純粋な関数にしたい。 Javaには、静的メソッドの動作を微調整して状態を保持する方法がありますが、それらが良いアイデアになることはほとんどありません。メソッドをstaticとして宣言すると、一般的なプログラマは、それが純粋な関数であるとすぐに想定します。予想される動作から逸脱することは、一般的に言えば、プログラムにバグを作成する傾向があるため、避ける必要があります。

シングルトンは、「純粋な関数」とは反対の静的メソッドを含むクラスです。単一の静的プライベートメンバーは、クラスの内部に保持され、インスタンスが1つだけであることを確認するために使用されます。これはベストプラクティスではなく、さまざまな理由で後で問題が発生する可能性があります。私たちが話していることを知るために、シングルトンの簡単な例を次に示します。

// DON'T DO THIS!
class Singleton {
  private String name; 
  private static Singleton instance = null;

  private Singleton(String name) {
    this.name = name;
  }

  public static Singleton getInstance() {
    if(instance == null) {
      instance = new Singleton("George");
    }
    return instance;
  }

  public getName() {
    return name;
  }
}

assert Singleton.getInstance().getName() == "George"
21
Neil

staticクラスの制限の例を示すために、一部のゲーマーがサイコロにわずかなボーナスを獲得したい場合はどうなりますか?そして、彼らは大金を払う用意があります! :-)

はい、別のパラメータを追加できるので、Dice.roll(bonus)

後でD20が必要になります。

Dice.roll(bonus, sides)

ええ、しかし、一部のプレイヤーは「最高能力」の偉業を持っているため、決して「いじくる」ことはできません(1をロール)。

Dice.roll(bonus, sides, isFumbleAllowed)

これは乱雑になっていますね。

10
user949300

Diceクラスの特定のケースでは、静的ではなくインスタンスメソッドを使用すると、テストが大幅に容易になると思います。

Diceのインスタンスを使用するもの(たとえば、Gameクラス)を単体テストする場合は、テストから、常に固定された値のシーケンスを返すDiceのテストフォームのフォームを挿入できます。あなたのテストは、ゲームがそれらのサイコロの振る舞いに正しい結果を持っていることを確認できます。

私はJava開発者ではありませんが、完全に静的なDiceクラスでそれを行うのは非常に難しいと思います。参照してください https://stackoverflow.com/questions/4482315/why-does-mockito-not-mock-static-methods

3
bdsl

これは実際にはMonostateパターンと呼ばれ、すべてのインスタンス(および「no-instance」)もステータスを共有しています。すべてのメンバーはクラスメンバーです(つまり、インスタンスメンバーはありません)。これらは一般に、1つの責任または要件に関連する一連のメソッドと定数をバンドルする「ツールキット」クラスを実装するために使用されますが、機能するために状態を必要としません(純粋に機能します)。実際、Javaにはそれらの一部がバンドルされています(たとえば、 Math )。

少しトピック外:VisualBasicでのキーワードの命名にほとんど同意しませんが、この場合、sharedは確かに明確で意味的に優れていると思います(sharedクラス自体とそのすべてのインスタンス間)staticよりも(宣言されたスコープのライフサイクルの後に残ります)。

0