Javaで定数のクラスをどのように定義しますか?


89

定数を保持するだけのクラスを定義する必要があるとします。

public static final String SOME_CONST = "SOME_VALUE";

これを行うための好ましい方法は何ですか?

  1. インターフェース
  2. 抽象クラス
  3. ファイナルクラス

どちらを使用する必要があり、その理由は何ですか?


いくつかの回答の明確化:

列挙型-列挙型は使用しません。何も列挙しません。互いに関連のない定数を収集するだけです。

インターフェイス-インターフェイスを実装するクラスとして設定するつもりはありません。インターフェイスを使用して、次のような定数を呼び出したいだけですISomeInterface.SOME_CONST


ここにいくつかの同様の議論があります:stackoverflow.com/questions/320588/…。インスタンス化できないように、プライベートコンストラクターでfinalクラスを使用します。
ダン・ダイアー

2
申し訳ありませんが、「列挙型を使用しない」は、この質問を「愚かなことをするための最良の方法は何ですか?」に変えます。
cletus 2009年

私はあなたがインターフェースを実装しようとしていると言っているのではありません。しかし、それを行うためにインターフェースを使用する意味はありません。だから、最後のクラスに行く
:)

列挙型の問題は何ですか?いつでもこれを使用して、「互いに関連のないいくつかの定数」を収集できます。うーん?
gedevan 2009年

5
概念的には、定数が関連していない場合、列挙型は悪い選択です。列挙型は、同じタイプの代替値を表します。これらの定数は代替ではなく、同じタイプでさえない場合があります(一部は文字列、一部は整数など)
Dan Dyer

回答:


92

最終クラスを使用します。簡単にするために、静的インポートを使用して、値を別のクラスで再利用できます。

public final class MyValues {
  public static final String VALUE1 = "foo";
  public static final String VALUE2 = "bar";
}

別のクラスで:

import static MyValues.*
//...

if(variable.equals(VALUE1)){
//...
}

4
ここで別のクラスを作成する利点はどこにありますか?私は通常、Calendar APIを設計の良い例として掲げていませんが、「カレンダー関連の定数はCalendarクラスにある」という点では問題ありません。
Jon Skeet

7
利点は、複数のクラスで定数を再利用する必要がある場合に、コードを複製しないことです。これの利点は簡単にわかると思います。
user54579 2009年

2
なぜコードを複製するのですか?他のクラスを参照してください。定数が実際に独立していることは比較的まれです。
Jon Skeet

14
読みやすくするために、本文(および一致するコメント)のないプライベートなデフォルトコンストラクターもあります。
Ran Biron

5
かなり古い答えであり、このコメントはおそらくVALUE1.equals(variable)場違いですが、NPEを回避するために使用します。
aakash 2017年

38

あなたの説明は次のように述べています。「私は列挙型を使用するつもりはありません。何も列挙するつもりはありません。相互に関連のない定数を収集するだけです。」

定数がまったく関連していない場合、なぜそれらを一緒に収集したいのですか?各定数を、最も密接に関連しているクラスに配置します。


2
ジョン-それらはすべて同じ機能に属しているという意味で関連しています。ただし、それらは何も列挙されていません...オブジェクトが「それらの1つ」であるというプロパティを保持していません。
ユーバルアダム

13
はい。その場合は、関連する機能に最も近いクラスにそれらを配置するだけです。
Jon Skeet

26

私の提案(好みの降順):

1)それをしないでください。最も関連性の高い実際のクラスに定数を作成します。「定数のバッグ」クラス/インターフェースを持つことは、実際にはOOのベストプラクティスに従っていません。

私と他のみんなは時々#1を無視します。あなたがそれをするつもりなら、それから:

2)プライベートコンストラクターを使用した最終クラスこれにより、定数に簡単にアクセスできるように拡張/実装することで、少なくとも誰かが「定数のバッグ」を悪用するのを防ぐことができます。(私はあなたがこれをしないと言ったことを知っています-しかしそれはあなたがそうしない後に誰かがやって来るという意味ではありません)

3)インターフェースこれは機能しますが、#2で悪用の可能性について言及している私の好みではありません。

一般に、これらが定数であるからといって、通常のオブジェクト指向の原則を適用してはならないという意味ではありません。1つのクラスだけが定数を気にする場合、それはプライベートであり、そのクラスに含まれている必要があります。テストだけが定数を気にする場合は、本番コードではなく、テストクラスに含める必要があります。定数が複数の場所で定義されている場合(偶然に同じではない)-重複を排除するためにリファクタリングします。など-あなたが方法と同じようにそれらを扱います。


2
1の問題は、定数をフェッチするためだけに、コードに別の層クラスへの依存関係を挿入する場合があることです。
amdev 2018

インターフェイスのすべてのフィールドは、暗黙的に、公共の静的および最終的なものである
Kodebetter

@Kodebetterただし、インターフェースを拡張/実装して、フィールドを追加することができます。
ウィット

