web-dev-qa-db-ja.com

インスタンスフィールドに依存しないメソッドを静的にしますか?

最近、Javaプロジェクトの統合テストフレームワークのためにGroovyでプログラミングを始めました。GroovyプラグインでIntellij IDEAを使用しています。非静的でインスタンスフィールドに依存しないすべてのメソッドに対する警告として。ただし、Javaでは、これは問題ではありません(少なくともIDEの観点から)。

インスタンスフィールドに依存しないすべてのメソッドを静的関数に変換する必要がありますか? trueの場合、これはGroovyに固有のものですか、それともOOPで一般的に利用できますか?なぜですか?

21
m3th0dman

IDEAにはこれがある inspection for Javaとも呼ばれ、これは呼び出される Method is 'static'

このインスペクションは、安全に静的にできるメソッドを報告します。メソッドは、クラスの非静的メソッドおよび非静的フィールドのいずれも参照せず、サブクラスでオーバーライドされない場合、静的である可能性があります...

Javaコードの場合、この検査はデフォルトでオフになっています(プログラマはそれをオンにすることができます)この理由は、非常に信頼できるいくつかの情報源に基づいて、そのような検査の有効性/有用性に異議が唱えられる可能性が高いためです。

まず、 official Java tutorial は、メソッドを静的にする必要がある場合にかなり制限があります。

静的メソッドの一般的な用途は、静的フィールドにアクセスすることです。

上記のように、デフォルトで言及された検査をオンにすることは、Javaでの静的修飾子の推奨される使用に準拠していないと主張することができます。

その上、この検査の背後にあるアイデアを使用するか、あるいはそれを落胆させることさえするための賢明なアプローチを提案する限り、他のいくつかのソースがあります。

例を参照Java世界の記事- Mr。Happy Objectは静的メソッドを教えます

インスタンスの状態に依存しないメソッドはすべて、静的として宣言される候補です。

「静的として宣言される候補」と言っていることに注意してください。前の例でも、instances()をstaticとして宣言する必要はありません。 staticとして宣言すると、メソッドを呼び出すためのインスタンスが不要になるため、呼び出しがより簡単になります。インスタンスの状態に依存していないように見えるメソッドがある場合があります。これらのメソッドを静的にしたくない場合があります。実際、インスタンスなしでそれらにアクセスする必要がある場合にのみ、おそらくそれらを静的として宣言することになるでしょう。

さらに、そのようなメソッドをstaticとして宣言することはできますが、設計に挿入する継承の問題のため、そうしたくない場合があります。 "Effective Object-Oriented Design" を見て、直面する問題のいくつかを確認してください...

Googleのテストブログの記事は、 Static Methods is Death to Testability

メンタルエクササイズをしましょう。アプリケーションに静的メソッドしかないとします。 (はい、そのようなコードを書くことは可能です。これは手続き型プログラミングと呼ばれます。)ここで、そのアプリケーションの呼び出しグラフを想像してください。リーフメソッドを実行しようとすると、その状態を設定し、すべての主要なケースをアサートする問題は発生しません。その理由は、leafメソッドがそれ以上の呼び出しを行わないためです。葉から離れ、ルートのmain()メソッドに近づくと、テストで状態を設定することが難しくなり、アサートすることが難しくなります。多くのことを主張することが不可能になります。テストは徐々に大きくなります。 main()メソッドに到達すると、ユニットテストはなくなります(ユニットはアプリケーション全体なので)。これでシナリオテストができました。テストしようとしているアプリケーションがワードプロセッサであるとします。あなたがメインメソッドから主張できることはあまりありません...

静的メソッドは他のオブジェクトのファクトリーになる場合があります。これにより、テストの問題がさらに悪化します。テストでは、重要な依存関係をモックに置き換えてオブジェクトを異なる方法でワイヤリングできるという事実に依存しています。 new演算子が呼び出されると、メソッドをサブクラスでオーバーライドできなくなります。このような静的ファクトリーの呼び出し元は、静的ファクトリーメソッドが生成した具象クラスに永続的にバインドされます。つまり、静的メソッドの損傷は静的メソッド自体をはるかに超えています。オブジェクトグラフのワイヤリングと構築コードを静的メソッドにバッティングするのは、オブジェクトグラフのワイヤリングがテストのために物事を分離する方法であるため、さらに悪いことです...


上記のように、Javaではデフォルトでインスペクションがオフになっているのはごく自然なことです。

IDE開発者は、広く認知されている推奨事項やベストプラクティスに反して、デフォルトで設定することが非常に重要であると考える理由を説明するのに本当に苦労するでしょう。

Groovyの場合、状況はまったく異なります。上記の引数のどれも適用されません。特に、たとえばJavalobbyの Groovyの静的メソッドのモック の記事で説明されているように、テスト容易性に関する引数は適用されません。

テストしているGroovyクラスが別のGroovyクラスで静的メソッドを呼び出す場合、メソッド、コンストラクター、プロパティ、静的メソッドを動的に追加できるExpandoMetaClassを使用できます...

この違いが、Groovyで前述の検査のデフォルト設定が逆になる理由と思われます。 Javaデフォルトの "on"はユーザーの混乱の原因になりますが、Groovyでは反対の設定がIDEユーザーを混乱させる可能性があります。

「メソッドでインスタンスフィールドが使用されていないのに、なぜ警告しないのですか?」その質問は、Java(上記で説明したように)の場合は簡単に答えられますが、Groovyの場合、説得力のある説明はありません。

27
gnat

これがパフォーマンスに識別可能な影響を与えるとは想像しがたいです。それらをstaticにすることで得られる唯一の利点は、インスタンスの状態が影響を受けていないことを視覚的に示すことです。言い換えると、ソースコードを読んでいる人に、そのメソッドが存在するという理由だけで、そのメソッドについて「興味深い」ことを伝えます。本当の質問は、それは明確にするか、混乱させるのですか? "このメソッドが静的なのはなぜですか?ファクトリメソッドですか?オブジェクトインスタンスなしで呼び出すことができるのですか?"

さらに、一部の人々は静的メソッドが好きではありません。なぜなら、それらはあなたがそれらをモックすることはできず、したがってそれらはテストできない、またはそれらの線に沿った何かだからです。確かに、たとえばファクトリメソッドを提供するなど、通常の理由のいずれかで静的にする場合、私はそれで十分です。インスタンスの状態に影響を与えないという理由だけでメソッドを静的にするのが義務であるかどうか、私にはまったくわかりません。

5
Robert Harvey

私はそれが可能なリファクタリングを可能にすることだと思いますspotted

メソッドが静的にされると、クラスの外に、たとえば単一のクラスに移動できるのはclearです。

また、パラメータの1つのインスタンスメソッドに簡単に変換することもできます。多くの場合、ここにコードがあります。

3
Ian