37

私は(抽象的な)工場をたくさん持っていますが、それらは通常シングルトンとして実装されています。

通常、これらのファクトリを使用したり知ったりすることに実際に関係のないレイヤーにそれらを渡す必要がないという利便性のためです。

ほとんどの場合、起動時にどのファクトリ実装のコード プログラムの残りの部分を決定する必要があるかだけです。

それは例えばのように見えます

abstract class ColumnCalculationFactory { 
  private static ColumnCalculationFactory factory;

 public static void SetFactory(ColumnCalculationFactory f) {
         factory = f;
  }

  public static void Factory() {
         return factory;
  }

 public IPercentCalculation CreatePercentCalculation();
 public IAverageCalculation CreateAverageCalculation();
    ....

}

これについて何かがにおいがしますが、私にはわかりません-それはおそらくシングルトンよりも使い古されたグローバルです。私のプログラムはそれ以上必要としませんが、ColumnCalculations を作成するファクトリが 1 つだけ存在する必要があるというわけではありません。

これはベストプラクティスと見なされますか? これらを(半)グローバル AppContext クラスに詰め込む必要がありますか?他に何か(私はまだ大きなIoCコンテナ、またはspring.netに切り替える準備ができていません)?

4

6 に答える 6

17

それは本当にあなたがしていることとあなたのアプリケーションの範囲に依存します。それがかなり小さなアプリであり、これを超えて成長することは決してない場合は、現在のアプローチで十分かもしれません。これらのことに対する普遍的な「ベスト」プラクティスはありません。ステートレスリーフメソッドや一方向の呼び出し(ロギングなど)以外にシングルトンを使用することはお勧めしませんが、シングルトンであるという理由だけで、それを手に負えないように却下することは必ずしも正しいことではありません。

些細なコードやプロトタイプコード以外の場合、私は個人的にコンストラクターインジェクションで制御の反転を明示的に使用するのが好きです。これは、すべての依存関係が考慮され、「驚き」が発生しないことを意味します。コンパイラでは、BなしでAをインスタンス化し、CなしでBをインスタンス化できません。シングルトンはこれらの関係をすぐに埋めます。BなしでAをインスタンス化し、CなしでBをインスタンス化できます。AからBへの呼び出しが発生すると、null参照が取得されます。例外。

これは、実行時の障害を介して繰り返し逆方向に作業する必要があるため、テスト時に特に厄介です。コードをテストするときは、他のコーダーと同じようにAPIを使用しているため、このアプローチの設計上の問題を示しています。コンストラクターインジェクションは、これが決して起こらないことを保証します-すべての依存関係は前もって述べられています。コンストラクターインジェクションの欠点は、オブジェクトグラフの構成がより複雑になることです。これは、IoCコンテナを使用することで軽減されます。

私が言おうとしているのは、ある種のコンテキストオブジェクトとレジストリパターンの使用を検討している場合は、IoCコンテナを確認した方がよいということです。Autofacのような確立された無料の製品を使用できる場合、独自のmuttバージョンを作成するのはおそらく時間の無駄です。

于 2009-08-16T20:18:25.617 に答える
12

いくつかのシングルトンを持つことは非常に一般的であり、通常は問題になりません.シングルトンがたくさんあると、イライラするコードが発生します.

シングルトンを大量に使用したクラスをテストしなければならない状況が発生しました。問題は、クラス b をテストしていて、クラス c (シングルトン) を取得した場合、クラス c をモックアウトする方法がないことです (少なくとも EasyMock では、シングルトン クラスの静的ファクトリ メソッドを置き換えることはできません。

簡単な修正の 1 つは、テスト目的ですべてのシングルトンに「セッター」を用意することです。あまりお勧めしません。

私たちが試みたもう 1 つのことは、すべてのシングルトンを保持する単一のクラス (レジストリ) を用意することでした。これを行うと、ほぼ確実に使用する必要がある依存性注入にかなり近づきます。

テストは別として、私はずっと前に、特定のオブジェクトの複数のインスタンスが存在することは決してないということを学びました。次のリビジョンでは、多くの場合、2 つが必要になります。これにより、シングルトンは静的クラスよりもはるかに優れたものになります。少なくとも、シングルトンのゲッターにパラメーターを追加して、リファクタリングをあまり行わずに 2 番目のパラメーターを返すことができます (これも、DI が行うことを行うだけです)。 )。

とにかく、DIを調べてみてください。あなたは本当に幸せかもしれません.

于 2009-08-16T19:42:18.420 に答える
6

いいえ、ここで行っていることはグローバルな状態を作成しているためです。グローバルな状態にはあらゆる種類の問題があります。そのうちの主な問題は、ある関数が目に見えない方法で他の関数の動作に依存することです。関数が終了する前に を保存して復元するのを忘れる別の関数を呼び出した場合factory、古い値をどこかに保存しない限り元に戻すことさえできないため、問題が発生します。そして、それを行うにはコードを追加する必要があります(コードから判断すると、あなたは次の言語を使用していると思いますfinally、間違いの余地がさらに大きくなります)。さらに、2 つのサブオブジェクトに対して 2 つのファクトリをすばやく切り替える必要があるコードになった場合、各ポイントでメソッド呼び出しを記述する必要があります。各サブオブジェクトに状態を格納することはできません (まあ、できますが、グローバル状態の目的を無効にします [これは確かにそれほど多くはありません])。

おそらく、ファクトリ型をメンバーとして格納し、それを必要とする新しいオブジェクトのコンストラクターに渡す (または必要に応じて新しいオブジェクトを作成するなど) のが最も理にかなっています。また、より優れた制御が可能になります。オブジェクト A によって構築されたすべてのオブジェクトが同じファクトリを経由したことを保証したり、ファクトリをスワップ アウトするメソッドを提供したりできます。

于 2009-08-16T19:29:09.697 に答える
4

これらのファクトリを呼び出すコードの適切な単体テストを作成するのが非常に難しくなるため、私はこれに反対することをお勧めします。

Misko Heveryのブログに、これに関するすばらしい記事があります。

于 2009-08-16T19:33:20.173 に答える
4

これはベストプラクティスと見なされますか?

問題はありません。「私のプログラムはこれ以上必要ない」と言ったため、より柔軟で抽象的なものを実装することは、 You Ain't Gonna Need Itの場合になる可能性があります。

于 2009-08-16T19:26:57.270 に答える
1

シングルトンの悪い形式は、 Factory メソッドと同等のものを次のように実装するものです。

return new CalculationFactory ();

これは、スタブ、モック、またはラップするのがはるかに困難です。

他の場所で作成されたオブジェクトを返すバージョンははるかに優れていますが、ほとんどのものと同様に、誤用または過剰使用される可能性があります。

于 2009-08-16T22:46:46.540 に答える