IOCコンテナがOOP原則を破る


51

IOCコンテナの目的は何ですか?組み合わされた理由は、次のように簡略化できます。

OOP / SOLID開発の原則を使用する場合、依存関係の注入が面倒になります。下位レベルの複数のレベルの依存関係を管理し、構築を通じて依存関係を再帰的に渡す最上位のエントリポイントがあるか、必要に応じて依存関係を構築するファクトリー/ビルダーパターンおよびインターフェイスにコードが多少重複しています。

これを実行するには、何のOOP / SOLID方法はありません、超きれいなコードを持っているが。

前のステートメントが正しい場合、IOCコンテナーはどのようにそれを行いますか?私の知る限り、それらは手動のDIでは実行できない未知の手法を使用していないため、IOCコンテナは静的オブジェクトのプライベートアクセッサを使用してOOP / SOLID原則を破ることだけです。

IOCコンテナは、背後で次の原則を破っていますか?私はよく理解しているので、これは本当の質問ですが、他の誰かがより良い理解を持っていると感じています

  1. スコープ制御。スコープは、コード設計に関するほとんどすべての決定の理由です。ブロック、ローカル、モジュール、静的/グローバル。スコープは、ブロックレベルでできるだけ多く、静的でできるだけ少なくする必要があります。宣言、インスタンス化、およびライフサイクルの終了が表示されます。言語とGCは、明示的に明示している限り、スコープを管理することを信頼しています。私の研究では、IOCコンテナがほとんどまたはすべての依存関係を静的として設定し、バックグラウンドでAOP実装を介して制御していることがわかりました。したがって、何も透明ではありません。
  2. カプセル化。カプセル化の目的は何ですか?なぜプライベートメンバーを保持する必要があるのですか?実際的な理由により、APIの実装者は、状態(所有者クラスによって管理される必要があります)を変更して実装を中断することはできません。しかし、セキュリティ上の理由から、メンバー状態を追い越し、検証とクラス制御をバイパスするインジェクションが発生しないようにします。したがって、プライベートメンバーへの外部アクセスを許可するためにコンパイル時間の前に何らかの形でコードを挿入するもの(モックフレームワークまたはIOCフレームワーク)は非常に巨大です。
  3. 単一責任の原則。表面的には、IOCコンテナは物事をよりきれいにするようです。しかし、ヘルパーフレームワークなしで同じことを達成する方法を想像してください。十数個の依存関係を持つコンストラクターが渡されます。それはIOCコンテナーでそれをカバーすることを意味するものではありません、それは良いことです!コードをリファクタリングし、SRPに従うことを示すサインです。
  4. オープン/クローズ。SRPがクラスのみではないように(メソッドはもちろん、SRPを単一の責任ラインに適用します)。Open / Closedは、クラスのコードを変更しないという単なる高レベルの理論ではありません。プログラムの構成を理解し、何が変更され、何が拡張されるかを制御する習慣です。IOCコンテナは、次の理由でクラスの動作方法を完全に変更できます。

    • a。主なコードは依存関係の切り替えを決定するのではなく、フレームワークの構成です。

    • b。スコープは、呼び出し元のメンバーによって制御されていないときに変更される可能性があり、代わりに静的フレームワークによって外部で決定されます。

したがって、クラスの構成は実際には閉じられていません。サードパーティのツールの構成に基づいて変更されます。

これが質問である理由は、私が必ずしもすべてのIOCコンテナのマスターではないからです。また、IOCコンテナーのアイデアは素晴らしいものの、実装が不十分なことを覆い隠す外観にすぎません。しかし、外部のスコープ制御、プライベートメンバーアクセス、および遅延読み込みを実現するには、多くの重要な疑問の余地のある作業を継続する必要があります。AOPは素晴らしいですが、IOC Containersを介して達成される方法にも疑問があります。

