インターフェイス定数の使用は何ですか?


123

私はJavaを学習していて、インターフェイスにフィールドがあり、それが静的で最終的なフィールドであることがわかりました。今のところ、これらの例は見たことがありません。これらのインターフェース定数の使用例にはどのようなものがありますか。Java標準ライブラリで確認できますか?

回答:


189

インターフェイスに静的メンバを置く(およびそのインターフェイスを実装する)は悪い習慣とそれのためにも名前があり、一定のインタフェースアンチパターン、参照効果的なJavaの、項目17:

一定のインターフェイスパターンは、インターフェイスの不適切な使用です。クラスがいくつかの定数を内部的に使用することは、実装の詳細です。定数インターフェースを実装すると、この実装の詳細がクラスのエクスポートされたAPIにリークします。クラスが定数インターフェースを実装することは、クラスのユーザーにとって重要ではありません。実際には、それらを混乱させることさえあります。さらに悪いことに、これはコミットメントを表しています。将来のリリースでクラスが変更され、定数を使用する必要がなくなった場合でも、バイナリ互換性を確保するためにインターフェイスを実装する必要があります。非最終クラスが定数インターフェースを実装する場合、そのすべてのサブクラスは、インターフェースの定数によって汚染された名前空間を持ちます。

などのJavaプラットフォームライブラリには、いくつかの定数インターフェイスがありますjava.io.ObjectStreamConstants。これらのインターフェースは異常と見なされるべきであり、エミュレートされるべきではありません。

定数インターフェースのいくつかの落とし穴を回避するために(人々がそれを実装するのを防ぐことができないため)、プライベートコンストラクターを持つ適切なクラスが推奨されます(例はWikipediaから借りたものです)。

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

    public static final double PI = 3.14159;
    public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

そして、それらを完全に修飾する必要なく(つまり、クラス名を前に付ける必要なく)定数にアクセスするには、静的インポートを使用します(Java 5以降)。

import static Constants.PLANCK_CONSTANT;
import static Constants.PI;

public class Calculations {

    public double getReducedPlanckConstant() {
        return PLANCK_CONSTANT / (2 * PI);
    }
}

12
わかりましたが、定数の定義だけではないインターフェースがあるとしたらどうでしょう。そのため、メソッド宣言を含む多くのクラスによって実装されるインターフェイスがありますが、たとえばサイズなどのいくつかの一般的な値もそこに追加したいと思います。この場合、それは本当に悪いパターンですか?一般に、定数のみのインターフェースを作成することはアンチパターンであることに同意します。
ルカシュRzeszotarski

11
誰かが本でそう言っているからといって、それは悪いことではありません。これらの定数にアクセスするためのインターフェースを実装しない限り、問題ありません。
ACV 2017

11
いやいやいや。EffectiveJavaでのその引用は何か他のものについてです!定数のみのインターフェースを作成することは、それらの定数を保持するクラスのより良い代替手段です。効果的なJavaは、「クラスが内部で定数を使用することは実装の詳細です」と述べています。しかし、ここではそうではありません。「グローバル」定数について話している。そして、メソッド宣言のないインターフェースを実装したい人はいますか?
ACV

6
ACVに同意します。定数インターフェースがエクスポートされたAPIモジュールの一部でない場合、または実装されていない場合、問題は発生しません。const finalクラスを使用するのは醜いです。コードを無駄にするため、コードを乱雑にするプライベートコンストラクターが必要です。
ローレンス

2
この回答は、「Effective Java」という本の要点を正しく示していません。これは、「(およびそのインターフェースの実装)」という括弧で囲んでメインポイントを「ダウングレード」するためです。代わりに、インターフェースの定数のポイントを強調します(そのようなインターフェースを実装しない限り問題ありません)。引用されたフラグメントを注意深く読むと、「Effective Java」の作者が最初に何を意味していたかがわかるので、これは一般に悪い答えではありません。しかし、私はそれが誤解を招くと思います。私の意見では、「そしてそのインターフェースを実装する」という部分は、それを強調するために太字フォントにすべきです。
krm '10 / 07/19

17

一定のインターフェイスパターンは、インターフェイスの不適切な使用です。

この仮説をだれが実行したにせよ、彼/彼女がどんなグルであろうとも、悪い習慣と実践を効率的に実行し続ける必要性に基づいてそれをだましました。仮説は、悪いソフトウェア設計習慣の妥当性の促進に基づいています。

