web-dev-qa-db-ja.com

Dependency InjectionをFactoryパターンと組み合わせて使用​​する方法

特定のタイプのファイルの解析を担当するモジュールについて考えてみます。 ここ ですでに説明したように、この問題に取り組むために戦略パターンを使用することを考えています。この質問に進む前に、リンクされた投稿を参照してください。

Product.xmlファイルのコンテンツを必要とするクラスBを検討してください。このクラスは、XMLファイルを解析するために、Parserインターフェースの適切な具象インプリメンターをインスタンス化する必要があります。適切な具象実装者のインスタンス化をファクトリーに委任して、クラスBが「has-a」ファクトリーになるようにすることができます。ただし、クラスBは、具象実装者をインスタンス化するためにファクトリに「依存」します。つまり、クラスBのコンストラクターまたはセッターメソッドには、ファクトリーを渡す必要があります。

したがって、ファイルを解析する必要があるファクトリとクラスBは、互いに密接に結合されます。私がこれまでに説明したことすべてについて完全に間違っている可能性があることを理解しています。依存関係が注入されるシナリオがファクトリーであるシナリオで依存関係注入を使用できるかどうか、およびこれを実装してユニットテストでファクトリーをモックするなどの領域を活用できるようにするための正しい方法は何ですか?.

10
CKing

これを行う正しい方法は、インターフェイスに依存し、そのインターフェイスの実装をクラスBに挿入することです。

インターフェースとは、信頼できる最も薄いもののことです-私はそれをほんの少しの煙を掴もうとするようなものです。コードはsomethingに結合する必要があります。そうしないと何も実行されませんが、インターフェースへの結合は可能な限り分離されていますが、インターフェースは必要なすべての機能を提供できます。

したがって、クラスBのコンストラクターが必要なクラスへのインターフェースを取り、ファクトリーがインターフェースの実装者としてそのクラスを生成するようにします。ファクトリに依存せず、インターフェースに依存し、ファクトリにそのファクトリの実装を提供させる。

つまり、依存関係注入を使用することになりますが、何も問題はありません。依存関係の注入(特に単純なコンストラクターの注入)は、「通常の」方法で行う必要があります。アプリ内の新しいもの(そしてmainの最初の行のできるだけ近く)を単純に延期し、新しいものを、ものを作成するために特別に設計されたクラスで非表示にします。

結論:依存関係を挿入することをためらわないでください。それが通常のやり方です。

8
Nick Hodges

ここであなたの前提は少し混乱していると思いますが、ファクトリを注入することについて話しますが、ファクトリパターンは、DIフレームワークが普及していないときに依存関係注入フレームワークが行うことのサブセットを実行することを目的とした作成パターンですそのため便利です。ただし、DIフレームワークを使用している場合、ファクトリーが達成するであろう目的をDIフレームワークが満たすことができるため、ファクトリーはもはや必要ありません。

とはいえ、依存性注入と、それを一般的にどのように使用するかについて少し説明しましょう。

依存関係の注入にはさまざまな方法がありますが、最も一般的なのは、コンストラクターの注入、プロパティの注入、および直接DIContainerです。ほとんどの場合、プロパティインジェクションは間違ったアプローチ(時として正しいアプローチ)であり、他のアプローチのいずれかを絶対に実行できない場合を除いて、DIContainerアクセス​​は好ましくないため、コンストラクターインジェクションについて説明します。

コンストラクターインジェクションでは、依存関係のインターフェイスと、その依存関係の具体的な実装を知っているDIContainer(またはファクトリ)があり、そのインターフェイスに依存するオブジェクトが必要な場合はいつでも、構築時にファクトリから実装を渡します。それ。

つまり.

IDbConnectionProvider connProvider = DIContainer.Get<IDbConnectionProvider>();
IUserRepository userRepo = new UserRepository(connProvider);
User currentUser = userRepo.GetCurrentUser();

多くのDIフレームワークは、DIContainerが具体的な実装を知っているUserRepositoryのコンストラクターを検査し、それらを自動的にユーザーに渡すところまで、これを大幅に簡略化できます。この手法はしばしばInversion of Controlと呼ばれますが、DIとIoCはどちらも多く交換される用語であり、あいまいな(ある場合)違いがあります。

包括的なコードがどのようにDIContainerにアクセスするのか疑問に思っている場合は、それにアクセスするための静的クラスを用意するか、ほとんどのDIフレームワークでDIContainerを新規作成して、実際には次のように動作するようにすることができます。与えられたインターフェースに対して具体的であるとわかっている型の内部シングルトン辞書へのラッパー。

つまり、コード内の任意の場所にDIContainerを新しく追加し、インターフェイスとコンクリートの関係を認識するように構成済みの同じDIContainerを効果的に取得できます。 DIContainerを直接操作してはならないコードの一部から隠す通常の方法は、必要なプロジェクトのみがDIフレームワークへの参照を持つようにすることです。

9
Jimmy Hoffa

他のものを渡すのと同じように、依存性注入を介してファクトリを渡すことができます。状況の再帰性に混乱させないでください。私はそれを実装することについて他に何を言うべきかわかりません-あなたはすでに依存性注入を行う方法を知っています。

私は工場をかなり定期的に注入するためにDIを使用しています。

5
psr

工場への注入に問題はありません。 「親」オブジェクトのビルド中にどのような依存関係が必要になるかを決定できない場合、これは標準的な方法です。例がそれを最もよく説明すると思います。 Javaがわからないのでc#を使用します。


class Parent
{
    private IParserFactory parserFactory;
    public Parent(IParserFactory factory)
    {
        parserFactory = factory
    }

    public ParsedObject ParseFrom(string filename, FileType fileType)
    {
        var parser = parserFactory.CreateFor(fileType);
        return parser.Parse(filename);
    }
}
4
Piotr Perak