依存性注入を使用することの欠点は何ですか?[閉まっている]


336

私が知りたいのですが、ここでの仕事と私たちのリード開発者の一人で、パターンとしてDIを導入しようとしている:どのような-もしあれば-あるマイナス面依存性の注入パターンを使用するには?

ここでは、トピックに関する主観的な議論ではなく、可能な限り完全なリストを探していることに注意してください。


明確化:私は依存性注入パターン(Martin Fowlerによるこの記事を参照)について話しているのですが、特定のフレームワークではなく、XMLベース(Springなど)でもコードベース(Guiceなど)でも、「自己ロール」 。


編集:ここで/ r / programmingを進行中のいくつかの素晴らしいディスカッション/怒り/討論。


DI自体、またはそれをサポートする特定の種類のツール(XMLベースかどうか)について説明するかどうかを指定することをお勧めします。
ジェシーミリカン

5
違いは、「XMLサックス」など、特定のフレームワークにのみ適用される回答を探しているのではないということです。:)ここでFowlerによって概説されているDIの概念に当てはまる答えを探しています:martinfowler.com/articles/injection.html
Epaga

3
DI(コンストラクター、セッター、またはメソッド)全般にマイナス面はまったくありません。それはオーバーヘッドなしで分離し、簡素化します。
吉崎

2
@kissakiは、setter injectとは別に。建設時に使用できるオブジェクトを作成するのに最適です。私を信じていない場合は、「setter」インジェクションを使用してオブジェクトに別のコラボレーターを追加してみてください
。NPEが

回答:


209

いくつかのポイント:

  • 責任がより分離されるため、DIは通常、クラスの数を増やすことによって複雑さを増加させますが、これは必ずしも有益ではありません
  • コードは、(ある程度)使用する依存関係注入フレームワーク(または、より一般的には、DIパターンの実装を決定する方法)に結合されます。
  • タイプ解決を実行するDIコンテナーまたはアプローチは、通常、実行時に若干のペナルティを伴います(ごくわずかですが、そこにあります)

一般に、デカップリングの利点により、各タスクが読みやすく、理解しやすくなりますが、より複雑なタスクのオーケストレーションはより複雑になります。


72
-クラスの分離により、複雑さが軽減されます。多くのクラスはアプリケーションを複雑にしません。-あなたは、アプリケーションルートであなたのDIフレームワークに依存するだけであるべきです。
Robert

91
私たちは人間です。私たちの短期記憶は限られており、多くの<xxx>を同時に処理することはできません。プログラムの開発に使用するメソッド、関数、ファイル、または任意の構成体の場合と同様に、クラスでも同じです。
–HåvardS 2010

45
@ハバードS:はい、しかし5つの本当に複雑なクラスは15の単純なクラスよりも単純ではありません。複雑さを軽減する方法は、コードで作業するプログラマーが必要とするワーキングセットを削減することです。複雑で相互依存性の高いクラスは、それを実現しません。
共龍

35
@kyoryu私たちはみんなそれに同意していると思います。複雑さは結合と同じではないことに注意してください。カップリングを減らすと、複雑さが増す可能性があります。DIはクラスの数を増やすので悪いことだとは言っていませんが、DIに関連する潜在的なマイナス面を強調しています。:)
HåvardS

96
「DIにより複雑さが増す」+1これは、DI以降に当てはまります。(ほぼ)柔軟性が高まるたびに、複雑さが増します。それはバランスについてすべてです。それは、良い面と悪い面を知ることから始まります。人々が「不利な点はない」と言うとき、彼らがまだ事を完全に理解していないことは確かな指標です。
Don Branson

183

オブジェクト指向プログラミング、スタイルルール、およびその他すべてについてよくある基本的な問題。非常に一般的ですが、実際には、あまりに多くの抽象化を実行し、あまりにも多くの間接化を追加し、一般に優れた手法を過度に、間違った場所に適用する可能性があります。

適用するすべてのパターンまたはその他の構成は複雑になります。抽象化と間接化は情報を分散させ、時には無関係な詳細を邪魔にならないようにしますが、同じように時々何が起こっているのか正確に理解することを難しくします。適用するすべてのルールは柔軟性に欠け、最適なアプローチである可能性があるオプションを除外します。

