Javaで定数を実装する最良の方法は何ですか?[閉まっている]


372

私はこのような例を見てきました:

public class MaxSeconds {
   public static final int MAX_SECONDS = 25;
}

そして、定数をラップして、静的なfinalを宣言するためのConstantsクラスがあると想定しました。私はJavaをまったく知らないので、これが定数を作成する最良の方法かどうか疑問に思っています。



回答:


403

それは、おそらく標準でさえ、完全に受け入れられます。

(public/private) static final TYPE NAME = VALUE;

ここTYPEで、はタイプ、NAMEはスペースを含む下線付きのすべて大文字の名前、はVALUE定数値です。

定数を独自のクラスまたはインターフェイスに配置しないことを強くお勧めします。

余談ですが、最終的に宣言されていて変更可能な変数は、引き続き変更できます。ただし、変数が別のオブジェクトを指すことはありません。

例えば:

public static final Point ORIGIN = new Point(0,0);

public static void main(String[] args){

    ORIGIN.x = 3;

}

これは合法でありORIGIN、(3、0)がポイントになります。


19
「静的MaxSeconds.MAX_SECONDS;をインポート」することもできます。MaxSeconds.MAX_SECONDS
Aaron Maenpaa

23
静的インポートに関する前述のコメントは、Java 5以降にのみ適用されます。定数がどこから来たのかについて、略記は混乱の可能性がないと感じている人もいます。長いコードを読む場合、MaxSeconds.MAX_SECONDSの方が簡単に追跡でき、インポートを確認できます。
MetroidFan2002 2008

5
jjnguyが示したようにobjetcを変更できるので、constatnsが不変オブジェクトまたは単純なプリミティブ/文字列の場合に最適です。
marcospereira 2008

14
この質問を読んでいる場合は、この回答を真剣に受け止める前に、以下の2つの回答を読んでください。
orbfish

3
@jjnguyあなたは間違っていませんが、質問とあなたの回答の最初の数行だけを読んだ場合、「定数クラス」は「完全に受け入れられ、おそらく標準でさえある」という印象を受けます。その概念間違っています。
Zach Lysobey 2013年

235

単一の定数クラスを持たないことを強くお勧めします。当時は良い考えのように思えるかもしれませんが、開発者が定数のドキュメント化を拒否し、クラスが500を超える定数に包含されるようになると、それらは互いにまったく関連がない(アプリケーションの完全に異なる側面に関連している)場合、これは通常、定数ファイルは完全に読み取り不可能になります。代わりに:

  • Java 5+にアクセスできる場合は、列挙型を使用して、アプリケーション領域の特定の定数を定義します。アプリケーション領域のすべての部分は、これらの定数の定数値ではなく列挙型を参照する必要があります。クラスを宣言する方法と同様の列挙を宣言できます。列挙型はおそらくJava 5+の最も便利な(そして間違いなく唯一の)機能です。
  • 特定のクラスまたはそのサブクラスの1つに対してのみ有効な定数がある場合、それらを保護またはパブリックとして宣言し、階層の最上位クラスに配置します。このように、サブクラスはこれらの定数値にアクセスできます(他のクラスがパブリック経由でそれらにアクセスする場合、定数は特定のクラスに対してのみ有効ではありません...つまり、この定数を使用する外部クラスは、定数を含むクラス)
  • 動作が定義されたインターフェースがあり、戻り値または引数値が特定である必要がある場合、そのインターフェースで定数を定義して、他の実装者がそれらにアクセスできるようにすることは完全に許容されます。ただし、定数を保持するためだけにインターフェースを作成することは避けてください。定数を保持するためだけに作成されたクラスと同じくらい悪くなる可能性があります。

12
完全に同意します...これは、大規模プロジェクトの古典的なアンチパターンとして文書化できます。
Das

30
オフトピックですが...ジェネリックスは完全ではありませんが、Java 5の便利な機能であるジェネリックをかなり良い例にできると思います:)
Martin McNulty

3
@ŁukaszL。質問自体は本当に意見に基づいているため(「最善」が発生する場合は、通常、それは意見の問題です)、答えはこの質問に対する有効な答えです。Javaに定数を実装する最良の方法は、何であるか(そうだと思います。そうです、そうです、それは意見です。これも、「最良の」変化は時間とともに変化し、一般に意見に基づいているためです)。
MetroidFan2002、2014年

1
上記のオプションのいずれも、真のグローバル変数を提供しません。どこでも使用されているが列挙型ではないものがある場合はどうなりますか?列挙型は1つだけですか?
markthegrea 14年

1
すべてのモジュールにまたがるグローバル定数が必要な場合は、おそらく設計戦略に問題があります。グローバル定数が本当に必要な場合は、最上位のパッケージでパブリックな最終クラスを作成し、そこに貼り付けます。次に、すべてのクラスが実際にその定数を必要としているわけではないことに気づいたらすぐに削除し、それを最も参照しているパッケージに移動します。など、あなたは、パッケージ全体で定数を共有することができますが、列挙型が行動を持つことができるよう、列挙型ではありませんグローバル定数を必要とするコードのにおいですが、文字列は、文字列で、int型はintです
MetroidFan2002を

120

定数を保持するためだけにインターフェースを使用するのは悪い習慣です(Josh Blochによって名前が付けられた定数インターフェースパターン)。Joshのアドバイスは次のとおりです。