その仮説に対する反論をここに書きました。Javaに定数を実装する最良の方法は何ですか?この仮説の根拠のないことを説明します。

私がこの仮説を正当化しない理由を投稿してから2時間以内に閉じられるまで、その質問は10年間開かれたままでした。

これらは私が仮説に対して表明したポイントです

  • この仮説を立てるための基礎は、悪いソフトウェアの習慣と方法論の影響に対処するための方法と制限ルールの必要性です。

  • 一定のインターフェイスパターンはインターフェイスの不適切な使用です」という感情の支持者は、これらの悪い習慣や習慣の影響に対処する必要性によって引き起こされる以外の理由を提供することはできません。

  • 基本的な問題を解決します。

  • そして、Java言語構造のすべての言語機能を最大限に活用して、自分の都合に合わせて活用してみませんか。ジャケットは必要ありません。より効果的なライフスタイルを差別し差別するために、効果のないライフスタイルをバリケードするルールを作成するのはなぜですか?

基本的な問題

情報組織です。プロセスを仲介する情報、およびその情報の動作は、いわゆるビジネスルールと共に最初に理解する必要があります-プロセスのソリューションを設計または補足する前に。このような情報整理の方法は、数十年前にデータの正規化と呼ばれていました。

ソリューションのコンポーネントの粒度とモジュール性を情報のコンポーネントの粒度とモジュール性に合わせることが最適な戦略であるため、ソリューションのエンジニアリングのみが可能になります。

情報の整理には2つまたは3つの大きな障害があります。

  1. データモデルの「正規化」の必要性に対する認識の欠如。

  2. データの正規化に関するEF Coddの声明には欠陥があり、欠陥があり、あいまいです。

  3. アジャイルエンジニアリングになりすましている最新の流行は、進行中にリファクタリングできるため、モジュールの編成を計画および調整してはならないという誤った考えです。言い訳として、将来の発見に妨げられることなく、リファクタリングと継続的な変更が行われます。次に、プロセス情報の動作の本質的な発見は、利益と資産化を遅らせるために会計トリックを使用することにより、本質的な知識とその処理は現在必要ないと見なされます。

インターフェース定数の使用は良い習慣です。

アドホックなヒットアンドランプログラミングの習慣が好きだからといって、ルールを構成したり、それに対してファトワを発行したりしないでください。

銃の扱い方を知らない人や銃を乱用する傾向がある人がいるという理由で、銃の所有を禁止しないでください。

作成したルールが初心者がプロとしてコーディングできないプログラミング用であり、その中で自分自身を数えることを意図している場合は、そのように言います。適切に正規化されたデータモデルに該当するものとしてfatwaを宣言しないでください。

ばかげた推論-インターフェースは、Java言語のヒラメがそのように使用することを意図していませんでしたか?

私は創設者の父親の当初の意図が米国憲法に対して何であったかは気にしません。私は、書かれていない成文化された意図については気にしません。私は、憲法に書面化されているものと、社会の効果的な機能のためにそれらをどのように利用できるかを気にしているだけです。

私はJava言語/プラットフォームの仕様で許可されているものにのみ関心があり、ソフトウェアソリューションを効率的かつ効果的に表現するための媒体を提供するために、それらを最大限に活用するつもりです。ジャケットは必要ありません。

Enum定数の使用は実際には恐ろしい習慣です。

パラメータを値にマップするために追加のコードを書く必要があります。Javaの創設者があなたの記述なしにパラメーター値のマッピングを提供しなかったという事実は、マッピングコードが列挙型定数がJava言語の意図しない使用と同じように示すことを示しています。

特に、パラメーターを正規化およびコンポーネント化することは推奨されていないため、列挙型バッグに混合されたパラメーターが同じディメンションに属しているという誤った印象を与える可能性があります。

定数はAPIコントラクトです

それを忘れないでください。データモデルを設計および正規化し、それらに定数が含まれている場合、それらの定数は契約です。データモデルを正規化しなかった場合は、その悪い習慣に対処するための制限付きコーディングの実践方法についてのファトワに準拠する必要があります。

したがって、インターフェイスは定数のコントラクトを実装するのに最適な方法です。