ポイントは、その仕事を行い、堅牢で、読みやすく、保守可能なコードを書くことです。あなたはソフトウェア開発者であり、象牙の塔ビルダーではありません。

関連リンク

http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx

http://www.joelonsoftware.com/articles/fog0000000018.html


おそらく、最も単純な依存性注入の形式(笑わないでください)がパラメーターです。依存コードはデータに依存しており、そのデータはパラメーターを渡すことによって注入されます。

はい、それはばかげているし、依存性注入のオブジェクト指向のポイントに対処していませんが、関数型プログラマーは(ファーストクラスの関数がある場合)これが必要な唯一の種類の依存性注入であることを教えてくれます。ここでのポイントは、些細な例を取り、潜在的な問題を示すことです。

この単純な従来の関数を見てみましょう-C ++構文はここでは重要ではありませんが、なんとかして綴る必要があります...

void Say_Hello_World ()
{
  std::cout << "Hello World" << std::endl;
}

「Hello World」というテキストを抽出して挿入したい依存関係があります。簡単です...

void Say_Something (const char *p_text)
{
  std::cout << p_text << std::endl;
}

それはオリジナルよりもどのように柔軟性がないのですか?さて、もし出力がユニコードであるべきだと決めたらどうなるでしょう。おそらくstd :: coutからstd :: wcoutに切り替えたいと思います。しかし、それは私の文字列がcharではなくwchar_tでなければならないことを意味します。すべての呼び出し元を変更する必要があるか、または(より合理的に)古い実装が文字列を変換して新しい実装を呼び出すアダプターに置き換えられます。

それは、私たちがオリジナルを維持していれば必要のない、その場でのメンテナンス作業です。

そして、それが取るに​​足りないと思われる場合は、Win32 APIからこの実際の関数を見てください...

http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx

これは、対処する12の「依存関係」です。たとえば、画面解像度が非常に大きくなる場合は、64ビットの座標値と、CreateWindowExの別のバージョンが必要になる可能性があります。そしてはい、古いバージョンがまだぶら下がっていて、おそらく裏側で新しいバージョンにマッピングされています...

http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx

これらの「依存関係」は、元の開発者にとって単なる問題ではありません。そのインターフェースを使用するすべての人は、依存関係の内容、指定方法、意味を調べ、アプリケーションに対して何をすべきかを考えなければなりません。これは、「賢明なデフォルト」という言葉が人生をより単純にすることができる場所です。

オブジェクト指向の依存性注入は、原則として同じです。クラスの作成はソースコードテキストと開発者時間の両方でオーバーヘッドであり、そのクラスが依存オブジェクトの仕様に従って依存関係を提供するように作成されている場合、依存オブジェクトは、必要がある場合でもそのインターフェイスをサポートするようにロックされます。そのオブジェクトの実装を置き換える。

これは、依存性注入が悪いと主張していると読むべきではありません。しかし、どんな良いテクニックでも、過度に間違った場所に適用される可能性があります。すべての文字列を抽出してパラメータに変換する必要があるわけではないのと同様に、すべての低レベルの動作を高レベルのオブジェクトから抽出して注入可能な依存関係に変換する必要があるわけではありません。


3
依存性注入には、これらの欠点はありません。オブジェクトへの依存関係を渡す方法が変更されるだけで、複雑さや柔軟性が増すことはありません。全く逆です。
吉崎

24
@キスサキ-はい、依存関係を渡す方法が変わります。そして、依存関係の受け渡しを処理するコードを記述する必要があります。それを行う前に、どの依存関係を渡すかを調べ、依存コードをコーディングしなかった人にとって意味のある方法で定義する必要があります。実行時の影響を回避できます(たとえば、テンプレートにポリシーパラメータを使用する) C ++では)、しかしそれはまだあなたが書いて維持しなければならないコードです。それが正当化される場合、それは大きな報酬に対する非常に小さな価格ですが、支払うべき価格がないというふりをすると、それは、利益がないときにその価格を支払うことを意味します。
Steve314、2011