定数が既存のクラスまたはインターフェースに強く結びついている場合は、それらをクラスまたはインターフェースに追加する必要があります。たとえば、IntegerやDoubleなどのすべてのボックス化された数値プリミティブクラスは、MIN_VALUEおよびMAX_VALUE定数をエクスポートします。定数は最高の列挙型のメンバーとして表示されている場合は、それらをエクスポートする必要があります列挙 タイプ。それ以外の場合は、インスタンス化できないユーティリティクラスを使用して定数をエクスポートする必要があります。

例:

// Constant utility class
package com.effectivejava.science;
public class PhysicalConstants {
    private PhysicalConstants() { }  // Prevents instantiation

    public static final double AVOGADROS_NUMBER   = 6.02214199e23;
    public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    public static final double ELECTRON_MASS      = 9.10938188e-31;
}

命名規則について:

慣例により、そのようなフィールドは、アンダースコアで区切られた単語で大文字で構成される名前を持っています。これらのフィールドにプリミティブ値または不変オブジェクトへの参照が含まれていることが重要です。


23
あなたが何か悪い習慣を呼ぶつもりなら、おそらくあなたはそれがなぜだと思うのかを説明する必要がありますか?
GlennS

14
これは古い投稿ですがabstract、プライベートコンストラクターの代わりにクラスの表記を使用することをお勧めします。
Xtreme Biker 2013

5
マット、バイカーの推奨は間違いではありませんが、私は抽象的なクラスではなく、最終クラスを推奨します。それは、定数クラスが変更可能でないことを確認したいということでした。したがって、これをfinalとしてマークすると、サブクラス化またはインスタンス化できなくなります。これは、静的な機能をカプセル化するのにも役立ち、他の開発者がそれをサブクラス化して、それが行うように設計されていないことを行うことを許可しません。
liltitus27

7
@XtremeBiker abstractプライベートコンストラクタの代わりにクラスをマークしても、インスタンス化が完全に妨げられるわけではありません。サブクラス化してサブクラスをインスタンス化できるからです(そうするのは良い考えではありませんが、可能です)。@ToolmakerSteveサブクラスのコンストラクターは、そのスーパークラスの(現在はプライベートな)コンストラクターを呼び出す必要があるため、プライベートコンストラクターでクラスをサブクラス化することはできません(少なくとも大きなハックがなければ)。したがって、それをマークすることfinalは不要です(しかし、おそらくより明示的です)。
インポート

3
定数を保持するためだけにクラスを使用するのはさらに悪いことです。そのクラスのオブジェクトを作成したくない場合は、なぜ最初に通常のクラスを使用するのですか?
MaxZoom、

36

効果的なJava(第2版)では、定数に静的整数ではなく列挙型を使用することをお勧めします。

Javaの列挙型については、こちらの優れた記事をご覧ください。http: //java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

その記事の最後で提起された質問は次のとおりです。

では、いつ列挙型を使用する必要がありますか?

答えは:

定数の固定セットが必要なときはいつでも


21

インターフェースの使用は避けてください:

public interface MyConstants {
    String CONSTANT_ONE = "foo";
}

public class NeddsConstant implements MyConstants {

}

それは魅力的ですが、カプセル化に違反し、クラス定義の区別を曖昧にします。


1
実際、静的インポートがはるかに望ましいです。
Aaron Maenpaa 2008

1
これは、クラスの提供するサービスを記述することを目的としたインターフェースの奇妙な使い方です。
Rafa Romero

1
定数のインターフェースの使用を避けることに同意しますが、あなたの例は誤解を招くと思います。暗黙的に静的、パブリック、およびファイナルであるため、定数にアクセスするためにインターフェースを実装する必要はありません。したがって、ここで説明したよりも簡単です。
djangofan 2017年

それは本当です...それはカプセル化に違反しています。私は、インターフェイスOR enumよりもオブジェクト指向でより好ましい最終的なConstantクラスを使用することを好みます注: Androidが必要ない場合は、列挙型を回避できます。
CoDe、2017

19

私は次のアプローチを使用します:

public final class Constants {
  public final class File {
    public static final int MIN_ROWS = 1;
    public static final int MAX_ROWS = 1000;

    private File() {}
  }

  public final class DB {
    public static final String name = "oups";

    public final class Connection {
      public static final String URL = "jdbc:tra-ta-ta";
      public static final String USER = "testUser";
      public static final String PASSWORD = "testPassword";

      private Connection() {}
    }

    private DB() {}
  }

  private Constants() {}
}

たとえば、私はConstants.DB.Connection.URL定数を取得するために使用します。私にとっては、より「オブジェクト指向」に見えます。


4
興味深いが、扱いにくい。代わりに、他の人が推奨するように、それらに最も密接に関連するクラスに定数を作成しないのはなぜですか?たとえば、DBコードの他の場所に、接続用の基本クラスがありますか?たとえば「ConnectionBase」。次に、定数をそこに置くことができます。接続を処理するコードには、「Constants.DB.Connection.URL」ではなく、単に「ConnectionBase.URL」と言うことができるインポートが含まれている可能性があります。
ToolmakerSteve 2014

3
@ToolmakerSteveしかし、複数のクラスが使用できる一般的な定数はどうですか?たとえば、スタイル、WebサービスのURLなど...?
ダニエルゴメスリコ

