3

宝石を集めなければならないゲームを作りたいとしましょう。そのため、Gem クラス、GemSpawner クラス、そしてもちろん MainActivity クラスが必要です。

public class MainActivity {
    public static void main(String[] args) {

        List<Gem> gems = new ArrayList<Gem>();

        GemSpawner gs = new GemSpawner(gems);

        //...
    }
}

この場合、gem を含む List を作成し、コンストラクターを介してそれを GemSpawner に渡したので、gs は次を使用してリストに gem を追加できます。

gems.add(new Gem(10, 50, "red")); //should represent Xpos, Ypos, and color.

しかし、これは良くないでしょうか:

public class MainActivity {

    public static List<Gem> gems = new ArrayList<Gem>();

    public static void main(String[] args) {

        GemSpawner gs = new GemSpawner();

        //...
    }
}

現在、GemSpawner (gs) は以下を使用して gem を追加できます。

MainActivity.gems.add(new Gem(10, 50, "red"));

上の方法を友人に見せて説明してもらっただけですが、下の方法の方が効率的ではないでしょうか?

4

5 に答える 5

7

効率の議論にはあまり根拠がありません。これは単一の参照であるため、最初に 32 ビット (64 ビット マシンの場合は 64 ビット) が一度解析されるため、(測定可能な) パフォーマンスへの影響はありません。

ただし、多くの静的変数を使用すると、コードの設計が雑然とする可能性があります。たとえば、静的にすることで、リストに何が追加されているかを追跡する簡単な方法がありません (ある夜遅くに何かをテストするために、ランダムに宝石を追加してから忘れてしまうかもしれません。数か月後、解決できません。なぜこの 1 つの宝石が表示され続けるのか!)

ばかげているように見えますが、物事へのアクセスを制限することで、デバッグに本当に役立ちます。gem を追加できるのは だけだとわかっている場合は、GemSpawner潜在的な gem ベースのバグを 1 つのクラスに分離したことになります。どこからでも来る可能性がある場合、特にプロジェクトが複雑になるにつれて、デバッグが非常に難しくなる可能性があります。

于 2013-10-27T12:07:59.340 に答える
5

静的データ メンバーは、プログラムにグローバル状態と呼ばれるものを導入します。一般に、グローバルな状態はいくつかの正当な理由から悪いと見なされます。

  • これにより、グローバル状態を読み取るメソッドの動作が予測不能になります。これには 2 つの効果があります。
    • 結果が、それが属するオブジェクトとそれに渡される引数以外にも依存するメソッドについて推論するのは困難です。
    • そのメソッドの正式なテストを無意味にする可能性があります (ただし、いくつかの例外があります)。
  • それは、現在は成り立つかもしれないが、後で成り立たないという仮定を立てます。たとえば、グローバルな状態を変更するプロシージャは、プログラムの実行ごとに厳密に 1 回実行されれば問題ない場合があります。ただし、後でプロシージャを複数回実行する必要がある場合があります。その場合:
    • 順番に、後続の反復では「使用済み」状態に注意する必要があります。
    • 並行して、データ競合やスレッドの安全性の欠如への扉を開くことになります。

一方、必要な状態を引数として各メソッドに渡すと、上記のすべてが発生する可能性がはるかに低くなり、プログラムの正確性が脅かされるセーフティネットが自動的に作成されます。

状態を渡すよりもグローバルな状態を選択する方が、パフォーマンスに大きなメリットがある (またはまったくメリットがない) とは思えません。そして、グローバルな状態の検証が過剰に行われたり、さらに悪いことに、ロックやバリアを導入したりすることになった場合 (どちらのシナリオも非常にコストがかかります)、とにかく得られたはずのメリットをすべてキャンセルしてしまいます。

グローバルな状態を導入しないという優れたプラクティスに固執することは、はるかに価値があります。

于 2013-10-27T12:11:08.790 に答える
4

public static変数は本質的にグローバル変数です。

経験豊富なプログラマーの間では、グローバル変数は非常に貧弱なプログラミング スタイルと見なされています。

これは、それらが悪いいくつかの理由を説明する記事です。

オブジェクト指向のソリューションは、gem リストをプライベート コレクションとして GemManager クラスにカプセル化し、メソッドを介して gem へのアクセスを公開することです。次に、GemManager のインスタンスを 1 つ作成し、そのインスタンスを必要とするすべてのクラスまたはメソッドに渡します。

于 2013-10-27T12:11:52.577 に答える
3

これは、あなたが思っているよりもはるかに複雑な質問です。

Java で書き始める多くの人が、static参照を渡す必要がないという理由だけですべてを作成し始めます。これにより、コードが「単純」になります。

ただし、コードが複雑になると、問題が発生し始めます。これらの問題が発生する主な経路は 3 つあります。

  1. カプセル化
  2. 抽象化
  3. テスト

カプセル化

これは、Objectがそのメンバーへの直接アクセスを許可するべきではなく、「何かをする」ように指示されるべきであり、これがどのように行われるかを公開せずに内部的に行うという考えです。

この背後にある考え方は、クラスを互いに密結合しすぎないようにしようとすることです。

これにより、次のポイントに進みます

抽象化

abstractJava では、これはクラスとで表されますinterfaces

yourGemSpawnerは、gem を生成するものの定義にすぎないという考えです。内部でこれをどのように行うかは、実際には誰の仕事でもありません。

staticJava では、継承という OO の重要な考え方とメソッドを実際に調和させることはできません。

staticメソッドは継承されますが、オーバーライドされるのではなくシャドウ化されるため、(簡単に) それらの動作を変更することはできません。

そして、これは私たちを導きます

テスト

これは、プログラムが複雑になるにつれて、ますます発生するトピックです。

「Hello World」プログラムをどのようにテストしますか? それを実行して、「Hello Wrld」と表示されるかどうかを確認します。この場合、バグがあります。

プログラムが複雑になると、単純にこれを行うことはできません。プログラムを分解して「ユニット」をテストする必要があります。単体テストとして知られています。

ここで、static参照が実際に問題を引き起こし始めます。すべてが直接のクラス参照を介して結び付けられているため、プログラムを個別のユニットに分割することはできません。staticまた、メソッドは簡単にオーバーライドできないため、メソッドの動作をモックすることはできません。

ということで、まとめます。はい; staticどこにでも配置し、参照を渡さない方が、より迅速かつ簡単になる可能性があります。しかし、ゲームのような複雑なものを作成する予定がある場合は、Java を最大限に活用することを検討する必要があります。

于 2013-10-27T12:17:06.303 に答える
0

静的変数を使用する利点はほとんどありませんが、欠点があります。

  • ゲームの複数のコピーを同時に実行したり、履歴コピーとして作成したりすることはできません。JVM ごとに最大 1 つのコピーでロックされています。
  • 存在する必要のないクラス間の依存関係がある -カップリングを参照
  • 別のクラスからゲームを開始したいかもしれませんが、今はできません。開始をメイン クラスにロックしています。
  • 実装を別のクラスに「ブリードアウト」させました - cohesionを参照してください
于 2013-10-27T12:35:13.593 に答える