奇妙な推測-インターフェイスが誤って実装された場合はどうなりますか?

うん。誰かがうっかりして任意のインターフェースをうっかり実装してしまう可能性があります。そのような不注意なプログラマの邪魔になるものは何もありません。

データモデルを設計し、漏洩に対して正規化する

APIへの未契約/浮遊パラメータのリークを引き起こす推定される不正行為を保護するために制限的な法令を配置しないでください。インターフェース定数に責任を負うのではなく、根本的な問題を解決してください。

IDEを使用しないのは悪い習慣です

正常に機能している効果的なプログラマーは、彼女が水中にとどまることができる時間、水ぶくれがする熱や湿った雷雨の中をどれだけ歩くことができるかを証明するためにそこにいません。彼女は、車、バス、または少なくとも自転車などの効率的なツールを使用して、毎日10マイル作業することになります。

IDEのないプログラミングに難解な禁欲主義者が執着しているからといって、仲間のプログラマーに制限を加えないでください。

いくつかのフレームワークは、プログラマーが悪い習慣を効率的に実践し続けるのに役立つように設計されています。

OSGIはそのようなフレームワークです。また、インターフェース定数に対する法令も同様です。

したがって、決定的な答え...

インターフェイス定数は、データモデルの適切に設計および正規化されたコンポーネントを契約に配置するための効果的かつ効率的な方法です。

クラスファイルにネストされた適切に名前が付けられたプライベートインターフェイスのインターフェイス定数は、ファイル全体に分散するのではなく、すべてのプライベート定数をグループ化することもお勧めします。


29
すべてのあなたのポイントは、冗談、皮肉、感情性なしで作ることができます。Stackoverflowはブログのプラットフォームではありません。
tkruse 2018

1
「私は創設者の父親が米国憲法に当初意図していたことは気にしません。私は書面化されていない法典化されていない意図は気にしません。文法化された憲法で文言化されているものとそれらをどのように利用できるかだけを気にします社会の効果的な機能。」-それは良い寓話ではありませんか?
Blessed Geek

「パラメーターを値にマップするために追加のコードを書く必要があります。Javaの創設者があなたの記述なしにパラメーター値のマッピングを提供しなかったという事実は、マッピングコードが列挙型定数がJava言語の意図しない使用と同じように実証されているという事実です。」他にどのようにして、追加のコードを書かずにパラメーター値のマッピングを取得しますか?
GabrielOshiro

インターフェイス定数を使用します。丁度。
Blessed Geek

9

私は今、この古い質問に何度か遭遇しましたが、受け入れられた答えはまだ私を混乱させます。いろいろ考えた結果、この問題はさらに明確になると思います。

インターフェイス定数を使用する理由

それらを比較してください:

public final class Constants {

    private Constants() {
        // restrict instantiation
    }

    public static final double PI = 3.14159;
    public static final double PLANCK_CONSTANT = 6.62606896e-34;
}

public interface Constants {

    public double PI = 3.14159;
    public double PLANCK_CONSTANT = 6.62606896e-34;
}

同じ使い方。はるかに少ないコード。

悪い練習?

@Pascal Thiventの答えは間違った強調をしていると思います、これが私のバージョンです:

静的メンバーをインターフェースに入れる(そしてそのインターフェースを実装する)ことは悪い習慣です。

Effective Javaからの引用には、他の人が実装している定数インターフェースが想定されていますが、これは起こらないはずです(起こらないでしょう)。

のような名前の定数インターフェイスを作成する場合Constants、誰も実装しないでください。(技術的には可能ですが、これが唯一の問題です)

標準ライブラリでは起こりません

標準ライブラリでは、設計の誤用を許すことはできないため、そこには何も表示されません。

しかし、あなたが心配する必要はありませんので、定数インターフェースを使用して、通常の開発者の日々のプロジェクトのために多くの方が簡単ですstaticfinalempty constructor、など、それがどんな悪い設計上の問題を引き起こすことはありません。私が考えることができる唯一の欠点は、それがまだ「インターフェース」の名前を持っていることですが、それだけです。

終わりのない議論

最後に、私は誰もがただ本を引用し、彼らの立場に意見と正当化を与えているだけだと思います。私も例外ではありません。多分決定はまだ各プロジェクトの開発者次第です。気になる場合は、そのまま使用してください。私たちにできる最善のことは、プロジェクト全体でそれを一貫させることです。


