web-dev-qa-db-ja.com

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

私はJavaを学んでおり、インターフェースはpublic staticおよびfinalであるフィールドを持つことができることを発見しました。これまでにこれらの例を見たことはありません。これらのインターフェイス定数、およびJava Standard Library?

109
unj2

静的メンバーをインターフェイスに配置する(およびそのインターフェイスを実装する)ことは悪い習慣であり、その名前さえありますConstant Interface AntipatternEffective Java 、Item 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;
}

そして、完全に修飾することなく(つまり、クラス名をプレフィックスとして付けることなく)定数にアクセスするには、 static import (since Java 5):

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

public class Calculations {

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

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

この仮説を作成した人は誰でも、教祖であっても、悪い習慣や習慣を効率的に実行し続ける必要性に基づいて作成しました。仮説は、悪いソフトウェア設計習慣の妥当性の促進に基づいています。

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

私はこの仮説を正当化する理由を投稿してから2時間以内に閉じられるまで、その質問は10年間開いていました。したがって、この誤った仮説を真剣に保持している人々による議論の不本意を暴露します。

これらは、私が仮説に対して表明した点です

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

  • 感情の支持者「一定のインターフェイスパターンはインターフェイスの不適切な使用です」それらの悪い習慣や慣習の影響で。

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

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

基本的な問題

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

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

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

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

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

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

インターフェイス定数を使用することをお勧めします。

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

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

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

馬鹿げた推論-インターフェイスは、Java言語がそのように使用されるのを好む人によって意図されたのではありませんか?

私は建国の父たちの元々の意図が米国憲法に対して何を持っているかを気にしません。私は書かれていないコード化されていない意図を気にしません。私は、憲法で書かれた文明化されたものと、社会の効果的な機能のためにそれらをどのように活用できるかだけに関心があります。

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

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

パラメーターを値にマップするための追加コードを書く必要があります。 Javaの創設者は、マッピングコードが列挙定数を示すことなくパラメータ値のマッピングを提供しなかったという事実は、Java language 。

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

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

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

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

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

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

データモデルを設計し、漏洩から正規化する

APIに未契約/迷子パラメータの漏洩を引き起こすと思われる悪い慣行を保護するために、制限的な法令を設けないでください。インターフェイス定数に責任を負うのではなく、基本的な問題を解決します。

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

正常に機能し、効果的なプログラマーは、彼女が水中にどれだけ長く滞在できるか、猛烈な暑さや濡れた雷雨の中をどれだけ歩くことができるかを証明するためにそこにはいません。彼女は車やバス、または少なくとも自転車のような効率的なツールを使用して、毎日10マイルの仕事をしています。

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

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

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

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

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

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

8
Blessed Geek

Joshua Bloch、「効果的なJava-プログラミング言語ガイド」:

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

7
stacker

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

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

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

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を心配する必要がないため、定数インターフェイスを使用する方がはるかに簡単です。 、など、悪いデザインの問題を引き起こすことはありません。私が考えることができる唯一の欠点は、それがまだ「インターフェース」の名前を持っているということですが、それ以上のものはありません。

終わりのない議論

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

4
Nakamura

これらは、インターフェイスを実装するクラスで使用される共通定数がある場合に役立ちます。

以下に例を示します。 http://www.javapractices.com/topic/TopicAction.do?Id=32

ただし、インターフェイスでは定数の代わりに静的インポートを使用することをお勧めします。リファレンスは次のとおりです。 http://www.javapractices.com/topic/TopicAction.do?Id=195

3
dcp

非常に手ごろな答えがあります。

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

私の意見では、インターフェイスのフィールドはプロジェクト全体の定数ではなく、インターフェイスの手段であり、インターフェイスはそれを拡張し、これらのインターフェイスを実装するクラスまたは密接な関係を持つクラスです。グローバルではなく、特定の範囲内で使用する必要があります。

2
Zhili

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

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

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

1
Progman

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

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

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

1
akagixxer