web-dev-qa-db-ja.com

Javaベストプラクティス:静的メソッドのみを持つクラス

PlausibilityCheckerというクラスがあるアプリケーションがあります。このクラスには、checkZipcodeFormatcheckMailFormatなどの静的メソッドのみがあります。 GUIクラスでそれらを使用して、入力を確認してから下位層に送信します。

これは良い習慣ですか? GUIクラスにインスタンスを渡すことや、GUIオブジェクトを参照しない各GUIクラスにインスタンスフィールドを持つことを気にする必要がないように、静的メソッドのみを使用すると思いました。

FilesクラスのJava NIOには静的メソッドしかありませんので、これはそれほどひどい間違いではないと思います。

38
user3629892

私はあなたがそれを正しくやっていると言うでしょう。それとは別に、ユーティリティクラスに関するいくつかのアドバイス:

  • 状態がないことを確認してください。つまり、static finalと宣言されていない限り、クラスにはフィールドがありません。また、このフィールドも不変であることを確認してください。 Strings。
  • 他のクラスのスーパークラスにできないことを確認してください。クラスをfinalにして、他のプログラマがクラスを拡張できないようにします。
  • これは議論の余地がありますが、引数なしのコンストラクタprivateを宣言することができるため、他のクラスはユーティリティクラスのインスタンスを作成できません(リフレクションまたは同様のものを使用して、しかし保護する必要はありません)クラスで)。なぜあなたはこれをしないのですか?まあ、これはユーティリティクラスのインスタンスを注入したい/必要な奇妙なケースです。クラスに沿って直接使用するのではなく、インターフェースを介して。 これの例を次に示します 。この設計は本当に奇妙ですが、発生する可能性があります(上記のリンクを参照)が、そのような場合に実行しない場合は、コンストラクターprivateを保持することをお勧めします。

プログラマーの作業を支援するために、ユーティリティクラスを提供するライブラリが多数あります。最も知られているものの1つは Apache Common ライブラリのセットです。これはオープンソースであり、コードをチェックして、これらを作成するためにこれらのユーティリティクラスをどのように設計するかを確認できます。 (免責事項:私はこれらのライブラリを使用したりサポートしたりしていません。私はそれらの幸せなユーザーです)

重要な注意: ユーティリティクラスにシングルトンを使用することは避けてください

41
Luiggi Mendoza

Java 8では、静的ユーティリティクラスを静的実装とのインターフェースに変更できるようになりました。これにより、クラスをfinalにしてプライベートコンストラクタを提供する必要がなくなります。 'to' interface 'と、もしあれば最終的なWordを削除します(すべてのインターフェイスは抽象的であるため、最終的にはできません)。インターフェイスメソッドは常にパブリックなので、パブリックスコープを削除できます。プライベートコンストラクタがある場合は削除します(コンストラクターはインスタンス化できないため、コンストラクターを使用してインターフェイスをコンパイルすることはできません。)コードが少なく、見た目もきれいです。既に使用しているクラスをリファクタリングする必要はありません。

13
afenkner

サブクラス化やインスタンス化について心配する必要はありません。 JDKの次のユーティリティクラスはサブクラス化またはインスタンス化できますが、これらのクラスは長年にわたって誤用されていません。人々はthatバカではありません。

Java.beans.Beans
Java.beans.PropertyEditorManager
Java.lang.invoke.LambdaMetafactory
Java.lang.reflect.Modifier
Java.net.URLDecoder                                   ...but not URLEncoder:)
javax.management.DefaultLoaderRepository
javax.management.Query
javax.management.loading.DefaultLoaderRepository
javax.management.relation.RoleStatus
javax.print.ServiceUI
javax.swing.UIManager
javax.swing.plaf.basic.BasicBorders
javax.swing.plaf.basic.BasicGraphicsUtils
javax.swing.plaf.basic.BasicHTML
javax.swing.plaf.basic.BasicIconFactory
javax.swing.plaf.metal.MetalBorders
javax.swing.plaf.metal.MetalIconFactory
javax.swing.text.Utilities
javax.swing.text.html.HTML

ただし、パブリックAPIとして、デフォルトのコンストラクターを抑制したい場合があります。そうしないと、javadocページに文書化されていないコンストラクターがあり、扱いにくく混乱を招きます。独自の社内APIの場合、重要ではなく、誰も気にしません。

ただし、サブクラス化を抑制する理由はありません。何らかの理由でユーティリティクラスをサブクラス化する場合は、許可してください。もちろん、プライベートコンストラクターは、副作用としてサブクラス化を抑制します。


Java8では、考慮すべき設計の可能性がさらにあります-

すべての静的メソッドを備えたインターフェース-これは、すべての静的メソッドを備えたクラスと同じくらい優れています。インターフェイスもクラスもこの目的のために設計されていないため、どちらでも構いません。ただし、これらの静的メソッドをインターフェイスのサブタイプで継承することを期待しないでください。インターフェイスの静的メソッドは継承できません。インターフェースを使用する1つのプラス点は、javadocにデフォルトのコンストラクターが表示されるのを抑制する必要がないことです。

すべてのデフォルトメソッドを備えたインターフェース-継承を通じてアクセスされます。これはおもしろいですが、一般的には問題があります(継承は非静的コンテキストでのみ機能します)。しかし、この html builder APIなど、一部のAPI設計ではより良いオプションになる可能性があります。

4
ZhongYu

他のクラスに「ツール」を提供するメソッドがあるだけなら、それは良い習慣ではないのはなぜですか。

1
Mirko

静的メソッドのみを持つクラスは、ユーティリティメソッドのJavaの一般的なパターンです。標準ライブラリの例には、 FilesCollections 、および- 実行者

このようなユーティリティクラスの場合、クラスの意図を明確にするために、クラスをインスタンス化できないようにすることをお勧めします。そのためには、プライベートコンストラクターを明示的に宣言します。詳細については、Josh Blochによる「Effective Java」の Item 4:プライベートコンストラクターによる非インスタンス化の強制 を参照してください。

1
markusk

コンテキストに応じて、シングルトンでも構いません。

テストの目的で、単体テストへの参照をモックアウトして、単体テスト中の副作用を回避することができます。その場合、Springなどの依存性注入フレームワークを使用してインスタンスの作成を処理し、静的メソッドの代わりにオーバーライドできる通常のメソッドを使用することはおそらく理にかなっています。

それでも静的メソッドを使用する予定がある場合は、マルチスレッドコンテキストで使用する場合は、呼び出しがスレッドセーフであることを確認してください。 (例:ダブルチェックロック)。

1
Jin Kim