「静的メンバーをインターフェースに入れる(そしてそのインターフェースを実装する)ことは悪い習慣です。」いいえそうではありません
雨が降る

修飾子publicはインターフェースであるため省略できます。これを単純にdouble PI = 3.14159;使用すると、インターフェースConstants.PIを実装するためにこれを使用するクラスは必要ありませんConstants。私はインターフェイスのアプローチは、使用、私見の面で非常にきれいだと思う
krozaine

6

Joshua Bloch、「Effective Java-Programming Language Guide」:

一定のインターフェイスパターンは、インターフェイスの不適切な使用です。クラスがいくつかの定数を内部的に使用することは、実装の詳細です。定数インターフェースを実装すると、この実装の詳細がクラスのエクスポートされたAPIにリークします。クラスが定数インターフェースを実装することは、クラスのユーザーにとって重要ではありません。実際には、それらを混乱させることさえあります。さらに悪いことに、これはコミットメントを表しています。将来のリリースでクラスが変更され、定数を使用する必要がなくなった場合でも、バイナリ互換性を確保するためにインターフェイスを実装する必要があります。非最終クラスが定数インターフェースを実装する場合、そのすべてのサブクラスは、インターフェースの定数によって汚染された名前空間を持ちます。


あなたはまだ言われていない価値の文字通り何も追加しませんでした。
ドナルフェロー


2

非常に共鳴する答えがあります。

しかし、私はこの質問についていくつかの考えを持っています。(間違っている可能性があります)

私の意見では、インターフェースのフィールドはプロジェクト全体の定数であってはなりません。それらはインターフェースの手段にすぎず、インターフェースはそれを拡張し、これらのインターフェースを実装するクラスまたはそれらと密接な関係を持つクラスを拡張します。グローバルではなく、一定の範囲で使用してください。


それらは確かにそれらの実装クラス内で使用されるべきです。

2

インターフェイスに関する2つのポイント:

  • インターフェイスはそれを実装するオブジェクトが実行できることのサブセットを記述ます。(これは直感です)

  • インターフェイスは、それを実装するオブジェクトが後に続く一般的な定数を記述します

    • これらの共通定数、これらのオブジェクトについて詳しく知るためにクライアントが知っていることを目的としています。
    • そう 定数インターフェイスは確かに定義するための直感的でグローバル定数をインタフェースを記述するために使用されているため、一部のオブジェクトではなく、すべてのオブジェクトを / 何のオブジェクトは、(の意味を考慮していないグローバルに)。

したがって、定数インターフェイスグローバル定数に使用されていない場合、それは受け入れられます:

  • これらの一般的な定数に適切な名前が付けられている場合、実装者はそれらを使用することを推奨します(以下の例については、最初のポイントを参照してください)。
  • クラスが仕様に従ってそれらのクラスと同期したい場合は、implementsそれだけです(もちろん、実装ではこれらの共通定数を使用します)。

例:

interface Drawable {

    double GOLDEN_RATIO = 1.618033988;
    double PI = 3.141592653;
    ...

    // methods
    ...
}

public class Circle implements Drawable {
    ...
    public double getCircumference() {
        return 2 * PI * r;
    }
}

void usage() {

    Circle circle = new Circle(radius: 3.0);
    double maxRadius = 5.0;

    if ( circle.getCircumference() < 2 * Circle.PI * maxRadius ) {
        ...
    }

}

この例では:

  • からCircle implements DrawableCircleはおそらくで定義された定数に準拠していることがすぐにわかりますDrawable。そうでない場合、良い名前PIGOLDEN_RATIO、すでに使われています!
  • これらのDrawableオブジェクトのみが特定のに準拠し、PIGOLDEN_RATIO定義されDrawableていますDrawable。piと黄金比の精度が異なるオブジェクトが存在する可能性があります。

私はあなたの答えを誤解しましたか、それともインターフェースの目的を誤解しましたか?インターフェイスはサブセットではありません。インターフェースはコントラクトであり、コントラクトにサブスクライブしたものは、そのコントラクトで指定された対話を提供する必要があります。インターフェイスの唯一の有効な使用は、それを使用して契約を宣言/実行することです。
Blessed Geek

@BlessedGeek契約を履行すると、契約によって記述された機能が、実行できることのサブセットになります。