私は、C#と.NET GCが期待どおりに動作することを信頼できます。しかし、コンパイルされたコードを変更して、手動で実行できないことに対する回避策を実行するサードパーティ製のツールに同じ信頼を置くことはできません。

EG:Entity Frameworkと他のORMは、厳密に型指定されたオブジェクトを作成してデータベースエンティティにマッピングし、CRUDを実行するための基本的な機能を提供します。誰でも独自のORMを構築し、OOP / SOLID原則を手動で従うことができます。しかし、これらのフレームワークは私たちを助けてくれるので、毎回車輪を再発明する必要はありません。一方、IOC Containersは、OOP / SOLID原則を意図的に回避し、それを隠すのに役立つようです。


13
+1との間の相関関係はIOCExplicitness of codeまさに私が問題を抱えているものです。手動DIは簡単に面倒になりますが、少なくとも自己完結型の明示的なプログラムフローを1つの場所に配置します。IOCコンテナのバインディングと宣言は、それ自体で簡単に非表示の並列プログラムになります。
ユージンポッドスカル14

6
これはどうすれば質問ですか?
スティーブン14

8
これは質問というよりもブログ投稿のようです。
バートヴァンインゲンシェナウ14

4
私は質問のための内部カテゴリーを持っています、それは公式の近い理由ではありませんが、私は投票し、時には「本当の質問ではない」を閉じるために投票することです。ただし、これには2つの側面があり、この質問は最初の質問にしか当てはまりません。(1)質問は論文を述べ、それが正しいかどうかを尋ねます。(2)質問者は同意しない回答に応答し、初期の立場を擁護します。マシューの答えは、質問の内容の一部と矛盾するため、質問者がそれをくまなくクロールしない限り、「私は正しい」とはいえ、個人的にこれを誠実な質問として分類します。
スティーブジェソップ14

3
@BenAaronsonベンありがとう。私は自分の研究を通じて学んだことを伝え、IOCコンテナの性質について答えを得ようとしています。私の研究の結果、これらの原則が破られていることがわかりました。私の質問に対する最良の答えは、IOC ContainersがOOP / SOLID Principlesを破ることなく手動でできないことをなんとかできることを確認または否定することです。あなたの素晴らしいコメントのために、私は質問をより多くの例でリファクタリングしました。
Suamere

回答:


35

私はあなたのポイントを数値で調べますが、最初に、あなたが非常に注意しなければならないことがあります:消費者がライブラリを使用する方法とライブラリの実装方法を混同しないでください。これの良い例は、Entity Framework(あなた自身が優れたライブラリとして引用している)とASP.NETのMVCです。これらの両方は、たとえば、リフレクションを使用して非常に多くのことを行います。これは、日常のコードに拡散すると、絶対に良いデザインとは見なされません。

これらのライブラリは、その動作方法や舞台裏で行われていることにおいて「透過的」ではありません。しかし、消費者の優れたプログラミング原則をサポートしているため、それは不利益ではありません。したがって、このようなライブラリについて話すときはいつでも、ライブラリの消費者として、その実装やメンテナンスを心配するのはあなたの仕事ではないことを忘れないでください。ライブラリを使用するコードを作成するのにどのように役立つか、またはそれを妨げるかについてのみ心配する必要があります。これらの概念を混同しないでください!