すべての定数を1つのクラスに入れることには、メンテナンスという1つの利点があります。あなたは常に定数を見つける場所を正確に知っています。これがこのテクニックをより良くすることを言っているのではなく、ただ一つの利点を提供しているだけです。そして、@ albus.uaが行ったのは彼の定数を分類することです。これは特に、定数クラスに多くの定数値が含まれている場合は、かなり良い考えです。この手法は、クラスを管理しやすくし、定数の目的をよりよく説明するのに役立ちます。
Nelda.techspiress

17

別のクラスで静的な最終定数を作成すると、問題が発生する可能性があります。Javaコンパイラはこれを実際に最適化し、定数の実際の値をそれを参照するクラスに配置します。

後で「定数」クラスを変更し、そのクラスを参照する他のクラスでハード再コンパイルを行わない場合は、使用されている古い値と新しい値の組み合わせになってしまいます。

これらを定数と考えるのではなく、構成パラメーターと考えて、それらを管理するクラスを作成します。値は最終ではなく、ゲッターの使用も検討してください。将来的には、これらのパラメーターの一部をユーザーまたは管理者が実際に構成できるようにする必要があると判断した場合、その方がはるかに簡単になります。


この優れた警告の+1。(あなたはbig_peanut_horseは言及して、代わりにゲッターを検討し、それが永久に一定の保証ができない場合。)同じ方法で、C#でのconstに適用されます。msdn.microsoft.com/en-us/library/e6w8fe1b.aspx
ジョンクームズ14年

13

あなたが犯しうる最大の間違いは、定数のような総称名で呼び出されるグローバルにアクセス可能なクラスを作成することです。これは単にゴミでいっぱいになり、システムのどの部分がこれらの定数を使用しているかを理解するすべての能力を失います。

代わりに、定数はそれらを「所有する」クラスに入れる必要があります。TIMEOUTという定数がありますか?おそらくCommunications()またはConnection()クラスに入るはずです。MAX_BAD_LOGINS_PER_HOUR?User()に入ります。等々。

実行時に「定数」を定義できるが、ユーザーが簡単に変更できない場合は、Java .propertiesファイルも使用できます。これらを.jarにパッケージ化して、クラスresourceLoaderで参照できます。


そしてもちろん、複数のクラスから定数にアクセスしたり、クラスの先頭で混乱を避けたりすることは決してありません。
orbfish 2014年

6

それが正しい方法です。

通常、定数は検出できないため、個別の「定数」クラスに保持されません。定数が現在のクラスに関連している場合、それらをそこに保持することは、次の開発者に役立ちます。



5

定数ではなくゲッターを使用することを好みます。これらのゲッターは定数値を返す場合があります。public int getMaxConnections() {return 10;}、定数を必要とするものはすべてゲッターを通過します。

1つの利点は、プログラムが定数を超えた場合(構成可能である必要があることがわかった場合)、ゲッターが定数を返す方法を変更できることです。

他の利点は、定数を変更するために、それを使用するすべてを再コンパイルする必要がないことです。静的最終フィールドを参照すると、その定数の値は、それを参照するバイトコードにコンパイルされます。


5
参照クラスを適切に再コンパイルすることは、21世紀の負担にはなりません。そして、あなたは物事のためのアクセサ/ミューテータ(ゲッター/セッター)モデルを使用しないでください他のメンバ変数にアクセスし、変異より。定数は概念的には本質的に即値であることを意味し、ゲッター/セッターは(両方)状態を管理することを意味します。その上、あなたはただ混乱を求めているだけです:人々はゲッターが単なる定数を生み出すことを期待しないでしょう。

5

インターフェースを使用することは、進むべき道ではないことに同意します。このパターンを回避すると、Blochの効果的なJavaに独自の項目(#18)さえ含まれます

Blochが定数インターフェースパターンに対して行う議論は、定数の使用は実装の詳細ですが、定数を使用するためのインターフェースを実装すると、エクスポートされたAPIにその実装の詳細が公開されます。

public|private static final TYPE NAME = VALUE;パターンは定数を宣言するのは良い方法です。個人的には、すべての定数を格納する個別のクラスを作成しない方がいいと思いますが、個人的な好みやスタイル以外に、これを行わない理由を私は見たことがありません。

定数が列挙型として適切にモデル化できる場合は、1.5以降で使用可能な列挙型構造を検討してください。

1.5より前のバージョンを使用している場合でも、通常のJavaクラスを使用して型保証された列挙を引き出すことができます。(詳細については、このサイトを参照してください)。


一部の定数は、APIの呼び出しに使用できます。たとえば、インターフェースorg.springframework.transaction.TransactionDefinitionを参照してください。これには、int PROPAGATION_REQUIRED = 0などの定数のリストがあります。
ボルジャブ2015

これは古いのですが、Blochの効果的なJavaへのリンクが壊れています。「インターフェースを使用するのは道ではない」ということを裏付ける別のリファレンスを提供してもらえますか?
Nelda.techspiress

4

上記のコメントに基づいて、これは(静的な最終的なパブリック変数を持つ)昔ながらのグローバル定数クラスを次のような方法で列挙型の同等のものに変更するための良いアプローチだと思います:

public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public interface ConstantType {}

    public enum StringConstant implements ConstantType {
        DB_HOST("localhost");
        // other String constants come here

        private String value;
        private StringConstant(String value) {
            this.value = value;
        }
        public String value() {
            return value;
        }
    }

    public enum IntConstant implements ConstantType {
        DB_PORT(3128), 
        MAX_PAGE_SIZE(100);
        // other int constants come here

        private int value;
        private IntConstant(int value) {
            this.value = value;
        }
        public int value() {
            return value;
        }
    }

    public enum SimpleConstant implements ConstantType {
        STATE_INIT,
        STATE_START,
        STATE_END;
    }

}