12

JoshuaBlochがEffectiveJavaで述べているように:

  • インターフェイスは、タイプを定義するためにのみ使用する必要があります。
  • 抽象クラスは不安定性を防ぐことはできません(サブクラス化することができ、サブクラス化するように設計されていることを示唆することさえあります)。

すべての定数が関連している場合(惑星名など)に列挙型を使用するか、関連するクラスに定数値を配置する(アクセスできる場合)か、インスタンス化できないユーティリティクラスを使用する(プライベートデフォルトコンストラクターを定義する)ことができます。 。

class SomeConstants
{
    // Prevents instanciation of myself and my subclasses
    private SomeConstants() {}

    public final static String TOTO = "toto";
    public final static Integer TEN = 10;
    //...
}

次に、すでに述べたように、静的インポートを使用して定数を使用できます。


7

私の好みの方法は、それをまったく行わないことです。Java 5がタイプセーフな列挙型を導入したとき、定数の時代はほとんどなくなりました。そしてその前でさえ、Josh Blochはそれの(もう少し言葉の多い)バージョンを公開しました。これはJava 1.4(およびそれ以前)で動作しました。

いくつかのレガシーコードとの相互運用性が必要でない限り、名前付きの文字列/整数定数を使用する理由はもうありません。


2
良い答えです、例が良いでしょう。
amdev 2018

3

最終クラスを使用するだけです。

他の値を追加できるようにしたい場合は、抽象クラスを使用してください。

インターフェイスを使用することはあまり意味がありません。インターフェイスはコントラクトを指定することになっています。いくつかの定数値を宣言したいだけです。



3

enumsは大丈夫です。IIRC、効果的なJava(2nd Ed)の1つの項目には、任意の値に対してenum[Javaキーワード]interfaceを実装する標準オプションを列挙する定数があります。

私の好みは、[Javaキーワード]を使用することですinterfacefinal classの定数のために。暗黙的にを取得しpublic static finalます。interface悪いプログラマーがそれを実装することを許可すると主張する人もいますが、悪いプログラマーはあなたが何をしてもひどいコードを書くでしょう。

どちらが良く見えますか?

public final class SomeStuff {
     private SomeStuff() {
         throw new Error();
     }
     public static final String SOME_CONST = "Some value or another, I don't know.";
}

または:

public interface SomeStuff {
     String SOME_CONST = "Some value or another, I don't know.";
}

しかし、悪いプログラマーは、あなたが何をしようとも、ひどいコードを書くでしょう。それは本当です。悪いプログラミングを軽減するための措置を講じることができる場合、またはそれを完全に排除することができる場合は、それを行う責任が少しあります。できるだけ明確にする。悪いプログラマーは最終クラスを拡張できません。
liltitus27 2013年

1
@ liltitus27ある程度同意します。しかし、あなたは本当に、貧しいプログラマーが悪いコードを書く一方向を止めるためだけに、醜いコードが欲しいですか?彼らが生成するコードはまだ絶望的ですが、今ではあなたのコードは読みにくくなっています。
トムホーティン-タックライン2013年

1

または4.定数を最も使用するロジックを含むクラスにそれらを配置します

...申し訳ありませんが、抵抗できませんでした;-)


3
これは良い考えではありません。これにより、クラス間に依存関係が作成されます。
ユーバルアダム

何故なの?とにかく同じ定数を使用するクラスには依存関係があると思います...そしてどういうわけか、これらの定数に最も依存しているクラスが1つあるに違いありません。
Simon Groenewolt 2009年

定数を使用するクラスが1つしかない場合、これは理にかなっています。
トムホーティン-タックライン2013年

-1
  1. プライベートコンストラクターの欠点の1つは、メソッドの存在をテストできないことです。

  2. 特定のドメインタイプに適用するのに適した性質の概念による列挙型、分散定数に適用するのは十分ではないように見えます

列挙型の概念は、「列挙型は密接に関連するアイテムのセットです」です。

  1. 定数インターフェイスを拡張/実装することは悪い習慣です。不変の定数を直接参照するのではなく、拡張する要件について考えるのは困難です。

  2. SonarSourceのような高品質のツールを適用する場合、開発者に一定のインターフェイスを削除するように強制するルールがあります。多くのプロジェクトが一定のインターフェイスを楽しんでおり、一定のインターフェイスで「拡張」が発生することはめったにないため、これは厄介なことです。


1
「プライベートコンストラクターは、メソッドの存在をテストできなかった」:真実ではありません。あなた(またはあなたの上司)がコードカバレッジレポートが100%であることを本当に妄想している場合でも、リフレクションを使用してコンストラクターが例外をスローすることを確認することで、これをテストできます。しかし、私見ですが、これは形式的なものであり、実際にテストする必要はありません。あなた(またはチーム)が本当に重要なことだけを本当に気にしているのであれば、100%のラインカバレッジは必要ありません。
L. Holandaの
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.