6
@Kissaki-柔軟性に関しては、依存関係が何であるかを指定すると、それに固定されます-他の人々はその仕様に従って注入する依存関係を記述しました。わずかに異なる依存関係を必要とする依存コードの新しい実装が必要な場合-難しいです。ロックインされています。代わりに、それらの依存関係用のアダプターの作成を開始してください(そして、もう少しオーバーヘッドと抽象化のレイヤーが増えます)。
Steve314

オーバーロードを検討している場合、私はこの例を理解しているとは思いません。リテラル「Hello World」を出力するには、()署名を使用します。8ビット文字列を出力するには、(char)シグネチャを使用します。ユニコードを出力するには、オーバーロード(wchar_t)。明らかに、この場合、(wchar_t)は他の人が裏で呼び出すものです。そこではコードの書き換えはあまり必要ありません。何か不足していますか?
原料

2
@ ingredient_15939-はい、これは簡略化されたおもちゃの例です。実際にこれを行っている場合は、コードを複製するコストがアダプターのコストよりも低いため、アダプターではなくオーバーロードを使用します。ただし、コードの複製は一般的に悪いことであり、アダプタの使用によるコードの複製の回避は、別の優れた手法です(使用頻度が高く、間違った場所で使用される場合があります)。
Steve314 2014年

77

ここに私自身の最初の反応があります:基本的にパターンの同じ欠点。

  • 学ぶには時間がかかる
  • 誤解すると、善よりも害につながる可能性があります
  • 極端に考えると、メリットを正当化するよりも多くの作業になる可能性があります

2
なぜ学ぶのに時間がかかるのですか?ejbに比べて物事が簡単になると思いました。
fastcodejava

8
これは、主観的な議論を望まないことを考えると、波打つように見えます。検討のための現実的な例を(必要に応じて集合的に)構築することをお勧めします。DI なしでサンプルを作成することから始めてください。次に、要件の変更に挑戦し、影響を調べることができます。(ちなみに、これから寝ようとしているので、これは私にとって非常に便利です。)
Jesse Millikan

4
これには実際にそれをバックアップするためのいくつかの例が必要であり、何十人もの人々にDIを教えてきたので、それは本当に学び、実践を始めるのは非常に単純な概念であると言えるでしょう。
チリトム

4
DIをパターンとは特に考えていません。これは(IoCと組み合わせて)本当にプログラミングモデルに近いものです。完全にフォローすると、コードは「典型的な」疑似手続き型オブジェクト指向オブジェクトよりもアクターのように見えます。
共龍

1
+1私はSymfony 2を使用していますが、DIはユーザーコード全体にあり、それを使用するだけで非常に優れています。
MGP

45

Inversion of Controlの最大の「欠点」(かなりDIではないが、十分に近い)は、アルゴリズムの概要を確認するための単一のポイントを削除する傾向があることです。ただし、これはコードを分離したときに基本的に何が起こるかです。1か所を見る機能は密結合の成果物です。


2
しかし、確かに「欠点」は、私たちが解決している問題の性質によるものであり、実装を簡単に変更できるように分離するということは、見るべき場所が1つもないことを意味します。私が考えることができる唯一のケースはデバッグであり、デバッグ環境は実装にステップインできるはずです。
vickirk

3
これが、「欠点」という言葉が引用符で囲まれていた理由です。)疎結合と強力なカプセル化により、定義上、「1つの場所ですべてを見る」ことができません。私がDI / IoCに反対していると感じた場合は、ハバードSの応答に関する私のコメントを参照してください。
共龍

1
私は同意します(私はあなたに投票しました)。私は要点を言っていました。
vickirk

1
@vickirk:私が推測する欠点は、人間が理解するのが難しいことです。物事を分離すると、人間が理解することが難しくなり、完全に理解するのに時間がかかるという意味で、複雑さが増します。
Bjarke Freund-Hansen

2
逆に、DIの利点の1つは、個々のクラスのコンストラクターを確認し、それが依存するクラス(つまり、どのクラスがその作業を行う必要があるか)を即座に計算できることです。他のコードでは、コードを自由にクラスを作成できるため、これははるかに困難です。
コンタンゴ

42

7
私が知りたいのですが、誰かが不思議を求めたとき、なぜ「存在しない」という精神での回答が賛成され、質問に関連するいくつかの情報を含む回答が反対されないのですか?
GabrielŠčerbák10年

