32

Java でメソッド シグネチャに static キーワードを使用するのが適切でないのはいつですか? メソッドがいくつかの引数に基づいて関数を実行し、静的ではないフィールドへのアクセスを必要としない場合、これらのタイプのメソッドを常に静的にしたくないでしょうか?

4

9 に答える 9

51

大規模なJavaアプリケーションでこれまでに遭遇する最大の悪の2つは次のとおりです。

  • 純粋関数であるものを除く静的メソッド*
  • 可変静的フィールド

これらは、コードのモジュール性、拡張性、およびテスト容易性を、この限られた時間とスペースであなたを納得させることはできないと私が理解する程度まで台無しにします。

*「純粋関数」とは、状態を変更せず、その結果が提供されたパラメーターのみに依存するメソッドのことです。したがって、たとえば、I / Oを(直接的または間接的に)実行する関数は純粋関数ではありませんが、もちろん、Math.sqrt()は純粋関数です。

純粋関数(自己リンク)と、それらに固執したい理由についての詳細。

SpringやGuiceなどのフレームワークによってサポートされている可能性のある「依存性注入」スタイルのプログラミングを支持することを強くお勧めします(免責事項:私は後者の共著者です)。これを正しく行うと、基本的に、変更可能な静的状態や純粋でない静的メソッドは必要なくなります。

于 2009-11-19T21:40:52.053 に答える
36

静的にしたくない理由の1つは、サブクラスでオーバーライドできるようにするためです。つまり、動作はオブジェクト内のデータではなく、オブジェクトの正確なタイプに依存する可能性があります。たとえば、常に可変のコレクション、常に不変のコレクションisReadOnlyを返し、他のインスタンス変数に依存するプロパティを持つ一般的なコレクションタイプがあるとします。falsetrue

ただし、これは私の経験では非常にまれであり、明確にするために通常は明示的に指定する必要があります。通常、静的なオブジェクトの状態に依存しないメソッドを作成します。

于 2009-11-19T21:35:35.140 に答える
24

一般的に、私は次の理由でインスタンスメソッドを好みます。

  1. 静的メソッドは、置き換えることができないため、テストが困難になります。
  2. 静的メソッドは、より手続き指向です。

私の意見では、静的メソッドはユーティリティクラス(のようなStringUtils)には問題ありませんが、可能な限りそれらを使用しないことを好みます。

于 2009-11-19T21:36:43.113 に答える
4

あなたの言うことは正しいのですが、派生クラスでそのメソッドの動作をオーバーライドしたい場合はどうなりますか? 静的な場合、それはできません。

例として、次の DAO 型クラスを考えてみましょう。

class CustomerDAO {
    public void CreateCustomer( Connection dbConn, Customer c ) {
       // Some implementation, created a prepared statement, inserts the customer record.
    }

    public Customer GetCustomerByID( Connection dbConn, int customerId ) {
       // Implementation
    }
}

現在、これらのメソッドはいずれも「状態」を必要としません。必要なものはすべてパラメーターとして渡されます。したがって、それらは簡単に静的になる可能性があります。ここで、別のデータベース (Oracle としましょう) をサポートする必要があるという要件が生じます。

これらのメソッドは静的ではないため、新しい DAO クラスを作成できます。

class OracleCustomerDAO : CustomerDAO {
    public void CreateCustomer( Connection dbConn, Customer c ) {
        // Oracle specific implementation here.
    }

    public Customer GetCustomerByID( Connection dbConn, int customerId ) {
        // Oracle specific implementation here.
    }
}

この新しいクラスは、古いクラスの代わりに使用できるようになりました。依存性注入を使用している場合は、コードの変更がまったく必要ない場合もあります。

しかし、これらのメソッドを静的にした場合、新しいクラスで静的メソッドを単純にオーバーライドすることはできないため、事態はさらに複雑になります。

于 2009-11-19T21:34:59.163 に答える
1