だから私はそれらを次のように参照することができます:

Constants.StringConstant.DB_HOST

4
どうして?それはどのように改善されましたか?すべての参照が面倒です(Constants.StringConstant.whatever)。私見、あなたはここででこぼこの道を進んでいます。
ToolmakerSteve 14

3

優れたオブジェクト指向の設計では、公開されている多くの定数を必要としません。ほとんどの定数は、その機能を実行する必要があるクラスにカプセル化する必要があります。


1
または、コンストラクタを介してそのクラスに注入されます。
WW。

2

これに答えるにはある程度の意見があります。まず第一に、Javaの定数は一般にpublic、static、finalとして宣言されています。理由は以下のとおりです。

public, so that they are accessible from everywhere
static, so that they can be accessed without any instance. Since they are constants it
  makes little sense to duplicate them for every object.
final, since they should not be allowed to change

インターフェイスが一般的に実装されることが期待されているため、単にCONSTANTSアクセサー/オブジェクトのインターフェイスを使用することはありません。これはおかしく見えませんか?

String myConstant = IMyInterface.CONSTANTX;

代わりに、いくつかの小さなトレードオフに基づいて、いくつかの異なる方法から選択するので、必要なものによって異なります。

1.  Use a regular enum with a default/private constructor. Most people would define 
     constants this way, IMHO.
  - drawback: cannot effectively Javadoc each constant member
  - advantage: var members are implicitly public, static, and final
  - advantage: type-safe
  - provides "a limited constructor" in a special way that only takes args which match
     predefined 'public static final' keys, thus limiting what you can pass to the
     constructor

2.  Use a altered enum WITHOUT a constructor, having all variables defined with 
     prefixed 'public static final' .
  - looks funny just having a floating semi-colon in the code
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you still have to put explicit 'public static final' before each variable
  - drawback: not type-safe
  - no 'limited constructor'

3.  Use a Class with a private constructor:
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you have to put explicit 'public static final' before each variable
  - you have the option of having a constructor to create an instance
     of the class if you want to provide additional functions related
     to your constants 
     (or just keep the constructor private)
  - drawback: not type-safe

4. Using interface:
  - advantage: you can JavaDoc each variable with an explanation
  - advantage: var members are implicitly 'public static final'
  - you are able to define default interface methods if you want to provide additional
     functions related to your constants (only if you implement the interface)
  - drawback: not type-safe

2

Javaで定数を実装する最良の方法は何ですか?

私たちが本当に避けるべき1つのアプローチ:定数を定義するためのインターフェースの使用。

特に定数を宣言するためのインターフェースを作成することは、実際に最悪のことです。それは、インターフェースが設計された理由、つまりメソッドコントラクトの定義を無効にすることです。

特定のニーズに対処するためのインターフェイスがすでに存在する場合でも、定数をクライアントクラスに提供するAPIおよびコントラクトの一部にすることはできないため、それらの定数を宣言しても意味がありません。


簡単にするために、4つの有効なアプローチがあります。

static final String/Integerフィールド:

  • 1)内部だけでなく内部で定数を宣言するクラスを使用する。
  • 1バリアント)定数の宣言のみに専用のクラスを作成します。

Java 5 enum

  • 2)関連する目的クラス(ネストされたクラスなど)で列挙型を宣言します。
  • 2バリアント)スタンドアロンクラスとして列挙型を作成する(独自のクラスファイルで定義されている)。

TLDR:どちらが最善の方法で、どこに定数を配置しますか?

ほとんどの場合、列挙型の方法は、よりおそらく細かいstatic final String/Integerと個人的に私がいることを考えるstatic final String/Integer方法は、我々は列挙型を使用しないように十分な理由がある場合にのみ使用されるべきです。
また、定数値を宣言する場所については、定数値を持つ特定の強力な機能的結合を所有する既存のクラスが1つあるかどうかを検索するという考えです。このようなクラスが見つかった場合は、定数ホルダーとして使用する必要があります。それ以外の場合、定数は特定のクラスに関連付けないでください。


static final String/ static final Integerenum

列挙型の使用は、実際に強く検討する方法です。
列挙型は、定数フィールドよりStringも優れていIntegerます。
彼らはより強力なコンパイル制約を設定しました。enumをパラメーターとして受け取るメソッドを定義する場合は、enumクラスで定義されたenum値(またはnull)のみを渡すことができます。
StringとIntegerを使用すると、互換性のある任意の値に置き換えることができ、値がstatic final String/ static final Integerフィールドで定義された定数でなくてもコンパイルは正常に行われます。

たとえば、クラスでstatic final Stringフィールドとして定義された2つの定数の下:

public class MyClass{

   public static final String ONE_CONSTANT = "value";
   public static final String ANOTHER_CONSTANT = "other value";
   . . .
}

ここでは、これらの定数の1つをパラメーターとして期待するメソッド:

public void process(String constantExpected){
    ...    
}

あなたはこのようにそれを呼び出すことができます:

process(MyClass.ONE_CONSTANT);

または

process(MyClass.ANOTHER_CONSTANT);

ただし、この方法で呼び出すことができないコンパイル制約はありません。

process("a not defined constant value");

エラーが発生するのは、実行時のみであり、送信された値のチェックを一度に行う場合のみです。

enumでは、クライアントがenumパラメータでenum値のみを渡すことができるため、チェックは必要ありません。