12
-1リンク集を探しているわけではないので、実際の答えを探しています。各記事の要点を要約してみませんか?その後、代わりに賛成票を投じます。最初の2つは実際にはDIの否定的な否定を示しているようですが、記事自体は非常に興味深いことに注意してください。
Epaga

4
私はあなたが尋ねたことと私が答えたことを知っていることを確認します。確かに私は賛成票を求めているのではなく、なぜ私のことを混乱させているのでしょうか。答えが役に立たない一方で、DIの欠点は明らかにクールすぎるとのことですが、多くのことを助けています。
GabrielŠčerbák2010年

41

私は過去6か月間、Guice(Java DIフレームワーク)を広範囲に使用しています。全体的には(特にテストの観点から)素晴らしいと思いますが、欠点もあります。最も注目すべき点:

  • コードは理解しにくくなる可能性があります。依存性注入は、非常に...創造的な...方法で使用できます。たとえば、カスタムアノテーションを使用して特定のIOStreams(例:@ Server1Stream、@ Server2Stream)を挿入するコードを見つけました。これは機能し、ある程度の優雅さがあることは認めますが、Guiceインジェクションを理解することがコードを理解するための前提条件になります。
  • プロジェクトを学ぶときのより高い学習曲線。これはポイント1に関連しています。依存性注入を使用するプロジェクトの動作を理解するには、依存性注入パターンと特定のフレームワークの両方を理解する必要があります。現在の仕事を始めたとき、私はかなり多くの混乱した時間を費やして、Guiceが舞台裏で何をしていたのかを理解しました。
  • コンストラクターが大きくなります。これは主にデフォルトのコンストラクターまたはファクトリーで解決できますが。
  • エラーは難読化できます。最近の例では、2つのフラグ名が衝突しました。Guiceはエラーを静かに飲み込み、私のフラグの1つが初期化されませんでした。
  • エラーはランタイムにプッシュされます。Guiceモジュールを誤って構成すると(循環参照、不適切なバインディングなど)、コンパイル時にほとんどのエラーが明らかになりません。代わりに、プログラムが実際に実行されるときにエラーが公開されます。

今私は不満を言った。私の現在のプロジェクトで、そしておそらく次のプロジェクトで、Guiceを(喜んで)使用し続けます。依存性注入は、優れた非常に強力なパターンです。しかし、それは間違いなく混乱を招く可能性があり、選択した依存関係注入フレームワークに呪いをかける時間をほぼ確実に費やします。

また、依存性注入が過度に使用される可能性があるという他のポスターにも同意します。


14
なぜ人々が「エラーがランタイムにプッシュされる」という大きな取引をしないのか理解できません。それは取引ブレーカーであり、静的型付けとコンパイル時エラーは開発者に与えられる最大の贈り物です。離れて何のためにそれら
リチャード・チンクル

2
@RichardTingle、アプリの起動時のIMOはDIモジュールが最初に初期化されるため、数日後または時間後ではなく、アプリが起動するとすぐにモジュールの設定ミスが表示されます。モジュールを段階的にロードすることも可能ですが、アプリケーションロジックを初期化する前にモジュールのロードを制限することでDIの精神に固執する場合、アプリの開始への不良バインディングを正常に分離できます。しかし、それをサービスロケーターのアンチパターンとして構成すると、これらの悪いバインディングは驚くべきものになります。
k4vin 2016

@RichardTingleコンパイラーが提供するセーフティネットに似ていることはないが、DIはツールで正しく使用されるため、ボックスで指示されているとおり、ランタイムエラーはアプリの初期化に限定されます。その後、アプリの初期化を、DIモジュールの一種のコンパイルフェーズと見なすことができます。私の経験では、ほとんどの場合、アプリが起動すれば、不適切なバインディングや不適切な参照は含まれません。PS-NInjectをC#で使用しています
k4vin

@RichardTingle-私はあなたに同意しますが、疎結合のテスト可能なコードを取得するためのトレードオフです。また、k4vinが言ったように、初期化時に欠落している依存関係が見つかります。インターフェイスを使用すると、コンパイル時エラーが解決します。
Andrei Epure 2017