だから、ポイントで行くには:

  1. すぐに上記の例であると推測できるものに到達します。IOCコンテナはほとんどの依存関係を静的として設定すると言います。おそらく、それらがどのように機能するかの実装の詳細には、静的ストレージが含まれます(NinjectのようなオブジェクトのインスタンスをIKernelコアストレージとして持つ傾向があることを考えると、それさえ疑問です)。しかし、これはあなたの関心事ではありません!

    実際、IoCコンテナーは、貧乏人の依存性注入と同じようにスコープで明示的です。(IoCコンテナを貧乏人のDIと比較し続けるのは、DIをまったくDIと比較することは不公平で混乱を招くためです。そして、明らかに、「貧乏人のDI」を軽jorとして使用していません。)

    貧乏人のDIでは、依存関係を手動でインスタンス化し、それを必要とするクラスに注入します。依存関係を構築する時点で、それをどう処理するかを選択します。ローカルスコープの変数、クラス変数、静的変数に保存します。何も保存しないでください。同じインスタンスを多数のクラスに渡すことも、クラスごとに新しいインスタンスを作成することもできます。なんでも。ポイントは、どちらが起こっているかを確認するために、依存関係が作成されるポイント(おそらくアプリケーションルートの近く)に注目することです。

    IoCコンテナについてはどうでしょうか?まあ、あなたはまったく同じことをします!ここでも、Ninjectの用語で行く、あなたはバインディングが設定されているところを見て、それが何かのように述べているかどうかを見つけるInTransientScopeInSingletonScopeまたは何でも。何らかのオブジェクトに何が起こるかを追跡するためにメソッドを調べる必要はなく、スコープを宣言するコードがあるため、これが潜在的に明確である場合(オブジェクトはブロックにスコープされているかもしれませんが、その中で複数回使用されていますたとえば、ブロックまたは1回だけ)。したがって、生の言語機能ではなく、IoCコンテナの機能を使用して範囲を決定する必要があるという考えに反発されるかもしれませんが、IoCライブラリを信頼している限り(そうすべきです!) 。

  2. ここであなたが何について話しているのか、まだよくわかりません。IoCコンテナーは、内部実装の一部としてプライベートプロパティを参照しますか?なぜそうなるのかは分かりませんが、もしそうなら、あなたが使用しているライブラリがどのように実装されるかはあなたの関心事ではありません。

    または、多分、彼らはプライベートセッターに注入するような機能を公開しますか?正直なところ、私はこれに遭遇したことがなく、これが本当に一般的な機能であるかどうか疑問に思っています。しかし、たとえそれが存在していても、誤用される可能性のあるツールの単純なケースです。IoCコンテナがなくても、プライベートプロパティにアクセスして変更するのはほんの数行のReflectionコードにすぎないことを忘れないでください。それはほとんど絶対にすべきでないことですが、それは.NETが機能を公開するのに悪いことを意味しません。誰かがツールを明白かつ乱暴に誤用した場合、それはツールの責任ではなく、人の責任です。

  3. ここでの最終的なポイントは2に似ています。ほとんどの場合、IoCコンテナーはコンストラクターを使用します。セッターインジェクションは、特定の理由により、コンストラクターインジェクションを使用できない非常に特殊な状況で提供されます。渡される依存関係の数を隠蔽するために常にセッターインジェクションを使用する人はだれでも、ツールを大幅に中止しています。それはツールのせいではなく、彼らのせいです。

    さて、これが非常に簡単な間違いであり、IoCコンテナが推奨する間違いである場合、それで問題ありません。それは私のクラスのすべてのメンバーを公開し、他の人がすべきでないものを変更したときに非難するようなものですよね?しかし、SRPの違反を隠蔽するためにセッターインジェクションを使用する人は、基本的な設計原則を故意に無視するか、まったく知らないかのいずれかです。IoCコンテナーでこれを非難するのは不合理です。

    それがあります特に、それはまた、あなたが貧乏人のDIと同様に簡単に行うことができるものだから真:

    var myObject 
       = new MyTerriblyLargeObject { DependencyA = new Thing(), DependencyB = new Widget(), Dependency C = new Repository(), ... };
    

    本当に、この心配は、IoCコンテナーが使用されているかどうかに完全に直交しているように見えます。

  4. クラスの連携方法の変更は、OCPの違反ではありません。もしそうなら、すべての依存関係の逆転はOCPの違反を助長するでしょう。これが当てはまる場合、それらは両方とも同じ固い頭字語ではありません!

    さらに、a)とb)のどちらもOCPに関係するものではありません。OCPに関してこれらに答える方法すら知りません。

    私が推測できる唯一のことは、OCPは、実行時に変更されない動作、または依存関係のライフサイクルがコードのどこから制御されるかに関するものだと思うということです。そうではありません。OCPでは、要件が追加または変更されたときに既存のコードを変更する必要はありません。それはすべて、コードを書くことであり、すでに書いたコードをどのように結び付けるかではありません(もちろん、疎結合はOCPを達成するための重要な部分です)。

