web-dev-qa-db-ja.com

依存関係のツリーである依存関係の注入

依存関係のツリーである依存関係を注入するのはパターンですか、それともアンチパターンですか?

例えば:

_public class ClassExample
{
    private IContainer _container;

    public ClassExample(IContainer container)
    {
        _container = container;
    }
}

public interface IContainer
{
    IDependencyA DependencyA { get; set; }
    IDependencyB DependencyB { get; set; }
    IDependencyC DependencyC { get; set; }
}

public interface IDependencyA
{
}

public interface IDependencyB
{
}

public interface IDependencyC
{
}
_

上記の例はさらに深くすることができます(ツリー)。たとえば、IDependencyAにはさらに多くの依存関係IDependencyAA、IDependencyABなどを含めることができます。

同じサービスのセットを挿入する必要がある複数の場所がある場合、誰かが上記の方法を使用してコードの重複を最小限に抑えることができます。コードは次のようになります。多くの場合、container.DependencyA.DependencyAA.Method(...)のほうが冗長であり、DRYが少なくなります。

上記の方法を使用することは良いアイデアですか、悪いアイデアですか(パターン/アンチパターン)?または、いつそれが良いアイデアであり、いつそれが悪いアイデアですか?

container.DependencyA.DependencyAA.Method(...)

デメテルの法則 違反のようです。問題は依存関係とは何の関係もありません。

問題は、過去のオブジェクトに到達し、それらの抽象化に違反しています。これは問題です。クライアントが1つでもcontainer.DependencyA.DependencyAA.Method()のようなコードを書いた場合、チェーン全体が固定されてしまうからです。他の方法で構築する自由はありません。クライアントがそれをdepAA.Method()と呼んでいた場合は、ある程度の柔軟性があります。

だからといって、ドットのチェーンが見たくないということではありません。結局のところ デメテルの法則はドットカウントの練習ではありません 。パスが常に当てはまることが約束されている場合、長いドットチェーンは問題ありません。たとえば、Java8ストリームでは、驚くほど長いチェーンが点在しています。これらのチェーンが想定されているため、問題ありません。あなたは彼らが変わらないと約束されました。

問題は、クライアントの作成者がコードベースを掘り下げ、機能するすべてのパスをつなぎ合わせるときです。現在、この注意深く分離されたコードベースは泥の玉のように結びついています。誰かに手渡されるのではなく、必要なものに手を伸ばし続けているからです。

アイデアは、話し合う方法を知っている友人が数人いる方が、オブジェクトごとに優れているということです。それらの友人は彼らが話す方法を知っている友人を持っています。すぐに友達の友達と話す場合は、みんなと話す方法を知っている必要があります。変更を実装できるようにしたい場合は、すべてが変更の影響を受けるため、これは悪いことです。あまり知らない価値。

ファサード、抽象化、および依存性注入を使用して、クライアントがオブジェクトグラフがどのように配線されているかを認識しないようにし、必要に応じて自由に配線できるようにします。

チェーンを許可する必要がある場合は、その下の実装からチェーンを切り離してください。これらは、内部ドメイン固有言語(iDSL)と呼ばれます。それらは非常に強力ですが、セットアップには多くの作業が必要です。許可されたチェーンはミニ言語を形成します。チェーンの背後にある実装を交換できることを確認してください。

9
candied_orange

以下の条件を満たしていれば問題ありません。

  1. 渡された依存関係のセットは単純なコンテナであり、
  2. and依存関係のコレクションは純粋に一緒に属し、
  3. andコレクションのメンバーは、(ほとんど)コレクションが注入されるクラスの実際の依存関係です。

最小知識の原則(より不可解にデメテルの法則として知られている)に惑わされないでください。クラスがその依存関係を知ることは完全に適切であり、あなたが話していることはそれらの依存関係を提供する方法ですクラスの内部について恥ずかしがり屋であるはずの別個の機能的構造ではありません。これが上記の最初のガイドラインに関するものです。依存関係のセットは単に依存関係のセットでなければなりません。注入されたクラスが独自の独立した状態と動作を持っていると、渡された依存関係のセットはその実装の一部になりますクラスと分離の明瞭さが失われます。

ただし、便宜上一緒にパッケージ化すると、すぐに肥大化したモノリスになり、セットに含まれる多くのクラスへのアクセスを受信するビジネスを持たない多くの依存関係を迂回することにより、クラスがお互いの内部ですべてを実現できるようになります。そして、どの依存関係が注入されるかを考えなくても済むようにする手段です。結局のところ、そうするつもりなら、依存関係をシングルトンセットにして、それで処理を完了させることもできます。それは事実上、同じことをするのに不格好な方法になります。これが上記のルールの2番目と3番目のルールです。一緒にパッケージ化された依存関係は、単に渡すのが簡単なものの束ではなく、自然なつながりを持つ必要があります。これにより、渡されたセット自体が意味を持ちます。また、セットを受け取るオブジェクトのほとんどが、セット内のほとんどの項目をほとんどの時間使用していることを確認する必要があります。そうでない場合は、依存関係を挿入せず、一般的なプログラム状態へのアクセスを提供します。

1
Jack Aidley