1
「コードをクリーンに保つのが難しい」をリストに追加します。登録なしでコードを広範囲にテストする前に、登録を削除できるかどうかはわかりません。
fernacolo

24

DIのないコードは、スパゲッティコード巻き込まれるよく知られたリスクを冒します -一部の症状は、クラスとメソッドが大きすぎ、やりすぎて、簡単に変更、分解、リファクタリング、またはテストできないことです。

DIを多用するコードは、各小クラスが個別のラビオリナゲットのようなラビオリコードにすることができます。これは1つの小さなことを行い、単一責任の原則が守られているので、優れています。しかし、クラス自体を見ると、システム全体が何をしているのかを理解することは困難です。これは、これらの多くの小さな部品がどのように組み合わされているかによって異なり、わかりにくいからです。小さなものの大きな山のように見えます。

大きなクラス内の結合されたコードの大きなビットのスパゲッティ複雑さを回避することにより、単純な小さなクラスがたくさんあり、それらの間の相互作用が複雑である、別の種類の複雑さのリスクを負います。

これが致命的なマイナス面だとは思わない-DIはまだ非常に価値がある。たった1つのことを行う少人数クラスのある程度のラビオリスタイルは、おそらく良いでしょう。過剰でもスパゲッティコードとしては悪くないと思います。しかし、それがあまりにも遠くにある可能性があることを認識することは、それを回避する最初のステップです。それを回避する方法の議論のためのリンクをたどってください。


1
はい、その用語「ラビオリコード」が好きです。DIのマイナス面といえば、もう少し長く表現します。それでも、DIなしでJavaで実際のフレームワークやアプリケーションを開発することは想像できません。
ハワードM.ルイス船

13

自社製のソリューションを使用している場合、依存関係はコンストラクターの目の前にあります。または、多分、見つけるのがそれほど難しくないメソッドパラメータとして。フレームワークは依存関係を管理しますが、極端な場合、魔法のように見え始める可能性があります。

ただし、あまりにも多くのクラスにあまりにも多くの依存関係があることは、クラス構造が台無しになっていることの明らかな兆候です。したがって、依存関係の注入(自社開発またはフレームワーク管理)は、そうでなければ暗闇に潜んでいる可能性のある、目立つデザインの問題を引き出すのに役立ちます。


2つ目のポイントをわかりやすく説明するために、ここではこの記事の抜粋(元のソース)を抜粋します。これは、コンピュータシステムだけでなく、システムを構築する上での根本的な問題であると心から信じています。

大学のキャンパスを設計するとします。設計の一部を学生や教授に委任する必要があります。そうしないと、物理学の建物は物理学者にはうまく機能しません。建築家は、人々が自分ですべてを行うために必要な物理学について十分に知っています。しかし、すべての部屋の設計をその居住者に委任することはできません。それは、瓦礫の巨大な山を得るからです。

全体的な設計の一貫性と調和を維持しながら、大規模な階層のすべてのレベルに設計の責任をどのように配分できますか?これは、アレクサンダーが解決しようとしている建築設計の問題ですが、コンピューターシステム開発の根本的な問題でもあります。

DIはこの問題を解決しますか?いいえ。しかし、すべての部屋を設計する責任をその居住者に委任しようとしているのかどうかを明確に理解するのに役立ちます。


13

私がDIに少し不満を感じる理由の1つは、すべての注入されたオブジェクトはインスタンス化するのに安価であり、副次的影響がないことです。

これが重要になるのは、依存関係が消費クラス内で頻繁に使用されない場合です。などのようなものIExceptionLogHandlerService。明らかに、このようなサービスは(うまくいけば:))クラス内で呼び出されることはめったにありません。おそらく、ログに記録する必要のある例外に対してのみです。しかし、標準的なコンストラクター注入パターン ...

Public Class MyClass
    Private ReadOnly mExLogHandlerService As IExceptionLogHandlerService

    Public Sub New(exLogHandlerService As IExceptionLogHandlerService)
        Me.mExLogHandlerService = exLogHandlerService
    End Sub

     ...
End Class