そして最後にあなたが言うこと:

しかし、コンパイルされたコードを変更して、手動で実行できないことに対する回避策を実行するサードパーティ製のツールに同じ信頼を置くことはできません。

はい、できます。膨大な数のプロジェクトに依存しているこれらのツールが、他のサードパーティライブラリよりもバグが多いか、予期しない動作を起こしやすいと考える理由はまったくありません。

補遺

私はあなたのイントロのパラグラフがいくつかのアドレス指定も使用できることに気づきました。IoCコンテナは、依存関係グラフを作成するための乱雑で重複しやすいコードを回避するために、「聞いたこともない秘密の手法を採用していない」と皮肉を言っています。そして、あなたはまったく正しいです。彼らがしていることは、私たちプログラマーがいつもしているのと同じ基本的なテクニックでこれらの事柄に実際に取り組んでいるということです。

仮定のシナリオを通して話させてください。プログラマーとして、大規模なアプリケーションを作成し、オブジェクトグラフを作成するエントリポイントで、非常に厄介なコードがあることに気づきます。何度も何度も使用されるクラスは非常に多く、そのうちの1つを構築するたびに、その下にある依存関係のチェーン全体を構築する必要があります。さらに、依存関係のライフサイクルを宣言または制御する表現方法はありませんが、それぞれのカスタムコードを使用する場合を除きます。コードは構造化されておらず、繰り返しに満ちています。これは、イントロの段落で説明する混乱です。

そのため、最初に、リファクタリングを開始します。いくつかの繰り返しコードが十分に構造化されているので、それをヘルパーメソッドに引き出します。しかし、あなたは考え始めます-これはおそらく私が一般的な意味で取り組むことができる問題であり、この特定のプロジェクトに固有のものではなく、将来のすべてのプロジェクトであなたを助けることができる問題ですか?

したがって、あなたは座って考えて、依存関係を解決できるクラスがあるべきだと判断します。そして、必要なパブリックメソッドをスケッチします。

void Bind(Type interfaceType, Type concreteType, bool singleton);
T Resolve<T>();

Bind「タイプのコンストラクター引数が表示される場所interfaceTypeで、インスタンスを渡します」と言いますconcreteType。追加のsingletonパラメーターは、concreteType毎回同じインスタンスを使用するか、常に新しいインスタンスを作成するかを示します。

Resolve単純に、T以前にバインドされたすべての型の引数を持つ引数を見つけることができるコンストラクタで構築しようとします。また、依存関係を完全に解決するために、それ自体を再帰的に呼び出すこともできます。すべてがバインドされていないためにインスタンスを解決できない場合、例外をスローします。

これを自分で実装してみてください。少しのリフレクションが必要で、バインディングのキャッシングが必要な場合がありますが、singleton劇的なことや恐ろしいことはありません。そして、完了したら、あなたはあなた自身のIoCコンテナの中核を手に入れました!それは本当にそんなに怖いですか?これとNinject、StructureMap、Castle Windsor、またはあなたが好むものとの唯一の本当の違いは、これらの基本的なバージョンでは不十分な(多くの!)ユースケースをカバーするためのより多くの機能があることです。しかし、基本的には、IoCコンテナーの本質があります。


