質問

デフォルトの実装をデフォルトのコンストラクターに単純にハードコーディングするよりも、IOC コンテナを使用する利点を誰かが説明してもらえますか?

言い換えれば、このコードのどこが間違っているのでしょうか?

public class MyClass
{
    private IMyInterface _myInterface;

    public MyClass()
    {
        _myInterface = new DefaultMyInterface();
    }

    public MyClass(IMyInterface myInterface)
    {
        _myInterface = myInterface;
    }
}

私の知る限り、このクラスはコンストラクター インジェクションを十分にサポートしているため、単体テストとモックを簡単に実行できます。これに加えて、デフォルトのコンストラクターは IOC コンテナーの計算オーバーヘッドを削除します (プロセス全体がより透過的であることは言うまでもありません)。

IOC コンテナを使用することの唯一の利点は、インターフェイスの実装を頻繁に切り替える必要がある場合です。何かが足りないのでしょうか?

役に立ちましたか?

解決

IoC の考え方は、コンポーネントの機能の一部をシステムの別の部分に委任することです。IoC の世界には、お互いのことを知らないコンポーネントがあります。MyClass と IMyInterface の一部の実装の間に密結合を作成しているため、あなたの例はこれに違反します。 本旨 それはあなたのコンポーネントですか 知識がありません どのように使われるのかについて。あなたの例では、コンポーネント いくつかの仮定を立てます その使用法について。

実際、このアプローチは機能しますが、IoC と明示的なオブジェクト初期化を混合することは、IMO の良い実践ではありません。

IoC は、コードの明瞭性を犠牲にして遅延バインディングを実行することにより、疎結合を実現します。このプロセスに追加の動作を追加すると、事態はさらに複雑になり、一部のコンポーネントが望ましくない動作や予期しない動作を持つオブジェクトを受け取る可能性がある場合、バグが発生する可能性があります。

他のヒント

どちら側を選んでください:)

要するに IOC が推奨されます。コードの問題は、最後に述べたように、コードを再コンパイルせずに依存関係のデフォルトの実装を交換できないことです。IOC を使用すると、再コンパイルせずに、外部ファイル内のオブジェクトの構成または構成を変更できます。
IOC は、コードの残りの部分から「構築とアセンブリ」の責任を引き継ぎます。IOC の目的は、コードをテスト可能にすることではありません...それは嬉しい副作用です。(TDD コードがより良い設計につながるのと同じように)

このコードには何も問題はなく、Spring や Guice などの依存性注入フレームワークでも引き続き使用できます。

多くの開発者は、Spring の XML 構成ファイルは、コンパイル手順を必要とせずに実装を切り替えることができるため、コード内で依存関係を配線するよりも利点があると考えています。この利点は実際には、クラスパス内にすでに複数の実装がコンパイルされており、デプロイメント時に実装を選択したい状況で実現されます。導入後にコンポーネントがサードパーティから提供される状況が想像できます。同様に、展開後に追加の実装をパッチとして配布したい場合があります。

ただし、すべての DI フレームワークが XML 構成を使用するわけではありません。たとえば、Google Guice には Java クラスとして記述されたモジュールがあり、他の Java クラスと同様にコンパイルする必要があります。

では、コンパイル手順が必要な場合でも、DI にはどのような利点があるのでしょうか?これで元の質問に戻ります。次のような利点があることがわかります。

  1. アプリケーション全体にわたる DI への標準的なアプローチ。
  2. 構成は他のロジックからきちんと分離されています。
  3. プロキシを挿入する機能。たとえば Spring では、実装の代わりにプロキシを挿入することで、宣言的なトランザクション処理を行うことができます。
  4. 構成ロジックの再利用が容易になります。DI を広範囲に使用すると、時間の経過とともに進化する依存関係の複雑なツリーが表示されます。明確に分離された構成レイヤーとフレームワークのサポートなしで管理することは悪夢のようなものになる可能性があります。DI フレームワークを使用すると、継承やその他の手段を通じて構成ロジックを簡単に再利用できます。

私の唯一の懸念は、(1) デフォルトのサービスの依存関係自体に別の/二次的なサービスの依存関係がある場合 (など...DefaultMyInterface は ILogger に依存している)、(2) 最初のサービスの依存関係を 2 番目のサービスの依存関係から分離する必要があることです (スタブ ILogger を使用して DefaultMyInterface をテストする必要があります)。その場合、明らかにデフォルトの「new DefaultMyInterface」を失い、代わりに次のいずれかを実行する必要があります。(1) 純粋な依存関係の注入、または (2) サービス ロケーター、または (3) container.BuildUp(new DefaultMyInterface());

他の投稿者が挙げた懸念事項の中には、あなたの質問に対して不公平なものもあるかもしれません。複数の「運用」実装について質問しているのではありません。あなたが尋ねているのは、 単体テスト。 ユニットテストの場合、最初に述べたように、あなたのアプローチは正当であるように思えます。私も、単純な単体テストのケースでこれを使用することを検討します。

同様に、数人の回答者は、悔しさについて懸念を表明した。私も繰り返しは好きではありませんが、(1) デフォルトの実装が本当にデフォルトである場合 (YAGNI:デフォルトを変更する計画はありません)、(2)私が述べた最初の警告が当てはまるとは信じていません、そして(3)あなたが共有したより単純なコードアプローチを好む場合、この特定の形式は必要ないと思います。繰り返しが問題です。

IoC は疎結合に加えて、コードの重複を削減します。IoC を使用し、インターフェイスのデフォルトの実装を変更する場合、変更する必要があるのは 1 か所だけです。デフォルトのコンストラクターを使用してデフォルトの実装を挿入する場合、インターフェイスが使用されるすべての場所でそれを変更する必要があります。

他のコメントに加えて、このような場合には DRY (Do Notrepeat Yourself) 原則が主張される可能性があります。すべてのクラスにデフォルトの構築コードを入れる必要があるのは冗長です。また、必要のない特別なケースの処理も導入されています。

デフォルトの実装をハードコーディングする手法が IOC コンテナと一緒に使用できない理由がわかりません。ただし、構成で指定していない依存関係にはデフォルトの実装が適用されます。

それとも何かが足りないのでしょうか?

IOC コンテナを使用する理由の 1 つは、ソフトウェアの後期構成を容易にするためです。

たとえば、特定のインターフェイスの実装をいくつか提供するとします。顧客 (または専門サービス チーム) は、IOC 構成ファイルを変更することで、どれを使用するかを決定できます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top