1

このjavax.swing.SwingConstantsインターフェースは、swingクラス間で使用される静的フィールドを取得した例です。これにより、次のようなものを簡単に使用できます

  • this.add(LINE_START, swingcomponent);
  • this.add(this.LINE_START, swingcomponent); または
  • this.add(SwingComponents.LINE_START, swingcomponent);

ただし、このインターフェイスにはメソッドがありません...


1

私はこの質問に出くわし、言及されていないものを追加したいと思いました。一般に、Pascalのここでの回答に同意します。ただし、インターフェイスの定数が「常に」アンチパターンであるとは思いません。

たとえば、定義している定数がそのインターフェイスのコントラクトの一部である場合、インターフェイスは定数にとって最適な場所だと思います。場合によっては、実装のユーザーにコントラクトを公開せずにパラメーターを非公開で検証することは適切ではありません。公に面した契約がない場合、ユーザーは、クラスを逆コンパイルしてコードを読み取ることなく、検証の内容を推測することしかできません。

したがって、インターフェイスを実装し、インターフェイスにコントラクトの保証に使用する定数(たとえば、整数の範囲など)がある場合、クラスのユーザーは、インターフェイスの定数をチェックすることで、インターフェイスインスタンスを正しく使用していることを確認できます。自分自身。定数が実装に対してプライベートである場合、または実装がパッケージプライベートなどである場合、これは不可能です。


1
あなたが説明する方法でのインターフェースと定数の問題、定数をインターフェースに追加できますが、APIのコンシューマーがその定数を実際に使用するように強制するバインディングはありません。
ダニエル

@ダニエル:私はあなたのコメントに賛成票を投じましたが、今私はあなたの質問について良い説明があります:「APIのコンシューマーが実際にその定数を使用するよう強制するバインディングはありません」しかし、クライアントはCONSTANT_NAMEを使用できなくなりました。中古、これは私にとって良い兆候です!

したがって、定数名はクラスでは使用できませんが、定数にまったく同じ名前を付けることを前提としています。定数を表すためにインターフェースを使用することは依然として誤りであり、インターフェースはAPIの規約です。定数値を表すために使用することはできません。
ダニエル

-1

クラス間で共有される定数を扱うときは、インターフェース定数を使用します。

public interface TestConstants
{
    String RootLevelConstant1 = "RootLevelConstant1";

    interface SubGroup1
    {
        String SubGroupConstant1 = "SubGroup1Constant1";
        String SubGroupConstant2 = "SubGroup1Constant2";
    }

    interface SubGroup2
    {
        String SubGroupConstant1 = "SubGroup2Constant1";
        String SubGroupConstant2 = "SubGroup2Constant2";
    }
}

グループ化は、特に定数のセットが大きい場合、非常に大きな資産です。

使用するには、単にそれらを一緒にチェーンします。

System.out.println(TestConstants.SubGroup1.SubGroupConstant1);
System.out.println(TestConstants.SubGroup2.SubGroupConstant1);
System.out.println(TestConstants.RootLevelConstant1);

同意します。基本的には、public static finalフィールドを持つpublic抽象クラスと同じですが、語数ははるかに少なくなります。必要なのは、チームのすべての開発者が適切なプラクティスに従っていることを確認し、これらのインターフェイスを実装しないことです。
Yahor 2017年

1
これは恐ろしいことです。クラスでまったく同じことを実行し、同じ方法でアクセスし、さらにクラスをfinalにして、それらのコンストラクターをプライベートにすることができるからです(本当に定数のバッグだけが必要な場合)。さらに、クラスを拡張する人を避けます。あなたはあなたがあなたのインターフェースを実装する人々を避けることはできませんか?
GabrielOshiro

1
なぜクラスでは、インターフェイスで何ができるのですか?問題は、人々がうっかりANYインターフェイスを実装しないようにする方法です。なぜインターフェース定数を選択するのですか?
Blessed Geek

-2

フィールドはインターフェースで宣言する必要があります。そうすることで、フィールドは共有しやすくなり、追加の結合を導入することなく参照できるようになります。

出典:Java Developer Toolsコーディングスタイル


多分java6の前。今日はほとんど関係ありません。
tkruse 2018

そして、リンクが壊れています。Codeproはもうありません。
スティーブンC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.