ありがとう、ベン。正直に言って、IOC Containersで作業したのは約1年だけで、私はやっていませんが、チュートリアルや私の周りの仲間はプロパティインジェクション(プライベートを含む)に集中しています。それはクレイジーで、私が作るすべてのポイントをもたらします。しかし、他の人がこのような状況にある場合でも、彼らができる最善のことは、IOC Containersが原則に従うためにどのように機能するかについてさらに学び、コードレビューでこれらの原則を破る点を指摘することだと思います。ただし...(続き)
Suamere 14

私の最大の懸念は、必ずしもOOP / SOLID Principlesにリストされているわけではなく、それはスコープの明示性です。私はまだ、キーワードのウィンドウを理解するブロック、ローカル、モジュール、およびグローバルレベルのスコープを投げています。ブロックを使用すること、および何かが範囲外になるか廃棄されるかを決定する宣言の全体的なアイデアは私にとって巨大であり、それは私にとってIOCコンテナの最も恐ろしい部分だったと思います。 。
Suamere

それで、私はあなたの反応を答えとしてマークしました。そして、私がそれを読む方法は、IOC Containersが他の誰もがそうするので、覆いの下で何をするかを信頼する必要があるということです。そして、誤用の可能性とそれを隠すエレガントな方法に関する限り、それはショップとコードレビューが心配することであり、良い開発原則に従うためにデューデリジェンスを行うべきです。
Suamere

2
4に関しては、Dependency InjectionはSOLIDの頭字語ではありません。'D' = 'Dependency Inversion Principle'、これはまったく無関係の概念です。
astreltsov

@astr良い点。そもそも「意図」を書くつもりだったと思うので、「注入」を「反転」に置き換えました。依存関係の反転は必ずしも複数の具体的な実装を意味するわけではないので、それはまだ少し単純化しすぎていますが、その意味は十分明確だと思います。実装の切り替えがOCP違反である場合、ポリモーフィックな抽象化に依存することは危険です。
ベンアーロンソン

27

IOCコンテナはこれらの原則の多くを破りませんか?

理論的には?いいえ。IoCコンテナは単なるツールです。単一の責任を持つオブジェクト、明確に分離されたインターフェース、書き込み後の動作を変更できないオブジェクトなどを持つことができます。

実際には?絶対に。

つまり、IoCコンテナを使用して、特定の構成を使用してシステムの動作を変更できるようにする、つまりOpen / Closed Principleに違反していると言うプログラマーは少なくありません。仕事の90%がSpringの設定を修正していたため、XMLのコーディングについて冗談を言っていました。そして、確かに、依存関係を隠すこと(確かに、すべてのIoCコンテナーがそうするわけではない)が、高度に結合され、非常に脆弱なコードを作成するための迅速かつ簡単な方法であることは確かです。

別の方法で見てみましょう。単一の基本的な依存関係を持つ非常に基本的なクラスを考えてみましょう。それは、Actionパラメータをとらずに戻るデリゲートまたはファンクタに依存しますvoid。このクラスの責任は何ですか?わかりません。その依存関係を明確CleanUpActionにすることで、自分がやりたいことを実行できると思うようになります。IoCが登場するとすぐに、それは何でもなります。誰でも構成にアクセスしてソフトウェアを変更し、ほぼ任意のことを実行できます。

Actionコンストラクタにを渡すこととどう違うのですか?」あなたが尋ねる。ソフトウェアがデプロイされた後(または実行時に!)コンストラクターに渡されるものを変更できないため、これは異なります。ユニットテスト(またはコンシューマのユニットテスト)がデリゲートがコンストラクターに渡されるシナリオをカバーしているため、これは異なります。

「しかし、それは偽の例です。私のものでは、動作を変更することはできません!」あなたは叫ぶ。教えてすみませんが、そうです。注入するインターフェイスが単なるデータでない限り。また、インターフェイスは単なるデータではありません。それが単なるデータである場合は、単純なオブジェクトを作成して使用するからです。インジェクションポイントに仮想メソッドがあるとすぐに、IoCを使用するクラスの規約は「何でもできます」です。