たとえば、次の2つの値は列挙型クラスで定義されています(そのままでは定数です)。

public enum MyEnum {

    ONE_CONSTANT("value"), ANOTHER_CONSTANT(" another value");

    private String value;

    MyEnum(String value) {
       this.value = value;
    }
         ...
}

ここでは、これらの列挙値の1つをパラメーターとして期待するメソッド:

public void process(MyEnum myEnum){
    ...    
}

あなたはこのようにそれを呼び出すことができます:

process(MyEnum.ONE_CONSTANT);

または

process(MyEnum.ANOTHER_CONSTANT);

しかし、コンパイルでは、このように呼び出すことはできません。

process("a not defined constant value");

定数をどこに宣言すればよいですか?

アプリケーションに、定数値を持つ特定の強力な機能的結合を所有する既存のクラスが1つ含まれている場合、1)と2)はより直感的に見えます。
一般に、定数を操作するメインクラスで宣言されている場合、または定数が内部で見つかると非常に自然な名前である場合、定数の使用が容易になります。

たとえば、JDKライブラリでは、定数とpiの定数値は、定数宣言(java.lang.Math)だけでなく、クラスでも宣言されています。

   public final class Math {
          ...
       public static final double E = 2.7182818284590452354;
       public static final double PI = 3.14159265358979323846;
         ...
   }

数学関数を使用するクライアントは、Mathクラスに頻繁に依存しています。そのため、定数を簡単に見つけることができ、場所Eを覚えPIて、非常に自然な方法で定義できます。

アプリケーションに、定数値との非常に具体的で強力な機能的結合を持つ既存のクラスが含まれていない場合、1つの方法)と2つの方法)の方がより直感的に見えます。
一般に、定数を操作する1つのクラスで宣言されている場合、定数の使用は容易ではありませんが、定数を操作する他の3つまたは4つのクラスがあり、これらのクラスのいずれかが他のクラスよりも自然ではないようですホスト定数値。
ここでは、定数値のみを保持するカスタムクラスを定義することは理にかなっています。
たとえば、JDKライブラリでは、java.util.concurrent.TimeUnit列挙型は特定のクラスで宣言されていません。保持するのに最も直感的に見えるJDK固有のクラスは実際には1つだけではないためです。

public enum TimeUnit {
    NANOSECONDS {
      .....
    },
    MICROSECONDS {
      .....
    },
    MILLISECONDS {
      .....
    },
    SECONDS {
      .....
    },
      .....
}      

多くのクラスはで宣言されたjava.util.concurrent:彼らが使用 BlockingQueueArrayBlockingQueue<E>CompletableFutureExecutorService、...そして実際にそれらの誰もがenumを保持するために、より適切と思いません。


1

任意の型の定数は、クラス(final修飾子を持つメンバー変数)内で不変のプロパティを作成することによって宣言できます。通常、staticおよび public修飾子も提供されます。

public class OfficePrinter {
    public static final String STATE = "Ready";  
}

定数の値が選択のnタプル(列挙型など)からの選択を示すアプリケーションは多数あります。この例では、割り当てられる可能性のある値を制限する列挙型を定義することを選択できます(つまり、改善された型安全性)。

public class OfficePrinter {
    public enum PrinterState { Ready, PCLoadLetter, OutOfToner, Offline };
    public static final PrinterState STATE = PrinterState.Ready;
}

1

単一の汎用定数クラスは悪い考えです。定数は、それらが最も論理的に関連しているクラスと一緒にグループ化する必要があります。

あらゆる種類の変数(特に列挙型)を使用するのではなく、メソッドを使用することをお勧めします。変数と同じ名前のメソッドを作成し、変数に割り当てた値を返すようにします。次に、変数を削除し、変数へのすべての参照を、作成したメソッドの呼び出しに置き換えます。定数が十分に汎用的であるため、それを使用するためだけにクラスのインスタンスを作成する必要がないと思われる場合は、定数メソッドをクラスメソッドにします。


1

FWIW、秒単位のタイムアウト値は、おそらく構成設定(プロパティファイルから読み込まれるか、Springのようにインジェクションを介して読み込まれる)であり、定数ではないはずです。


1

違いはなんですか

1。

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

2。

public class MyGlobalConstants {
    private MyGlobalConstants () {} // Prevents instantiation
    public static final int TIMEOUT_IN_SECS = 25;
}

そして、MyGlobalConstants.TIMEOUT_IN_SECSこの定数が必要なところはどこでも使用し ます。どちらも同じだと思います。


1
これは本質的には、bincobの回答に対するコメントのようです。私はそれらは非常に似た動作をすると思いますが、bincobの要点は、それらは決してインターフェースを定義しないということでした。また、MyGlobalConstantsスケルトンクラスを作成するのではなく、実際のクラスに定数を追加することを提案しました。(これは時々理にかなっていますが、インスタンス化を防ぐために静的定数とプライベートコンストラクターを使用して「静的クラス」を使用してください。java.lang.mathを参照してください。)列挙型の使用を検討してください。
Jon Coombs、