...このサービスの「ライブ」インスタンスを提供する必要があり、そこに到達するために必要なコスト/副作用を抑制しました。そうではないかもしれませんが、この依存関係インスタンスの構築にサービス/データベースのヒット、構成ファイルの検索、または破棄されるまでリソースのロックが含まれる場合はどうなるでしょうか。このサービスが必要に応じて構築された場合、サービスが配置された場合、または工場で生成された場合(すべてに問題がある)、必要な場合にのみ建設費がかかります。

さて、オブジェクトを構築すること安価で副作用を引き起こさないことが、一般に受け入れられているソフトウェア設計原則です。そしてそれはいい考えですが、いつもそうとは限りません。ただし、典型的なコンストラクター注入を使用すると、基本的にこれが当てはまることが要求されます。依存関係の実装を作成するときは、DIを考慮して設計する必要があります。おそらく、他の場所で利益を得るためにオブジェクト構築をより費用がかかるようにしたかもしれませんが、この実装が注入される場合は、おそらくその設計を再考することを強いられます。

ちなみに、特定の手法では、注入された依存関係の遅延読み込みを許可することで、この正確な問題を軽減できLazy<IService>ます。たとえば、依存関係としてクラスにインスタンスを提供します。これにより、依存オブジェクトのコンストラクターが変更され、オブジェクト構築費用などの実装の詳細がさらに認識されるようになります。これも間違いなく望ましくありません。


1
私はあなたの言っていることは理解していますが、「依存関係の実装を作成するときは、DIを念頭に置いて設計する必要がある」と言うのは公平ではないと思います。インスタンス化のコストと、構築中の副作用または障害モードの欠如に関するベストプラクティスで実装されたクラスで使用する場合に最適です。」最悪の場合、実際のオブジェクトの割り当てを最初に使用するまで延期する遅延プロキシ実装を常に挿入できます。
Jolly Roger、

1
最新のIoCコンテナーでは、特定の抽象型/インターフェイス(常に一意、シングルトン、httpスコープなど)のオブジェクトの有効期間を指定できます。Func <T>またはLazy <T>を使用して遅延的にインスタンス化するファクトリメソッド/デリゲートを提供することもできます。
ドミトリーS.

スポット。依存関係をインスタンス化すると、メモリが不必要に消費されます。私は通常、呼び出されたときにのみクラスをインスタンス化するゲッターで「遅延読み込み」を利用します。パラメータなしのデフォルトのコンストラクタと、インスタンス化された依存関係を受け入れる後続のコンストラクタを提供できます。最初のケースでは、たとえばIErrorLoggerを実装するクラスthis.errorLogger.WriteError(ex)は、try / catchステートメントでエラーが発生したときにのみインスタンス化されます。
ジョンボンファルデシ

12

依存性注入を実際に分離することなく実装するだけでコードを分離したような錯覚。それがDIの最も危険なことだと思います。


11

これは、ちょっとしたテクニックです。しかし、依存性注入の欠点の1つは、開発ツールがコードを推論してナビゲートするのが少し難しくなることです。

具体的には、コード内のメソッド呼び出しでControl-Click / Command-Clickを実行すると、具体的な実装ではなく、インターフェイスのメソッド宣言に移動します。

これは、疎結合コード(インターフェースによって設計されたコード)のマイナス面であり、依存関係注入を使用しない場合(つまり、ファクトリーを使用する場合でも)に当てはまります。しかし、依存性注入の出現は、疎結合されたコードを大衆に本当に奨励するものなので、私はそれについて言及したいと思いました。

また、疎結合コードの利点はこれをはるかに上回ります。そのため、私はそれをnitpickと呼んでいます。私はこれが依存関係注入を導入しようとした場合に得られる可能性のあるプッシュバックの一種であることを知るのに十分な時間をかけて取り組んできましたが

実際、依存関係の注入で見つけられるすべての「マイナス面」について、それをはるかに上回る多くのプラス面が見つかると思います。


5
Ctrl-Shift-Bと
resharper

1
しかし、再び(理想的な世界では)すべての実装が少なくとも2
つない

1
Eclipseでは、Ctrlを押しながらメソッド呼び出しコードにカーソルを合わせると、宣言または実装を開くためのメニューが表示されます。
サムハスラー