「スクリプトを使用して物事を推進することと、それはどのように違いますか。それはまったく問題ありません。」あなたの何人かが尋ねます。違いはありません。プログラム設計の観点からは、違いはありません。任意のコードを実行するためにプログラムを呼び出しています。そして確かに、それは長い間ゲームで行われてきました。大量のシステム管理ツールで実行されます。それはOOPですか?あんまり。

彼らの現在の遍在性の言い訳はありません。IoCコンテナーには、1つの強固な目的があります。非常に多くの組み合わせがある場合に依存関係を結合するか、依存関係を明示的にするのは実用的でないほど急速にシフトします。そのため、実際にそのシナリオに適合する企業はほとんどありません。


3
右。そして、多くの店は、彼らの製品が非常に複雑であると主張するでしょう。多くのシナリオでは真実です。
Suamere

12
しかし、IoCはあなたが言ったことと正反対です。プログラムのオープン/クローズを採用しています。コード自体を変更せずにプログラム全体の動作を変更できる場合。
陶酔14

6
@Euphoric-拡張のために開き、変更のために閉じます。プログラム全体の動作を変更できる場合、変更のために閉じられていませんか?IoC構成は依然としてソフトウェアであり、JavaやC#などではなくXMLである場合でも、クラスが動作するために使用するコードです。
テラスティン14

4
@Telastyn「修正のためにクローズ」は、全体の動作を変更するために、コードを変更(変更)する必要がないことを意味します。外部設定を使用して、新しいDLLを指定するだけで、全体を変更する動作を実行できます。
陶酔

12
@Telastynそれは、オープン/クローズド原則が言っていることではありません。そうしないと、異なるパラメーターを渡すことでその動作を「変更」できるため、パラメーターを取るメソッドはOCPに違反します。同様に、OCPのバージョンでは、DIと直接競合するため、両方がSOLID頭字語に表示されるのはかなり奇妙になります。
ベンアーロンソン14

14

IoCコンテナーの使用は、必ずしもOOP / SOLIDの原則に違反しますか?いいえ

IoCコンテナーをOOP / SOLIDの原則に違反するような方法で使用できますか?はい

IoCコンテナは、アプリケーションの依存関係を管理するための単なるフレームワークです。

レイジーインジェクション、プロパティセッター、および使用する必要があるとはまだ感じていない他のいくつかの機能について述べましたが、最適なデザインとは言えないことに同意します。ただし、これらの特定の機能の使用は、IoCコンテナーを実装しているテクノロジーの制限によるものです。

たとえば、ASP.NET WebFormsでは、Page。をインスタンス化することができないため、プロパティインジェクションを使用する必要があります。WebFormsは厳密なOOPパラダイムを念頭に置いて設計されたことがないため、これは理解できます。

一方、ASP.NET MVCでは、非常にOOP / SOLIDに適したコンストラクターインジェクションを使用してIoCコンテナーを使用できます。

このシナリオ(コンストラクターインジェクションを使用)では、次の理由により、SOLID原則が促進されます。

  • 単一責任の原則-多くの小さなクラスを使用すると、これらのクラスを非常に具体的にすることができ、既存の理由が1つあります。IoCコンテナーを使用すると、それらを整理しやすくなります。

  • Open / Closed-これは、IoCコンテナの使用が本当に優れている場所です。異なる依存関係を注入することにより、クラスの機能を拡張できます。注入する依存関係があると、そのクラスの動作を変更できます。良い例は、デコレータを記述してキャッシングまたはロギングを追加することにより、注入するクラスを変更することです。適切な抽象化レベルで記述されている場合、依存関係の実装を完全に変更できます。

  • Liskov Substitution Principle-あまり関係ない

  • インターフェースの分離の原則-必要に応じて、複数のインターフェースを1つの具体的な時間に割り当てることができます。

  • 依存関係の反転-IoCコンテナーを使用すると、依存関係の反転を簡単に行うことができます。

