定数を定義するインターフェースを持つのは悪い習慣ですか?


40

Javaでjunitテストクラスのセットを書いています。さまざまなテストクラスで必要な文字列など、いくつかの定数があります。それらを定義し、すべてのテストクラスがそれを実装するインターフェイスについて考えています。

私が見る利点は次のとおりです。

  • 定数への簡単なアクセス:MY_CONSTANT代わりにThatClass.MY_CONSTANT
  • 各定数は一度だけ定義されます

このアプローチはむしろ良い習慣ですか、悪い習慣ですか?インターフェイスの概念を少し乱用したい気がします。

インターフェイス/定数について一般的に答えることができますが、特別なことがあれば単体テストについても答えることができます。


「インターフェースにXを定義させるのは悪い習慣ですか?」に対する答えは、「メソッドシグネチャ」ではないXであるため、ほとんどの場合必ず「はい」です。
T.サール-復活モニカ

回答:


79

ジョシュア・ブロッホは、彼の著書「Effective Java」でこれに反対しています

クラスが内部でいくつかの定数を使用することは、実装の詳細です。定数インターフェイスを実装すると、この実装の詳細がクラスエクスポートされたAPIにリークします。クラスが定数インターフェースを実装することは、クラスのユーザーにとって重要ではありません。実際、混乱させることさえあります。さらに悪いことに、これはコミットメントを表しています。将来のリリースでクラスを変更して定数を使用する必要がなくなった場合でも、バイナリ互換性を確保するためにインターフェイスを実装する必要があります。

定数を定義する通常のクラスで同じ効果を得ることができ、次に使用します import static com.example.Constants.*;


13

私たちの場合、定数の値は、サービス実装が提供する必要がある最終状態の契約を表すため、これを行っています。これらの定数をインターフェイスに配置すると、コントラクトの一部として終了状態が指定され、インターフェイスの実装がそれらを使用しなかった場合、そのジョブは実行されません。

SOMETIMES定数は実装の詳細です。時々そうではありません。いつものように、エンジニアは自分の脳を使って何をすべきかを決定する必要があり、抜本的なパターンや練習に頼る必要はありません。


7

定数専用のインターフェイスを持つのは良いことだとは思いません。

しかし、振る舞いを定義するインターフェース(クラスを実装するメソッドが実装する必要がある)に定数がある場合、それは問題ありません。APIに「実装者の詳細を漏らしている場合、それが本来あるべき方法だからです。また、実装者がfooメソッドとbarメソッドを実装していることも漏れています。

たとえば、java.awt.Transparencyインターフェイスを取り上げます。OPAQUE、BITMASK、およびTRANSLUCENT定数がありますが、getTransparency()メソッドもあります。

設計者がこれらの定数をそこに配置すると、getTransparency()のように、インターフェースの一部として十分安定していると考えたためです。


2

これは、契約による設計が一般的な場所で最も人気のある視点だと思います。
インターフェイスは契約です。インターフェイスに定数を配置するということは、契約を順守するすべてのクラスが、定数によって識別される値/概念に同意することを意味します。


1
インターフェイスは公開契約です。定数VALUESはプライベートな関心事であり、パブリックインターフェイスはせいぜいその名前を公開する必要があります。それは抽象クラスに任せるのが最善です。
11

適切な事例:javax.naming.Context、javax.ims.Session、および数百のそのようなインターフェース
...-CMR

2
@jwentingまた、パブリックインターフェイス"at most expose their names"は、値を公開せずにできますか?
CMR

それは私が推測するプログラミング言語に依存するでしょう。Javaの場合、いいえ。
jwenting

2

私が働いていた会社は、インターフェイスでインポートされた1つの定数を多用していました。害は感じません。

あなたが自問すべき質問は、あなたにとって名前空間の重要性です。定数の場合、それはクラスが実際に機能するすべてです。数千の定数がある場合、これらの定数のすべてを常に使用可能にしたくない場合があります。

インターフェースの素晴らしい点は、どちらの方法でも機能することです-必要なすべての名前空間を取り込むか、それらの名前空間をまったく取り込まない(および明示的にアクセスするMyInterface.CONSTANT)ことです。とほぼ同じですimport static MyInterface.*が、もう少し明白です。


1:Javaに精通していない場合、importキーワードという意味ではなく、implements MyConstantsInterface


1

私は主に「Adaの方法」と「.Netの方法」に主に影響される背景から来ています。おそらく、インターフェイス内で定数を宣言するのは最善ではないということです。技術的にはc#では許可されていません。

私がノーと言う理由は、インターフェースは状態や構造ではなく、振る舞いを定義するコントラクトの形式だからです。定数は、ある種の状態(プリミティブ)、または状態の側面(複合または集約)を意味します。

インターフェイスを実装するすべての人がデフォルトと事前定義された値を使用できるようにしたいのですが、デフォルト状態は抽象または値オブジェクトまたはテンプレートで説明する方が良いでしょう。

より技術的なガイド:download.oracle.com/javase/1.5.0/docs/guide/language/static-import.html


Static Import(1.5)を参照するリンクを追加します。1. ウィキペディア 2. @Justincを参照するOracle Docs
Abhijeet

1
So when should you use static import? Very sparingly! Only use it when you'd otherwise be tempted to declare local copies of constants, or to abuse inheritance (the Constant Interface Antipattern). In other words, use it when you require frequent access to static members from one or two classes. If you overuse the static import feature, it can make your program unreadable and unmaintainable, polluting its namespace with all the static members you import. Oracle Docs
-Abhijeet

1

いいえ、それは一般的な悪い練習ではありません。

重要なことは、最小限の可視性と適切な抽象化レベルのルールの下で、他のアーティファクトとしての定数を導入する必要があるということです。

できるという理由だけで構文を使用するのが本当の問題です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.