インターフェース定義にいる場合は、メソッド名を強調表示してCtrl + Tを押すと、そのメソッドの型階層が表示されます。型階層ツリーにそのメソッドのすべての実装者が表示されます。
予選

10

コンストラクターベースの依存性注入(魔法の「フレームワーク」を使用しない)は、OOコードを構造化するためのクリーンで有益な方法です。私が見た中で最高のコードベースで、Martin Fowlerの他の元同僚と何年もかけて、この方法で記述されたほとんどの優れたクラスが単一のクラスを持つことに気づき始めましたdoSomethingメソッド。

主な欠点は、関数型プログラミングの利点を得るために、クラスとしてクロージャを書くための手に負えない長手なOO方法であることに気づくと、OOコードを書く動機がすぐに消えてしまうことです。


1
コンストラクタベースの通報は、あなたがいつもより多くのコンストラクタ引数を追加する必要がありますということです...
ミゲルPingの

1
はは。やり過ぎると、コードが壊れていることがすぐにわかり、リファクタリングします。その上、ctrl-f6はそれほど難しくありません。
time4tea

そしてもちろんその逆も当てはまります。オブジェクト指向プログラミングの利点を得るために、クラスをクロージャーとして書くための、手に負えない長きに渡る関数的な方法です
CurtainDog

何年も前に、Perlでクロージャーを使用してオブジェクトシステムを構築したので、私はあなたの言っていることを理解していますが、データのカプセル化はOOプログラミングに固有の利点ではないので、OOのこれらの有益な機能が何であるかは明らかではありません関数型言語で取得するために、ずんぐりしていて利き手が長い。
sanityinc 2011

9

コンストラクターインジェクションは大きな醜いコンストラクターにつながる可能性があることを発見しました(そして、コードベース全体でコンストラクターインジェクションを使用しています-おそらくオブジェクトが細かすぎますか?)。また、コンストラクターインジェクションを使用すると、恐ろしい循環依存関係が発生することがあります(これは非常にまれですが)。そのため、より複雑なシステムでは、いくつかのラウンドの依存関係インジェクションを伴う、ある種の準備状態のライフサイクルが必要になる場合があります。

ただし、オブジェクトが構築されると、単体テスト環境にあるのか、IOCコンテナーにロードされているのか、それがどのような状態にあるのか、間違いなくわかるので、セッターインジェクションよりもコンストラクターインジェクションを優先します。これは、回り道のような方法で、私が感じるのはセッター注入の主な欠点だと言っています。

(付記として、私はトピック全体が非常に「宗教的」であると思いますが、あなたのマイレージはあなたの開発チームの技術的熱狂のレベルによって異なります!)


8
醜いコンストラクタが大きい場合、クラスが大きくて依存関係がたくさんあるのではないでしょうか?
Robert

4
それは確かに私が楽しませてくれる可能性です!...残念ながら、ピアレビューを行うことができるチームがいません。バイオリンがバックグラウンドで柔らかく再生され、その後画面がフェードインして黒くなる...
James B

1
マーク・シーマンが悲しいように「それはあなたのキャリアにとって危険である可能性がある」...
ロバート・

私はここで背景ナレーションがとても表情豊かになる手がかりがなかった:P
Anurag

@ロバート私は引用を見つけようとしています、どこで彼はそれを言ったのですか?
liang

8

IOCコンテナーなしでDIを使用している場合、最大の欠点は、コードに実際に依存している依存関係の数と、すべてが実際にどの程度密結合されているかをすばやく確認できることです。(「それでも良いデザインだと思いました!」)自然な進歩は、学習と実装に少し時間がかかる可能性があるIOCコンテナーに移動することです(WPFの学習曲線ほど悪くはありませんが、無料ではありません)どちらか)。最終的なマイナス面は、一部の開発者が善良さのユニットテストを正直に書き始め、それを理解するのに時間がかかることです。以前に何かを半日でクランクアウトできた開発者は、突然、すべての依存関係を模倣する方法を理解するために2日間を費やします。

Mark Seemannの答えと同様に、肝心なのは、コードのビットをまとめてハッキングして、ドア/プロダクションに放り投げるのではなく、より良い開発者になるために時間を費やすことです。あなたのビジネスはどちらを持っているでしょうか?あなただけがそれに答えることができます。