一連の依存関係を定義し、関係とスコープを宣言し、bing bang boom:魔法のように、ある時点でコードまたはILを変更して動作させるアドオンがあります。それは明示的または透明ではありません。

明示的かつ透過的であるため、依存関係を結び付ける方法とオブジェクトの有効期間を管理する方法をIoCコンテナに伝える必要があります。これは、慣例、構成ファイル、またはシステムのメインアプリケーションで記述されたコードのいずれかです。

IOCコンテナを使用してコードを記述または読み取ると、少し洗練されていないコードが削除されることに同意します。

これが、システムを管理しやすくするためのOOP / SOLIDの全体的な理由です。IoCコンテナーの使用は、その目標に沿ったものです。

そのクラスの作成者は、「IOCコンテナーを使用しなかった場合、コンストラクターには12個のパラメーターがあります!!!それは恐ろしいことです!」

12個の依存関係を持つクラスは、使用しているコンテキストに関係なく、おそらくSRP違反です。


2
素晴らしい答え。さらに、すべての主要なIOCコンテナもAOPをサポートしていると思います。これはOCPで大いに役立ちます。横断的な関心事では、AOPは通常、デコレータよりもOCPに適したルートです。
ベンアーロンソン14

2
@BenAaronson AOPがコードをクラスに注入することを考えると、私はそれをOCPフレンドリと呼ぶつもりはありません。コンパイル/実行時にクラスを強制的に開いて変更しています。
ドーバル14

1
@Dovalクラスにコードを挿入する方法がわかりません。注:IL織りのスタイルではなく、インターセプターがあるCastle DynamicProxyスタイルについて説明しています。ただし、インターセプターは本質的に、リフレクションを使用するデコレーターに過ぎないため、特定のインターフェイスに結合する必要はありません。
ベンアーロンソン

「依存関係の反転-IoCコンテナを使用すると、依存関係の反転を簡単に行うことができます」-できません。IoCを使用しているかどうかに関係なく、有益な何かを活用するだけです。他の原則と同じです。
デン14

私は、フレームワークであるという事実に基づいて何かが悪いわけではないという説明の論理は本当に得られません。ServiceLocatorはフレームワークとしても作成されており、不良とみなされます:)。
ipavlu

5

IOCコンテナーは、多くのOOP / SOLID原則を破り、コーダーが破ることを許さないのですか?

staticC#のキーワードにより、開発者は多くのOOP / SOLID原則を破ることができますが、適切な状況では依然として有効なツールです。

IoCコンテナーは、適切に構造化されたコードを可能にし、開発者の認知的負担を軽減します。IoCコンテナーを使用すると、SOLIDの原則に従うことがはるかに簡単になります。確かに誤用される可能性がありますが、誤用される可能性のあるツールの使用を除外した場合、プログラミングを完全に放棄する必要があります。

したがって、この暴言は不十分に書かれたコードについていくつかの有効なポイントを提起しますが、それは正確に質問ではなく、正確に有用ではありません。


IOCコンテナについての私の理解は、スコープ、遅延、アクセシビリティを管理するために、コンパイルされたコードを変更してOOP / SOLIDを壊すことを行いますが、その実装を素晴らしいフレームワークの下に隠します。しかし、はい、それはさらに誤った使用のために他のドアを開きます。私の質問に対する最良の答えは、私自身の研究を追加または無効化するIOCコンテナの実装方法に関する明確化です。
Suamere

2
@Suamere-IOCの定義が広すぎます。私が使用するものは、コンパイルされたコードを変更しません。コンパイルされたコードを変更する、IOC以外のツールもたくさんあります。たぶんあなたのタイトルは、「コンパイルされたコードを変更しますか?」のようになります。
セラド14

