web-dev-qa-db-ja.com

Java値のない列挙型とプライベートコンストラクターのあるユーティリティクラスの違い

ユーティリティクラスに対して行う一般的なことは、 プライベートコンストラクタを与える :です。

_public final class UtilClass {
    private UtilClass() {}

    ...
}
_

しかし残念ながら、一部のツールはそのプライベートコンストラクターを好みません。クラス内で呼び出されることはない、テストの対象外である、ブロックにコメントが含まれていないなどの警告が表示される場合があります。

代わりにこれを行うと、これらの警告の多くは消えます。

_public enum UtilClass {;
    ...
}
_

私の質問は、将来の開発者の果てしない憎しみに加えて、値のない列挙型とJavaのプライベートコンストラクターを持つクラスの間にどのような重要な違いがあるのでしょうか。

私はnotに質問していることに注意してください a Java enumとpublicstaticのクラスの利点は何ですか?最終フィールド? 。物事のリストを定数の束にするか列挙型にするかを決定するのではなく、関数の束をコンストラクターのないクラスに入れるか、値のない列挙型にするかを決定します。

また、私は実際にはこれをしたくないことに注意してください。一般的な言語知識の一部としてのトレードオフを知りたいだけです。

たとえば、列挙型を使用すると、UtilClass.values()などの役に立たないメソッドでオートコンプリートが汚染されます。他にどのような欠点がありますか?利点?

37
Craig Gidney

1つの利点は、クラス内からでもインスタンスを作成できないことが絶対に保証されることです。

欠点は、これが列挙型の通常の意図を超えていることです。ただし、列挙型で実装されたシングルトンに対してはすでにこれを行っています。

このようなシングルトンに関するJoshuaBlochによる「EffectiveJava」のこのビットは、ユーティリティクラスにも適用されます。

...宣言された定数以外にインスタンスが存在しないことを保証します。 JVMはこの保証を行い、信頼できます。

免責事項:私はこのパターンを使用しておらず、賛成または反対を推奨していません。

30
Andy Thomas

実際には列挙型ではないものにenumを使用すると、醜くて混乱します。それはそれをしない十分な理由だと思います。

「ユーティリティクラス」パターンは完全に正当です。あなたのツールがそれを気に入らなければ、それはツールの問題です。

35
Mike Baranczak

ユーティリティクラスの次のパターンは、インスタンスが存在しないことを保証します。

public abstract class Util {
    private Util() { throw new Error(); }
    ... // static methods
}

さらに、列挙型によって提供される、追加の無関係な静的メソッドはありません。

9
ursa

唯一の違いは、コンストラクターを呼び出すことができることですクラス内

_public final class UtilityClass {

    public static final UtilityClass Instance = new UtilityClass();

    private UtilityClass () {}

    public static int Foo (int a, int b) {
         return a+b;
    }

}
_

しかし、あなたはそのクラスの設計者なので、独自のコードコントラクトを破ることは意味がありません。

一般的に、私が今まで読んだほとんどのソフトウェア設計書は、静的メソッドの使用に反対しています。それらが本当にユーティリティメソッドでない限り、ある意味では決して状態を必要としません。それでも、Singletonパターンを実装するのはほんの少しの努力であり、その時が来たら、それに状態を割り当てることができます。

_public final class UtilityClass {

    public static final UtilityClass Instance = new UtilityClass();

    private UtilityClass () {}

    public int Foo (int a, int b) {
         return a+b;
    }

}
_

そしてそれをUtilityClass.Instance.Foo(2,5);で呼び出します。コーディングプロセスの後半で状態の導入変換を実行するのははるかに困難です。 したがって、静的メソッドの保守は困難です。

インスタンスが役立つ理由は、インスタンスを次のような多くのパターンで使用できるためですStrategyある場合に何をすべきかに依存する場合...staticを使用するメソッドの場合、Javaは(正当な理由で)メソッドポインタをサポートしないため)メソッドの動的性が低下します。したがって、非静的メソッドの方が動的で便利です。

さらに、セキュリティ研究者の中には、static修飾子を使用してコードを分析するのは難しいと主張する人もいます。コードはどこからでもアクセスでき、副作用は予測しにくいためです(たとえば、自動セキュリティ分析ツールで)。それが完全に実装されていない場合でも、フィールドを分析して、アクセスできるメソッドを確認し、考えられる副作用(ネットワークの使用状況、ファイルIOなど)を分析できます。これにより、検証が必要なクラスごとの潜在的な危険のリストが生成される可能性があります。少なくとも、私の仲間の研究者の1人の博士論文が正しいことを理解していれば。 したがって、非静的メソッドでは、より多くの修飾子分析が可能になります。

結論として:Javaはオブジェクト指向プログラミングの原則に基づいて構築されました。これは、「classworld」がcompiler、およびinterpreter /による「instanceworld」ランタイム。2つの単語の間に多くの矛盾があることに同意します。しかし、staticメソッドは、多くの場合、または場合によっては、そのような矛盾を解決するための間違いです。

6