web-dev-qa-db-ja.com

コンストラクタパラメータではなくメソッドパラメータとして依存関係を注入する

コンストラクターに依存関係を挿入できないORMを使用しています。ビジネスロジックにDDDを使用し、UIにMVCパターンを使用しているとします。

ここで、私のドメインオブジェクトの1つが外部サービスにアクセスする必要があります。私はサービスロケーターのアンチパターン(10フィートのポールで触れないだろう)に非常に反対していますが、それを見ると、次のことがわかります。

class Controller
{
    private readonly IExternalService _externalService;

    public Controller(IExternalService externalService)
    {
        _externalService = externalService;
    }

    public ViewResult Action(Guid Id)
    {
        // Omitted repository access for brevity.
        domainObject.DoSomethingWichNeedsAnExternalService(_externalService);
    }
}

どういうわけか、これはあまりクリーンではないという感じがします。「domainObject」がモデル/グラフの奥深くに埋め込まれている場合、「_ externalService」はずっと下に渡されるべきですか?

ベストプラクティスの代替策はありますか?

7
dvdvorle

手に負えなくなるようです。たとえば、テスト中のユニットにIRealTimeClockServiceを使用して注入する必要があったため、システム時間に依存するものについて繰り返し可能なテスト結果を得ることができました。これは、DateTime.Nowを呼び出すだけのサービスにとっては非常に重要なようです。ただし、基本クラスのコンストラクターにもコードを渡さなければならない場合でも、コードが読みにくくなることはありません。

依存関係が何であるかが明らかであるため、いくつかの点でより優れています。

オブジェクトに多くの依存関係が注入されている場合、それは単一責任の原則に違反していることを意味し、そのクラスは2つの無関係なことを行うものに分割される可能性があります。

一方、複雑なシステムを使用している場合は、多数の依存関係を持つ複雑なオブジェクトが存在します。私はそれについて明示するほうがいいと思います。

考慮すべきこと:クラスAが5つの依存関係を取り、それらに触れずにそれらの4つをヘルパーオブジェクトに渡す場合、おそらくこれら4つをヘルパーオブジェクト(またはインターフェイス)。

3
Scott Whitlock

私がやったことは、他のすべてのインスタンスを作成してそれらをワイヤリングするファクトリークラスを作成することです。次に、コンストラクターを介して依存オブジェクトを渡す必要はありません。ファクトリーに置換インスタンスを提供し、それ以外のものをすべてビルドさせます。

1
Jeff Grigg

ORM APIをオプションでラップしないので、ラッパーのコンストラクターに何でも渡すことができますか?

一般に、外部APIを扱う場合、そうすることは悪い考えではありません。さらに、あなたはORMとの結びつきが少なくなります。これは将来的には素晴らしいかもしれません。

1