web-dev-qa-db-ja.com

IOCクラスがプロジェクトを汚染しています

レイヤー化されたC#アプリがあるとします。他のレイヤーとは独立してドメインレイヤーをテストしたい。したがって、私は3つのクラスを持つドメインレイヤープロジェクトを作成しました。 Person、Order、OrderItem(架空)。

私はInversion of Control(Castle Windosr)を使用したので、他のクラスもすべてロードしました。

PersonFactory
OrderFactory
OrderItemFactory
IPersonFactory
IOrderFactory
IOrderItemFactory
etc

私のVisual Studioプロジェクトは、これらのクラスで「汚染されている」ように見えます。これらのクラスで何ができますか? Factoriesというフォルダを作成することを考えました。プロジェクトを「汚染」するこれらのクラスで何をしますか?

4
w0051977

IoCは非常に良いことです。しかし、彼らが作るものと厳密に1対1の関係にある工場は、それほどうまくいっていません。

工場は何かのために何かを作る必要があります。それらは、コンストラクターの頭の悪い代替物であってはなりません。それらは常にデフォルト値を常に強制することなく、適切なデフォルト値を許可する必要があります。

あなたは自分の行動を構築から切り離しておくべきです。これは、すべての構成をxmlドキュメントで維持する必要があることを意味しません。

とにかく、建設のすべてが工場にある必要はありません。創造的なパターンには多くの種類があります。また、メインで必要なものだけを構築するのが最善の場合もあります。

IoCコンテナを隅に入れないでください。あなたの考えがそうだったとしたら:Personオブジェクトが必要なので、PersonFactoryが必要です。あなたは自分で作った地獄に住んでいます。

6
candied_orange

CandiedOrangeとはかなり異なるタックを使います。その前に、私はいくつかの他の潜在的な問題を検討したいと思います。あなたの状況に当てはまるかどうかはわかりませんが、すべての拠点をカバーしたいと思います。

まず、すべてを注入する必要はありません。依存関係のないもの(概念的に)、特に値オブジェクトとデータ転送オブジェクト(DTO)は、StringFactoryを注入するために依存関係注入を使用しないのと同じように注入する必要はありません。第二に、クラスのコンストラクターが依存関係を除いてパラメーター化されていない場合、ファクトリーは必要ありません。第3に、依存関係が多すぎるため、コードを再構築する必要がある場合があります。たとえば、DTOが依存関係を取得してそれ自体を保存する必要がある場合、その動作をDTOから移動して、依存関係を必要としないようにする必要があるかもしれません。 4番目に、他の人が述べたように、DIフレームワークの型に物事を適合させようとする罠に陥る可能性があります。作成したコードをmain /「コンポジションルート」の依存関係解決プロセスの一部で処理する方が簡単な場合もあります。

それでも、上記のいずれの状況にも当てはまらない場合でも、状況に容易に気づくことができます。類推ではなく、正確にが何であるかの類推を考えてみます。 LINQで追加された操作を使用して次の式があるとします( "linq example"をグーグルして、トップリンクの1つを選択し、ランダムに選択した後、 here から取得しました。このサイトの例から):

customers.SelectMany((cust, custIndex) =>
    orders.Where(o => cust.Field("CustomerID") == o.Field("CustomerID"))
          .Select(o => new { CustomerIndex = custIndex + 1, OrderID = o.Field("OrderID") }));

それが何をするかは重要ではありません。重要なのは、3つのラムダ関数です。 C#1.0の場合と同様に、ストラテジーパターンを使用して各ラムダのクラスを作成する必要があると想像してください。それは卑猥であり、あなたはそれをしません。そして、あなたがそれを強制された範囲で、それは間違いなくあなたのプロジェクトを「汚染」するでしょう。 Factoryパターンは、オブジェクトの作成に適用される戦略パターンです。実際、たとえば、PersonコンストラクタをFunc<Dependencies, Parameters, Person>と考えると、基本的なPersonFactoryは、これをカリー化することで得られるもの、つまりFunc<Dependencies, Func<Parameters, Person>>Personsを作成する必要があるクラスで実際に必要なのはFunc<Parameters, Person>の部分であり、依存関係を処理するために依存関係の注入が必要です。

依存関係注入フレームワークをまったく使用しておらず、メイン/コンポジションルートで依存関係を手動で配線しただけの場合、Func<Parameters, Person>(またはFunc<Parameters, IPerson>)に依存し、単に配線中の適切なラムダ関数。ただし、多くのDIフレームワークはこれを困難または不可能にします。その結果、この目的のために、C#1.0の状況に戻ることができます。 (これが私が個人的にDIフレームワーク[DI自体と混同しないでください]、特に構成ファイル主導のフレームワーク)にそれほど熱心でない理由の1つです。)

上記の直感を使用して多くのファクトリークラスを排除できる可能性がありますが、これはおそらくDIフレームワークに収まるように複雑になり、その価値はありません。ディレクトリの汚染、名前空間の汚染、Intellisenseの汚染など、実際に懸念している「汚染」は明確ではありませんでしたか。後者の2つについては、C#の名前空間メカニズムで適切に処理できます。前者の場合、ディレクトリは適切なソリューションです。どのアプローチが最も意味があるかは、使用しているディレクトリ構造によって異なります。たとえば、各「エンティティ」/「サービス」に独自のディレクトリがある場合、実際には問題はありません。 「Entities」フォルダがある場合は、ファクトリインタフェース用のサブフォルダを用意し、おそらく、ファクトリ実装の一部またはすべてを使用するのが妥当と思われます。