web-dev-qa-db-ja.com

シングルトンとしての静的ファクトリとファクトリ

一部のコードでは、次のような静的ファクトリがあります。

public class SomeFactory {

    // Static class
    private SomeFactory() {...}

    public static Foo createFoo() {...}

    public static Foo createFooerFoo() {...}
}

コードレビュー中に、これはシングルトンであり、注入されるべきであると提案されました。したがって、次のようになります。

public class SomeFactory {

    public SomeFactory() {}

    public Foo createFoo() {...}

    public Foo createFooerFoo() {...}
}

強調するいくつかのこと:

  • どちらの工場も無国籍です。
  • メソッド間の唯一の違いは、スコープ(インスタンスと静的)です。実装は同じです。
  • Fooはインターフェースを持たないBeanです。

静的になるために私が持っていた引数は:

  • クラスはステートレスであるため、インスタンス化する必要はありません
  • ファクトリをインスタンス化する必要があるよりも、静的メソッドを呼び出すことができるほうが自然なようです。

シングルトンとしてのファクトリの引数は次のとおりです。

  • すべてを注入するのは良いことです
  • 工場の無国籍にもかかわらず、注入によりテストが簡単になります(モックしやすい)
  • 消費者をテストするときにそれはあざける必要があります

シングルトンアプローチには深刻な問題があります。静的なメソッドは絶対にないようです。 StringUtilsなどのユーティリティをラップして挿入する必要があることも示唆しているようですが、これはばかげているようです。最後に、ある時点でファクトリーをモックする必要があることを意味しますが、これは正しくないようです。いつ工場をあざける必要があるか、私には考えられません。

コミュニティはどう思いますか?私はシングルトンアプローチが好きではありませんが、それに対してひどく強い議論をしているようには見えません。

25
bstempi

作成するオブジェクトタイプからファクトリを分離するのはなぜですか?

public class Foo {

    // Private constructor
    private Foo(...) {...}

    public static Foo of(...) { return new Foo(...); }
}

これが、Joshua Blochが彼の著書「Effective Java」の5ページにある彼のアイテム1として述べていることです。 Javaは、余分なクラスやシングルトンなどを追加しなくても十分冗長です。別のファクトリクラスが意味をなす場合もありますが、その数は限られています。

Joshua BlochのItem 1を言い換えると、コンストラクターとは異なり、静的ファクトリーメソッドは次のことができます。

  • 特定の種類のオブジェクト作成を説明できる名前を付ける(Blochは例としてprobablePrime(int、int、Random)を使用します)
  • 既存のオブジェクトを返す(例:flyweight)
  • 元のクラスのサブタイプまたはそれが実装するインターフェースを返す
  • 冗長性を減らす(型パラメーターを指定する-たとえばBlochを参照)

短所:

  • パブリックコンストラクターまたは保護されたコンストラクターのないクラスはサブクラス化できません(ただし、保護されたコンストラクターおよび/またはアイテム16:継承よりも構成を優先することができます)
  • 静的ファクトリーメソッドは、他の静的メソッドよりも目立たない(of()やvalueOf()などの標準名を使用)

本当に、Blochの本をコードレビュー担当者に渡して、2人がBlochのスタイルに同意できるかどうかを確認する必要があります。

15
GlenPeterson

私の頭の真上から、Javaの静的に関する問題のいくつかを次に示します。

  • 静的メソッドは、OOP "ルール"によって再生されません。特定の静的メソッドを実装するように強制することはできません(私が知る限り)。したがって、複数のクラスを持つことはできません。同じシグネチャを使用して同じ静的メソッドのセットを実装します。つまり、何を実行していてもoneで立ち往生しています。静的クラスを実際にサブクラス化することもできません。したがって、ポリモーフィズムはありません、など.

  • メソッドはオブジェクトではないため、静的メソッドを渡すことはできず、それらを使用することはできません(大量のボイラープレートコーディングを行わないと)exceptそれらにハードリンクされているコードによって- -これにより、クライアントコードが高度に結合されます。 (公平に言うと、これは静力学のせいだけではありません)。

  • staticsフィールドはグローバルとかなり似ています


あなたは言及しました:

シングルトンアプローチには深刻な問題があります。静的なメソッドは絶対にないようです。また、StringUtilsなどのユーティリティをラップして挿入する必要があることも示唆しているように見えますが、これはばかげているようです。最後に、ある時点でファクトリーをモックする必要があることを意味しますが、これは正しくないようです。いつ工場をあざける必要があるか、私には考えられません。

それは私があなたに尋ねることを好奇心をそそる:

  • あなたの意見では、静的メソッドの利点は何ですか?
  • StringUtilsが正しく設計および実装されていると思いますか?
  • なぜ工場をあざける必要がないと思いますか?
5
user39685

あなたが構築しているアプリケーションはかなり単純でなければならないか、そうでなければあなたはそのライフサイクルの比較的初期にいると思います。静的に関する問題が発生していないと考えられる唯一のシナリオは、ファクトリについて知っているコードの他の部分を1つか2つの場所に制限できた場合です。

アプリケーションが進化し、今ではいくつかのインスタンスでFooBar(Fooのサブクラス)を生成する必要があるとします。次に、SomeFactoryを認識し、someConditionを参照してSomeFactoryまたはSomeOtherFactoryを作成するIFooFactoryを作成したとしましょう。さて、異なるサブクラスまたはまったく異なる実装を作成することは子供の遊びです-チェーンの上位にある適切なIFooFactoryをフィードし、クライアントがそれを取得すると、gimmeAFoo()を呼び出して正しいものを取得しますそれは正しいファクトリーを得たからです。

これが製品コードでどのように機能するのか疑問に思われるかもしれません。私が取り組んでいるコードベースの1つの例を挙げますと、1年以上のプロジェクトの開始後にレベルが安定し始めています。Questionデータオブジェクトを作成するために使用される一連のファクトリーがあります(これらは次のようなものです- プレゼンテーションモデル )。私はIFooを持っています。これは基本的に、どの質問ファクトリをいつ使用するかを調べるためのハッシュです。したがって、さまざまな質問をするアプリケーションを作成するために、さまざまなファクトリをマップに配置しました。

質問は、手順または演習(どちらもQuestionFactoryMapを実装)で提示できるため、IContentBlockまたはInstructionsFactoryはそれぞれ、QuestionFactoryMapのコピーを取得します。次に、さまざまなInstructionsおよびExerciseファクトリがExerciseFactoryに渡されます。ContentBlockBuilderは、いつ使用するかのハッシュを保持します。そして、XMLがロードされると、ContentBlockBuilderはハッシュからExerciseまたはInstructions Factoryを呼び出し、それをcreateContent()に要求します。次に、ファクトリは、質問の作成を、引き出したものに委任します各XMLノードとハッシュの内容に基づいて、その内部QuestionFactoryMapの 残念ながら 、それはBaseQuestionではなくIQuestionですが、設計に注意を払っていても、間違いを犯す可能性があることを示していますあなたを悩ませることができます。

あなたの腸はこれらの静力学があなたを傷つけるとあなたに言っています、そして確かにあなたの腸をサポートするために文学に そこにたくさん があります。単体テストにのみ使用する依存性注入を使用することで失うことは決してありません(ただし、優れたコードを作成した場合、それ以上使用しないと信じているわけではありません)。コードをすばやく簡単に変更できます。なぜそこに行くのですか?

0
Amy Blankenship