また、クラス宣言に "final"を入れると、サブクラス化が防止されます。(C#では、「静的」、つまり「最終的な抽象」を意味するため、明示的なプライベートコンストラクターは必要ありません。)
Jon Coombs

はい、@ JonCoombsですが、「final」は直接のインスタンス化を妨げません。また、Javaはfinalとabstractの両方をクラスに一緒に表示することを許可しないため、インスタンス化とサブクラス化の両方を防止するために無限に表示されるプライベートコンストラクターを使用します。「最終的な抽象」が許可されない理由はわかりませんが、一見すると、「サブクラス化することはできませんが、このクラスはサブクラス化することを意図しています」というように一見矛盾しています。

0

私は、クラスを定数と同じ(大文字小文字の区別を除いて)呼び出さないでしょう...すべての定数が存在する「設定」、「値」、または「定数」のクラスを少なくとも1つ持つことになります。それらが多数ある場合は、それらを論理定数クラス(UserSettings、AppSettingsなど)にグループ化します。


定数と呼ばれるクラスを持つことは、私が計画していたことでした、それは私が見つけたほんの小さな例でした。
mk。

0

さらに一歩進んで、グローバルに使用される定数をインターフェイスに配置して、システム全体で使用できるようにすることができます。例えば

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

しかし、それを実装しないでください。完全修飾クラス名を介してコードで直接参照するだけです。


インターフェースでそれらを宣言する(そしてそれを実装しない)ことのポイントは、「public static final」を見逃してしまう可能性があることです。
トムホーティン-タックライン

9
インターフェイスは、動作規約を定義するためのものであり、定数を保持するための便利なメカニズムではありません。
John Topley、

@JohnTopleyそうだね。;)
trusktr 2013年

0

定数の場合、EnumがIMHOのより良い選択です。ここに例があります