通常、静的メソッドは 2 つの目的で作成されます。最初の目的は、 java.util.Collectionsに見られる機能の種類に似た、ある種のグローバル ユーティリティ メソッドを用意することです。これらの静的メソッドは通常、無害です。2 つ目の目的は、シングルトンファクトリなどのさまざまな設計パターンを介して、オブジェクトのインスタンス化を制御し、リソース (データベース接続など) へのアクセスを制限することです。これらは、実装が不十分な場合、問題が発生する可能性があります。

私にとって、静的メソッドの使用には 2 つの欠点があります。

  1. それらはコードのモジュール性を低下させ、テスト/拡張を困難にします。ほとんどの回答はすでにこれに対処しているため、これ以上説明しません。
  2. 静的メソッドは、何らかの形でグローバル状態になる傾向があり、これはしばしば潜行性のバグの原因となります。これは、上記の 2 番目の目的のために書かれた不適切なコードで発生する可能性があります。詳しく説明しましょう。

たとえば、特定のイベントをデータベースに記録する必要があり、他の状態もデータベース接続に依存しているプロジェクトを考えてみましょう。通常、データベース接続が最初に初期化され、次にログ フレームワークが特定のログ イベントをデータベースに書き込むように構成されているとします。ここで、開発者が手書きのデータベース フレームワークから既存のデータベース フレームワーク (hibernate など) に移行することを決定したとします。

ただし、このフレームワークには独自のロギング構成がある可能性が高く、たまたま同じロギング フレームワークを使用している場合、構成間でさまざまな競合が発生する可能性が高くなります。突然、別のデータベース フレームワークに切り替えると、一見無関係に見えるシステムのさまざまな部分でエラーや障害が発生します。このような失敗が発生する理由は、ロギング構成が静的メソッドと変数を介してアクセスされるグローバル状態を維持し、さまざまな構成プロパティがシステムのさまざまな部分によってオーバーライドされる可能性があるためです。

これらの問題を回避するには、開発者は静的メソッドと変数を介して状態を保存しないようにする必要があります。代わりに、ユーザーが必要に応じて状態を管理および分離できるようにするクリーンな API を構築する必要があります。BerkeleyDBはここでの良い例であり、静的呼び出しではなく環境オブジェクトを介して状態をカプセル化します。

于 2009-11-19T23:30:30.247 に答える
0

それは正しい。確かに、Javaの用語に、そうでなければ合理的な設計(クラスに関連付けられていないいくつかの関数を持つため)である可能性があるものをゆがめる必要があります。そのため、FredsSwingUtilsやYetAnotherIOUtilsなどのキャッチオールクラスが表示されます。

于 2009-11-19T21:35:59.933 に答える
0

そのクラスのオブジェクトとは独立してクラスメンバーを使用する場合は、静的として宣言する必要があります。
静的と宣言されている場合は、クラスのオブジェクトの既存のインスタンスがなくてもアクセスできます。静的メンバーは、その特定のクラスのすべてのオブジェクトによって共有されます。

于 2009-11-19T21:39:11.977 に答える
0

ここで 2 つの質問 1) オブジェクトを作成する静的メソッドは、最初にアクセスしたときにメモリにロードされたままになりますか? これ(メモリにロードされたまま)は欠点ではありませんか?2) Java を使用する利点の 1 つは、そのガベージ コレクション機能です。静的メソッドを使用するときにこれを無視していませんか?

于 2010-03-09T06:41:04.433 に答える
0

静的メソッドに関する追加の煩わしさ: ラッパー クラスを作成せずに、そのような関数への参照を渡す簡単な方法はありません。例 - 次のようなもの:

FunctorInterface f = new FunctorInterface() { public int calc( int x) { return MyClass.calc( x); } };

私は、この種の Java の make-work が大嫌いです。おそらく、Java の新しいバージョンでは、デリゲートまたは同様の関数ポインター / 手続き型メカニズムが得られるでしょうか?

ちょっとした不満ですが、不要な静的関数、つまりメソッドについて気に入らないことがもう 1 つあります。

于 2009-11-19T22:06:20.873 に答える