@Suamere IoCの経験はあまりありませんが、IoCがコンパイルされたコードを変更したことは聞いたことがありません。どのプラットフォーム/言語/フレームワークについて話しているかについての情報を提供してください。
陶酔14

1
「IoCコンテナを使用すると、SOLIDの原則に従うことがはるかに簡単になります。」-詳しく説明してください。それが各原則に具体的にどのように役立つかを説明することが役立つでしょう。そしてもちろん、何かを活用することは、何かが起こるのを助けることと同じではありません(例:DI)。
デン14

1
@Euphoric suamereが話していた.netフレームワークについては知りませんが、Springは確かに内部コード変更を行います。最も明白な例は、メソッドベースのインジェクションのサポートです(これにより、クラス内の抽象メソッドをオーバーライドして、管理する依存関係を返します)。また、自動生成されたプロキシを広範に使用して、コードをラップして追加の動作を提供します(トランザクションの自動管理など)。ただし、この多くは、実際にはDIフレームワークとしての役割とは関係ありません。
ジュール14年

3

あなたの質問には複数の間違いや誤解があります。最初の大きな問題は、プロパティ/フィールドインジェクション、コンストラクターインジェクション、およびサービスロケーターの区別が欠落していることです。どちらが物事を行うのが正しい方法であるかについて、多くの議論(例:フレームウォーズ)がありました。あなたの質問では、プロパティの注入のみを想定し、コンストラクターの注入を無視しているようです。

2番目のことは、IoCコンテナーが何らかの形でコードの設計に影響を与えると仮定することです。IoCを使用している場合、コードのデザインを変更する必要はありません。少なくとも変更する必要はありません。多くのコンストラクターを持つクラスの問題は、IoCがコードの実際の問題(ほとんどの場合SRPを破るクラス)を隠すケースであり、隠された依存関係は、プロパティインジェクションとサービスロケーターの使用を推奨しない理由の1つです。

私は、オープンクローズド原則の問題がどこに来るのか理解していないので、コメントしません。しかし、SOLIDの一部が欠落しています。これは、これに大きな影響を及ぼします:依存関係反転の原則。DIPに従うと、依存関係を反転すると抽象化が発生し、クラスのインスタンスが作成されたときに実装を解決する必要があることがわかります。このアプローチでは、適切に機能するために構築時に複数のインターフェイスを実現して提供する必要がある多くのクラスが作成されます。これらの依存関係を手動で提供する場合、多くの追加作業を行う必要があります。IoCコンテナーを使用すると、この作業が簡単になり、プログラムを再コンパイルしなくても変更できます。

だから、あなたの質問への答えはノーです。IoCコンテナーは、OOPの設計原則に違反しません。まったく逆に、SOLIDの原則(特にDependency-Inversionの原則)に従うことによって引き起こされる問題を解決します。


最近、重要でないプロジェクトにIoC(Autofac)を適用しようとしました。私は非言語構成要素で同様の仕事をしなければならなかったことに気付きました(new()vs API):インターフェイスに解決すべきものと具体的なクラスに解決すべきものを指定し、インスタンスとシングルトンにすべきものを指定し、循環依存を緩和するために、プロパティインジェクションが正しく機能することを確認します。放棄することにしました。ただし、ASP MVCのコントローラーでうまく機能します。
デン14

@Denあなたのプロジェクトは、依存関係の逆転を念頭に置いて明らかに設計されていません。そして、IoCの使用は簡単だとは言いませんでした。
陶酔14

実際、そのこと-私は最初からずっと依存関係反転を使用しています。それ以上の設計に影響を与えるIoCは、私の最大の心配です。たとえば、なぜIoCを単純化するためだけにどこでもインターフェイスを使用するのでしょうか?質問の一番上のコメントも参照してください。
デン14

@Denは、技術的にはインターフェイスを使用する必要はありません。インターフェイスは、単体テストのモック作成に役立ちます。また、仮想のモックに必要なものをマークすることもできます。
フレッド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.