パブリッククラスmyClass {

public enum myEnum {
    Option1("String1", 2), 
    Option2("String2", 2) 
    ;
    String str;
            int i;

            myEnum(String str1, int i1) { this.str = str1 ; this.i1 = i }


}

0

私が行う方法の1つは、定数値を使用して「グローバル」クラスを作成し、定数へのアクセスを必要とするクラスで静的インポートを行うことです。



0

私が使う static final定数を宣言し、ALL_CAPS命名表記しています。私は、すべての定数が1つのインターフェイスにまとめられている実例を数多く見ました。いくつかの投稿では、主にそれがインターフェースの目的ではないため、これを悪い習慣と正しく呼んでいます。インターフェイスはコントラクトを強制する必要があり、無関係な定数を配置する場所であってはなりません。定数のセマンティクスが特定のクラスに属していない場合は、(プライベートコンストラクターを介して)インスタンス化できないクラスにまとめることもできます( es)。私は常にそれが最も関連しているクラスに定数を入れました。それは理にかなっていて、簡単に保守できるからです。

列挙型は値の範囲を表すのに適していますが、スタンドアロン値を絶対値に重点を置いて格納している場合(たとえば、TIMEOUT = 100ミリ秒)は、このstatic finalアプローチに進むことができます。


0

ほとんどの人が言っていることに同意します。定数のコレクションを扱うときは列挙型を使用するのが最善です。ただし、Androidでプログラミングしている場合は、IntDefアノテーションというより優れたソリューションがあります。

@Retention(SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST,NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
...
public abstract void setNavigationMode(@NavigationMode int mode);
@NavigationMode
public abstract int getNavigationMode();

IntDefアノテーションは、列挙型よりも1つの単純な方法で優れています。これは、コンパイル時のマーカーであるため、必要なスペースが大幅に少なくなります。クラスではなく、自動文字列変換プロパティもありません。


Javaでのみインターフェイスを使用せず、Androidで列挙型を回避するというベストプラクティスに同意しますが、Androidでのこの置換は、少数のフィールドを使用している場合にのみ機能します。大幅なメモリの節約ですが、混合列挙型のフィールドごとのインターフェイスであるため、肥大化につながる可能性があります。たとえば、オブジェクトがコンストラクタで取るものを定義する混合列挙型がある場合、このアプローチでは何も保存できず、Androidではクラス/インターフェイスの期間が多すぎないため、タイプセーフでない定数に戻ります。
ドロイドティーハウス2017

0

基本的なグラウンドゼロの原理主義を理解せずにジョシュアブロックを引用するのは、悪い習慣であり、ひどく迷惑な習慣です。

ジョシュア・ブロックは何も読んでいないので

  • 彼はひどいプログラマーです
  • または、私が彼を引用しているところまで見つけた人々(ジョシュアは私が推測する男の子の名前です)は、彼の資料を宗教的スクリプトとして単に使用して、ソフトウェアの宗教的な耽溺を正当化しています。

聖書の原理主義のように、すべての聖書の法則は

  • 心と心でファンダメンタルアイデンティティを愛する
  • 隣人を自分のように愛する

同様に、ソフトウェアエンジニアリングの原理主義は、

  • すべてのプログラミングの力と心で、ゼロゼロの基本に専念する
  • 自分と同じように、他のプログラマーの卓越性に専念します。

また、聖書の原理主義者サークルの間には、強力で合理的な帰結が描かれています

  • まず自分を愛してください。なぜなら、自分をあまり愛していない場合、「自分を隣人を愛する」という概念はそれほど重要ではありません。なぜなら、「自分をどれだけ愛するか」は、他の人を愛する基準線だからです。

同様に、プログラマーとして自分を尊重せず、ファンダメンタルズを問うことなく、いくつかのプログラミングの第一人者の発言と予言を受け入れるだけの場合、引用やジョシュアブロックなどへの依存は意味がありません。したがって、実際には他のプログラマを尊重することはできません。

ソフトウェアプログラミングの基本的な法則

  • 怠惰は良いプログラマの美徳です
  • あなたはあなたのプログラミング生活をできるだけ簡単にし、怠惰にし、それゆえ可能な限り効果的にすることです
  • あなたはあなたのプログラミングの結果と内臓をできるだけ簡単に、そして怠惰にして、あなたと協力してあなたのプログラミングの内臓を拾うあなたの隣のプログラマーのために可能な限り効果的にすることです。

インターフェイスパターン定数は悪い習慣ですか???

基本的に効果的で責任あるプログラミングのどの法律の下で、この宗教的勅令は当てはまりますか?

インターフェースパターン定数に関するウィキペディアの記事(https://en.wikipedia.org/wiki/Constant_interface)を読んでください。インターフェースパターン定数に対してそれを述べている愚かな言い訳です。

  • Whatif-No IDE?ソフトウェアプログラマとして一体誰がIDEを使用しないのでしょうか。私たちのほとんどは、IDEの使用を避けてマッチョな生存主義を証明する必要がないことを好むプログラマーです。

    • また、IDEを必要としない手段として、マイクロ関数型プログラミングの第2の支持者を待ちます。データモデルの正規化に関する私の説明を読むまでお待ちください。
  • 現在のスコープ内で使用されていない変数で名前空間を汚染しますか?この意見の支持者である可能性があります

    • データモデルの正規化を認識しておらず、その必要性がない
  • 定数を適用するためのインターフェースの使用は、インターフェースの乱用です。そのような支持者は悪い癖を持っています

    • 「定数」が契約として扱われる必要があることを見ていない。また、インターフェースは、契約へのコンプライアンスを実施または予測するために使用されます。
  • 将来、インターフェースを実装クラスに変換することは不可能ではないにしても困難です。はぁ……。うーん……?

    • なぜあなたはしつこい生計のようなプログラミングのパターンに従事したいのですか?IOW、なぜそのような大胆で悪いプログラミング習慣に専念するのですか?

言い訳が何であれ、インターフェース定数の使用を非合法化または一般的に阻止する根本的に効果的なソフトウェアエンジニアリングに関しては、有効な言い訳はありません。

アメリカ合衆国憲法を作成した創設者の父親の本来の意図と精神状態が何であったかは関係ありません。私たちは創設者の父親の当初の意図について議論することができますが、私が気にするのは米国憲法の書かれた声明だけです。そして、合衆国憲法の書かれていない創設意図ではなく、書かれた文学的基礎主義を利用することは、すべての米国市民の責任です。

同様に、Javaプラットフォームとプログラミング言語の創設者の「元の」意図がインターフェースに対して何を持っているかは気にしません。私が気にしているのは、Java仕様が提供する効果的な機能であり、それらの機能を最大限に活用して、責任あるソフトウェアプログラミングの基本的な法則を実行できるようにするつもりです。「インターフェースの意図に違反する」と認識されてもかまいません。GoslingやBlochが「Javaを適切に使用する方法」について何を言っているかは気にしません。

基本はデータモデルの正規化です

データモデルがどのようにホストまたは送信されるかは関係ありません。データモデルの正規化の必要性とプロセスを理解していない場合は、インターフェイスを使用するか、列挙型を使用するか、リレーショナルまたはSQLなしを使用するか。

まず、一連のプロセスのデータモデルを定義して正規化する必要があります。そして、一貫性のあるデータモデルがある場合、そのコンポーネントのプロセスフローを使用して、機能的な動作を定義し、アプリケーションのフィールドまたは領域をプロセスブロックすることができます。その後、各機能プロセスのAPIを定義できます。

EF Coddによって提案されたデータ正規化の側面でさえ、現在、深刻な課題と厳しい課題に直面しています。たとえば、1NFに関する彼の発言は、特に最新のデータサービス、レポテクノロジー、およびトランスミッションの出現におけるその他の発言と同様に、あいまいで、調整が不十分で、過度に単純化されていると批判されています。IMO、EF Coddステートメントは完全に破棄し、より数学的に妥当なステートメントの新しいセットを設計する必要があります。

EF Coddの明白な欠陥と効果的な人間の理解への不整合の原因は、人間が認識できる多次元の可変次元データが、断片的な2次元マッピングのセットを通じて効率的に認識できるという彼の信念です。

データ正規化の基礎

EFコッドが表現できなかったもの。

各コヒーレントデータモデル内で、これらは達成するデータモデルコヒーレンスの連続的な段階的な順序です。

  1. データインスタンスのUnityとIdentity。
    • 各データコンポーネントの粒度を設計します。その粒度は、コンポーネントの各インスタンスを一意に識別して取得できるレベルです。
    • インスタンスのエイリアスがない。つまり、識別によってコンポーネントの複数のインスタンスが生成される手段は存在しません。
  2. インスタンスのクロストークがない。コンポーネントのインスタンスの識別に寄与するために、コンポーネントの1つ以上の他のインスタンスを使用する必要はありません。
  3. データコンポーネント/ディメンションの単一性とアイデンティティ。
    • コンポーネントのエイリアス除去の存在。コンポーネント/ディメンションを一意に識別できる定義が1つ存在する必要があります。これはコンポーネントの主要な定義です。
    • 主な定義によって、意図したコンポーネントの一部ではないサブディメンションまたはメンバーコンポーネントが公開されない場合;
  4. コンポーネントのディエイリアシングのユニークな手段。コンポーネントには、そのようなコンポーネントのエイリアス除去定義が1つだけ存在する必要があります。
  5. コンポーネントの階層関係で親コンポーネントを識別するための定義インターフェースまたはコントラクトが1つだけ存在します。
  6. コンポーネントのクロストークがない。コンポーネントの最終的な識別に貢献するために別のコンポーネントのメンバーを使用する必要はありません。
    • このような親子関係では、親の識別定義は、子のメンバーコンポーネントのセットの一部に依存してはなりません。親のIDのメンバーコンポーネントは、子の一部またはすべての子を参照することに頼ることなく、完全な子IDである必要があります。
  7. データモデルのバイモーダルまたはマルチモーダルの外観を先取りします。
    • コンポーネントの候補定義が2つ存在する場合、1つに混同されている2つの異なるデータモデルが存在することは明らかです。これは、データモデルレベルまたはフィールドレベルで一貫性がないことを意味します。
    • アプリケーションのフィールドでは、1つのデータモデルのみを一貫して使用する必要があります。
  8. コンポーネントの変異を検出して識別します。膨大なデータの統計的コンポーネント分析を実行していない限り、コンポーネントの変異はおそらく見られないか、処理の必要性がわかりません。
    • データモデルでは、そのコンポーネントの一部が周期的または段階的に変化する場合があります。
    • モードは、メンバーローテーションまたは転置ローテーションです。
    • メンバーローテーションミューテーションは、コンポーネント間の子コンポーネントの明確な交換である可能性があります。または、完全に新しいコンポーネントを定義する必要がある場合。
    • 転置変異は、属性に変化する次元メンバーとして現れ、逆も同様です。
    • 各突然変異サイクルは、異なるデータモーダルとして識別される必要があります。
  9. 各ミューテーションをバージョン化します。データモデルの8年前の変異を処理する必要が生じた場合に、以前のバージョンのデータモデルを引き出すことができるように。

サービス間コンポーネントアプリケーションのフィールドまたはグリッドでは、一貫したデータモデルが1つだけ存在するか、データモデル/バージョンがそれ自体を識別する手段が存在する必要があります。

まだインターフェイス定数を使用できるかどうか尋ねていますか?本当に ?

この平凡な質問よりも重要な、データ正規化の問題があります。これらの問題を解決しない場合、インターフェイス定数が原因であると考える混乱は、比較的何もありません。ジルチ。

データモデルの正規化から、コンポーネントを変数、プロパティ、コントラクトインターフェイス定数として決定します。

次に、値の注入、プロパティ構成のプレースホルダ、インターフェイス、最終的な文字列などを決定します。

インターフェース定数に対して指示するのがより簡単なコンポーネントを見つける必要があるという言い訳を使わなければならない場合、それはデータモデルの正規化を実践しないという悪い習慣にいることを意味します。

おそらく、データモデルをvcsリリースにコンパイルする必要があります。データモデルの明確に識別可能なバージョンを引き出すことができること。

インターフェイスで定義された値は、変更不可であることを完全に保証されています。そして共有可能。必要なのが定数のセットだけであるのに、最終的な文字列のセットを別のクラスからクラスにロードするのはなぜですか?

それでは、なぜデータモデルコントラクトを公開しないのでしょうか。つまり、それを首尾一貫して管理および正規化できるのであれば、どうしてですか?...

public interface CustomerService {
  public interface Label{
    char AssignmentCharacter = ':';
    public interface Address{
      String Street = "Street";
      String Unit= "Unit/Suite";
      String Municipal = "City";
      String County = "County";
      String Provincial = "State";
      String PostalCode = "Zip"
    }

    public interface Person {
      public interface NameParts{
        String Given = "First/Given name"
        String Auxiliary = "Middle initial"
        String Family = "Last name"
      }
    }
  }
}

これで、次のような方法でアプリの契約済みラベルを参照できます

CustomerService.Label.Address.Street
CustomerService.Label.Person.NameParts.Family

これはjarファイルの内容を混乱させますか?Javaプログラマーとして、私はjarの構造を気にしません。

これは、osgiによる動機付けされたランタイムスワッピングに複雑さを与えますか?Osgiは、プログラマが悪い習慣を続けることを可能にする非常に効率的な手段です。osgiよりも良い選択肢があります。

それともなぜこれではないのですか?公開された契約へのプライベート定数の漏洩はありません。すべてのプライベート定数は、「定数」というプライベートインターフェイスにグループ化する必要があります。これは、定数を検索する必要がなく、「プライベート最終文字列」を繰り返し入力するのが面倒だからです。

public class PurchaseRequest {
  private interface Constants{
    String INTERESTINGName = "Interesting Name";
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

おそらくこれでも:

public interface PurchaseOrderConstants {
  public interface Properties{
    default String InterestingName(){
       return something();
    }
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

検討する価値があるインターフェイス定数の唯一の問題は、インターフェイスがいつ実装されるかです。

これはインターフェースの「本来の意図」ではありませんか?最高裁判所が米国憲法の書かれた手紙をどのように解釈するかではなく、私が米国憲法を作成する際の創設者の父親の「本来の意図」について気にかけるように???

結局のところ、私は自由で荒野で勇敢な家の土地に住んでいます。勇敢に、自由に、そしてワイルドに-インターフェイスを使用してください。同僚のプログラマーが効率的で遅延のあるプログラミング手段を使用することを拒否した場合、私は彼らの方法に合わせるためにプログラミング効率を下げるという黄金律に義務付けられていますか?多分私はすべきですが、それは理想的な状況ではありません。

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