回答:
インターフェイスに静的メンバを置く(およびそのインターフェイスを実装する)は悪い習慣とそれのためにも名前があり、一定のインタフェースアンチパターン、参照効果的な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);
}
}
「一定のインターフェイスパターンは、インターフェイスの不適切な使用です。」
この仮説をだれが実行したにせよ、彼/彼女がどんなグルであろうとも、悪い習慣と実践を効率的に実行し続ける必要性に基づいてそれをだましました。仮説は、悪いソフトウェア設計習慣の妥当性の促進に基づいています。
その仮説に対する反論をここに書きました。Javaに定数を実装する最良の方法は何ですか?この仮説の根拠のないことを説明します。
私がこの仮説を正当化しない理由を投稿してから2時間以内に閉じられるまで、その質問は10年間開かれたままでした。
これらは私が仮説に対して表明したポイントです
この仮説を立てるための基礎は、悪いソフトウェアの習慣と方法論の影響に対処するための方法と制限ルールの必要性です。
「一定のインターフェイスパターンはインターフェイスの不適切な使用です」という感情の支持者は、これらの悪い習慣や習慣の影響に対処する必要性によって引き起こされる以外の理由を提供することはできません。
基本的な問題を解決します。
そして、Java言語構造のすべての言語機能を最大限に活用して、自分の都合に合わせて活用してみませんか。ジャケットは必要ありません。より効果的なライフスタイルを差別し差別するために、効果のないライフスタイルをバリケードするルールを作成するのはなぜですか?
情報組織です。プロセスを仲介する情報、およびその情報の動作は、いわゆるビジネスルールと共に最初に理解する必要があります-プロセスのソリューションを設計または補足する前に。このような情報整理の方法は、数十年前にデータの正規化と呼ばれていました。
ソリューションのコンポーネントの粒度とモジュール性を情報のコンポーネントの粒度とモジュール性に合わせることが最適な戦略であるため、ソリューションのエンジニアリングのみが可能になります。
情報の整理には2つまたは3つの大きな障害があります。
データモデルの「正規化」の必要性に対する認識の欠如。
データの正規化に関するEF Coddの声明には欠陥があり、欠陥があり、あいまいです。
アジャイルエンジニアリングになりすましている最新の流行は、進行中にリファクタリングできるため、モジュールの編成を計画および調整してはならないという誤った考えです。言い訳として、将来の発見に妨げられることなく、リファクタリングと継続的な変更が行われます。次に、プロセス情報の動作の本質的な発見は、利益と資産化を遅らせるために会計トリックを使用することにより、本質的な知識とその処理は現在必要ないと見なされます。
アドホックなヒットアンドランプログラミングの習慣が好きだからといって、ルールを構成したり、それに対してファトワを発行したりしないでください。
銃の扱い方を知らない人や銃を乱用する傾向がある人がいるという理由で、銃の所有を禁止しないでください。
作成したルールが初心者がプロとしてコーディングできないプログラミング用であり、その中で自分自身を数えることを意図している場合は、そのように言います。適切に正規化されたデータモデルに該当するものとしてfatwaを宣言しないでください。
私は創設者の父親の当初の意図が米国憲法に対して何であったかは気にしません。私は、書かれていない成文化された意図については気にしません。私は、憲法に書面化されているものと、社会の効果的な機能のためにそれらをどのように利用できるかを気にしているだけです。
私はJava言語/プラットフォームの仕様で許可されているものにのみ関心があり、ソフトウェアソリューションを効率的かつ効果的に表現するための媒体を提供するために、それらを最大限に活用するつもりです。ジャケットは必要ありません。
パラメータを値にマップするために追加のコードを書く必要があります。Javaの創設者があなたの記述なしにパラメーター値のマッピングを提供しなかったという事実は、マッピングコードが列挙型定数がJava言語の意図しない使用と同じように示すことを示しています。
特に、パラメーターを正規化およびコンポーネント化することは推奨されていないため、列挙型バッグに混合されたパラメーターが同じディメンションに属しているという誤った印象を与える可能性があります。
それを忘れないでください。データモデルを設計および正規化し、それらに定数が含まれている場合、それらの定数は契約です。データモデルを正規化しなかった場合は、その悪い習慣に対処するための制限付きコーディングの実践方法についてのファトワに準拠する必要があります。
したがって、インターフェイスは定数のコントラクトを実装するのに最適な方法です。
うん。誰かがうっかりして任意のインターフェースをうっかり実装してしまう可能性があります。そのような不注意なプログラマの邪魔になるものは何もありません。
APIへの未契約/浮遊パラメータのリークを引き起こす推定される不正行為を保護するために制限的な法令を配置しないでください。インターフェース定数に責任を負うのではなく、根本的な問題を解決してください。
正常に機能している効果的なプログラマーは、彼女が水中にとどまることができる時間、水ぶくれがする熱や湿った雷雨の中をどれだけ歩くことができるかを証明するためにそこにいません。彼女は、車、バス、または少なくとも自転車などの効率的なツールを使用して、毎日10マイル作業することになります。
IDEのないプログラミングに難解な禁欲主義者が執着しているからといって、仲間のプログラマーに制限を加えないでください。
OSGIはそのようなフレームワークです。また、インターフェース定数に対する法令も同様です。
インターフェイス定数は、データモデルの適切に設計および正規化されたコンポーネントを契約に配置するための効果的かつ効率的な方法です。
クラスファイルにネストされた適切に名前が付けられたプライベートインターフェイスのインターフェイス定数は、ファイル全体に分散するのではなく、すべてのプライベート定数をグループ化することもお勧めします。
私は今、この古い質問に何度か遭遇しましたが、受け入れられた答えはまだ私を混乱させます。いろいろ考えた結果、この問題はさらに明確になると思います。
それらを比較してください:
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
、誰も実装しないでください。(技術的には可能ですが、これが唯一の問題です)
標準ライブラリでは、設計の誤用を許すことはできないため、そこには何も表示されません。
しかし、あなたが心配する必要はありませんので、定数インターフェースを使用して、通常の開発者の日々のプロジェクトのために多くの方が簡単ですstatic
、final
、empty constructor
、など、それがどんな悪い設計上の問題を引き起こすことはありません。私が考えることができる唯一の欠点は、それがまだ「インターフェース」の名前を持っていることですが、それだけです。
最後に、私は誰もがただ本を引用し、彼らの立場に意見と正当化を与えているだけだと思います。私も例外ではありません。多分決定はまだ各プロジェクトの開発者次第です。気になる場合は、そのまま使用してください。私たちにできる最善のことは、プロジェクト全体でそれを一貫させることです。
public
はインターフェースであるため省略できます。これを単純にdouble PI = 3.14159;
使用すると、インターフェースConstants.PI
を実装するためにこれを使用するクラスは必要ありませんConstants
。私はインターフェイスのアプローチは、使用、私見の面で非常にきれいだと思う
Joshua Bloch、「Effective Java-Programming Language Guide」:
一定のインターフェイスパターンは、インターフェイスの不適切な使用です。クラスがいくつかの定数を内部的に使用することは、実装の詳細です。定数インターフェースを実装すると、この実装の詳細がクラスのエクスポートされたAPIにリークします。クラスが定数インターフェースを実装することは、クラスのユーザーにとって重要ではありません。実際には、それらを混乱させることさえあります。さらに悪いことに、これはコミットメントを表しています。将来のリリースでクラスが変更され、定数を使用する必要がなくなった場合でも、バイナリ互換性を確保するためにインターフェイスを実装する必要があります。非最終クラスが定数インターフェースを実装する場合、そのすべてのサブクラスは、インターフェースの定数によって汚染された名前空間を持ちます。
これらは、インターフェースを実装するクラスで使用される共通の定数がある場合に役立ちます。
次に例を示します。http: //www.javapractices.com/topic/TopicAction.do?Id = 32
ただし、推奨される方法は、インターフェースで定数の代わりに静的インポートを使用することです。これがリファレンスです:http : //www.javapractices.com/topic/TopicAction.do?Id=195
インターフェイスに関する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 Drawable
、Circle
はおそらくで定義された定数に準拠していることがすぐにわかりますDrawable
。そうでない場合、良い名前PI
とGOLDEN_RATIO
、すでに使われています!Drawable
オブジェクトのみが特定のに準拠し、PI
でGOLDEN_RATIO
定義されDrawable
ていますDrawable
。piと黄金比の精度が異なるオブジェクトが存在する可能性があります。このjavax.swing.SwingConstants
インターフェースは、swingクラス間で使用される静的フィールドを取得した例です。これにより、次のようなものを簡単に使用できます
this.add(LINE_START, swingcomponent);
this.add(this.LINE_START, swingcomponent);
または this.add(SwingComponents.LINE_START, swingcomponent);
ただし、このインターフェイスにはメソッドがありません...
私はこの質問に出くわし、言及されていないものを追加したいと思いました。一般に、Pascalのここでの回答に同意します。ただし、インターフェイスの定数が「常に」アンチパターンであるとは思いません。
たとえば、定義している定数がそのインターフェイスのコントラクトの一部である場合、インターフェイスは定数にとって最適な場所だと思います。場合によっては、実装のユーザーにコントラクトを公開せずにパラメーターを非公開で検証することは適切ではありません。公に面した契約がない場合、ユーザーは、クラスを逆コンパイルしてコードを読み取ることなく、検証の内容を推測することしかできません。
したがって、インターフェイスを実装し、インターフェイスにコントラクトの保証に使用する定数(たとえば、整数の範囲など)がある場合、クラスのユーザーは、インターフェイスの定数をチェックすることで、インターフェイスインスタンスを正しく使用していることを確認できます。自分自身。定数が実装に対してプライベートである場合、または実装がパッケージプライベートなどである場合、これは不可能です。
クラス間で共有される定数を扱うときは、インターフェース定数を使用します。
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);
フィールドはインターフェースで宣言する必要があります。そうすることで、フィールドは共有しやすくなり、追加の結合を導入することなく参照できるようになります。