いい視点ね。それは質の悪い/速い配達vs良い品質/遅い配達です。欠点は?DIは魔法ではありません。それが期待されることはマイナス面です。
リャン2013

5

DIは手法またはパターンであり、フレームワークとは関係ありません。依存関係を手動で関連付けることができます。DIはSR(単一の責任)とSoC(懸念の分離)を支援します。DIはより良い設計につながります。私の見解と経験上、欠点はありません。他のパターンと同様に、誤解したり誤用したりする可能性があります(ただし、DIの場合は非常に困難です)。

フレームワークを使用してDIをレガシーアプリケーションに原則として導入する場合-できる最大の間違いは、それをService-Locaterとして誤用することです。DI + Framework自体は素晴らしく、私が見たすべての場所で物事が改善されました。組織の観点から見ると、すべての新しいプロセス、手法、パターンなどに共通の問題があります。

  • あなたはあなたのチームを訓練しなければなりません
  • アプリケーション(リスクを含む)を変更する必要がある

一般に、時間とお金投資する必要があります。それ以外に、マイナス面はありません。


3

コードの可読性。依存関係はXMLファイルに隠されているため、コードフローを簡単に理解することはできません。


9
依存関係の注入にXML構成ファイルを使用する必要はありません。コードでの構成をサポートするDIコンテナーを選択してください。
HåvardS

8
依存性注入は必ずしもXMLファイルを意味するわけではありません。これはまだJavaに当てはまるようですが、.NETではこの結合を数年前に中止しました。
Mark Seemann

6
または、DIコンテナをまったく使用しないでください。
ジェシーミリカン

コードがDIを使用していることがわかっている場合は、依存関係を設定するユーザーを簡単に想定できます。
Bozho

Javaでは、GoogleのGuiceは、たとえばXMLファイルを必要としません。
Epaga

2

2つのこと:

  • 構成が有効であることを確認するには、追加のツールサポートが必要です。

たとえば、IntelliJ(商用版)は、Spring構成の有効性のチェックをサポートしており、構成内の型違反などのエラーにフラグを立てます。そのようなツールのサポートがないと、テストを実行する前に構成が有効かどうかを確認できません。

これが(Scalaコミュニティで知られている)「ケーキ」パターンが良いアイデアである理由の1つです。コンポーネント間の配線はタイプチェッカーでチェックできます。アノテーションやXMLを使用しても、そのメリットはありません。

  • プログラムのグローバルな静的分析が非常に困難になります。

SpringやGuiceのようなフレームワークでは、コンテナによって作成されたオブジェクトグラフがどのように見えるかを静的に決定することが困難になります。コンテナの起動時にオブジェクトグラフを作成しますが、/作成されるオブジェクトグラフを記述する便利なAPIは提供されません。


1
これは絶対的な雄牛です。依存性注入は概念であり、複雑なフレームワークを必要としません。必要なのは新しいものです。スプリングを捨てると、ツールが問題なく機能し、さらにコードをより適切にリファクタリングできるようになります。
time4tea

確かに良い点です。パターンではなく、DIフレームワークの問題について話していることをもっと明確にすべきでした。私が答えたとき、質問の明確化を逃した可能性があります(その時にそこにあったと仮定します)。
マーティンエリス

ああ。その場合、私は喜んで私の煩わしさを撤回します。謝罪。
time4tea

2

静的型付けを回避する手法を常に採用している場合、静的型付け言語の想定される利点は大幅に減少するようです。私がインタビューしたばかりの大きなJavaショップの1つは、ビルドの依存関係を静的コード分析でマッピングすることでした...効果的なものにするために、すべてのSpringファイルを解析する必要がありました。


1

IoCコンテナーは依存関係を適切な方法で解決する必要があるため、アプリの起動時間が長くなる可能性があります。


3
数値を示すために、DIコンテナは1秒あたり数千の依存関係を解決する必要があります。(codinginstinct.com/2008/05/…)DIコンテナでは、インスタンス化を遅延できます。パフォーマンスは(巨大なアプリケーションでも)問題になりません。または、少なくともパフォーマンスの問題は対処可能である必要があり、IoCとそのフレームワークに対して決定を下す理由にはなりません。
Robert
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.