依存性注入とファクトリパターン


498

Dependency Injectionの使用法として引用されている例のほとんどは、ファクトリーパターンを使用して解決することもできます。依存関係の注入とファクトリーの違いは、使用法/設計に関してはぼやけている、または薄いようです。

誰かが私にあなたがそれをどのように使うかが違いをもたらすと私に言ったら!

私はかつて、StructureMapのDIコンテナを使用して問題を解決しました。その後、シンプルなファクトリで機能するように再設計し、StructureMapへの参照を削除しました。

それらの違いと何をどこで使用するのか、ここでのベストプラクティスは何ですか?


21
これら2つのアプローチは互いに補完できません。依存関係注入を使用してファクトリクラスを注入しますか?
Richard Ev

20
この質問にコードが含まれている答えがあれば、本当に素晴らしいでしょう!DIが作成のためのファクトリを使用することとどのように有益/異なるのかまだわかりませんか?作成されるobj / implementationを変更するには、ファクトリクラスのその1行だけを置き換える必要がありますか?
ギデオン2010

2
@gideonは、アプリ、または少なくともファクトリクラスを含むモジュールをコンパイルすることを強制しませんか?
リゼルグ酸

1
@liortalうんそうです。そのコメント以来、DIについて長い研究をしてきましたが、DIはファクトリーメソッドを一歩先に進めていることを理解しています。
ギデオン2012

1
この素晴らしい答えをチェックしてください:stackoverflow.com/questions/4985455/…-彼はそれを非常によく言い、コードサンプルを提供しています。
Luis Perez 2012

回答:


293

ファクトリを使用する場合、コードは実際にはオブジェクトの作成を担当します。DIによって、その責任を、コードとは別の別のクラスまたはフレームワークに外部委託します。


172
DIパターンはフレームワークを必要としません。DIを行うファクトリを手動で記述することで、DIを行うことができます。DIフレームワークはそれをより簡単にします。
Esko Luontola、2009

28
@Perpetualcoder-ありがとう@Esko-一部の高度なサードパーティライブラリを意味するフレームワークという言葉にとらわれないでください。
willcodejavaforfood 2009

4
+1 @willcodeありがとう!そのため、代わりにconfig / xmlファイルを変更する必要があります。そうですか。wikiリンクen.wikipedia.org/wiki/…として、工場のパターンを定義するManually-Injected Dependency
ギデオン

5
XMLの1行を変更する場合と、コードを1行変更する場合の利点はありません。詳しく説明してもらえますか?
Rafael Eyng 2015年

1
"DI"を "factory"に置き換えるOPの回答を繰り返しますが、それでも意味があります。
エドソンメディナ

219

概念をわかりやすくシンプルに保つことをお勧めします。Dependency Injectionは、ソフトウェアコンポーネントを疎結合するためのアーキテクチャパターンです。ファクトリパターンは、他のクラスのオブジェクトを作成する責任を別のエンティティに分離する1つの方法にすぎません。ファクトリパターンは、DIを実装するツールとして呼び出すことができます。依存性注入は、コンストラクターを使用したDI、マッピングxmlファイルの使用など、さまざまな方法で実装できます。


4
ファクトリパターンは、依存性注入を実装する方法の1つであることは事実です。ファクトリパターンに対する依存性注入を使用するもう1つの利点は、DIフレームワークによって、具象型に対して抽象化を登録する方法に柔軟性がもたらされることです。構成コード、XML、自動構成などのコード。その柔軟性により、オブジェクトの寿命を管理したり、インターフェースを登録する方法とタイミングを決定したりできます。
Teoman Shipahi 2014年

1
ファクトリパターンは、DIよりも高いレベルの抽象化を提供します。ファクトリはDIと同じように構成オプションを提供できますが、構成の詳細をすべて非表示にすることもできるため、クライアントに気付かれずに完全に異なる実装に切り替えることができます。DI自体はこれを許可しません。DIでは、クライアントが希望する変更を指定する必要があります。
ニューロン

1
いい答えだ。多くの人がその質問を混乱させています。「どのパターンを選択すればよいですか?」実際、設計パターンは、適切な状況で問題を解決するための方法にすぎません。使用するデザインパターンがわからない場合、または「パターンをどこに実装すればよいですか?」現時点では必要ありません。
Benyi

2
Factory PatternはIoC(DIではない)を実装するためのツールであると言う方がより正確だと思います。DIはIoCの形式で
Hooman Bahreini、2018年

185

依存性注入

パーツ自体をインスタンス化する代わりに、自動車機能するために必要なパーツを要求します。

class Car
{
    private Engine engine;
    private SteeringWheel wheel;
    private Tires tires;

    public Car(Engine engine, SteeringWheel wheel, Tires tires)
    {
        this.engine = engine;
        this.wheel = wheel;
        this.tires = tires;
    }
}

工場

ピースを組み合わせて完全なオブジェクトを作成し、具体的なタイプを呼び出し元から隠します。

static class CarFactory
{
    public ICar BuildCar()
    {
        Engine engine = new Engine();
        SteeringWheel steeringWheel = new SteeringWheel();
        Tires tires = new Tires();
        ICar car = new RaceCar(engine, steeringWheel, tires);
        return car;
    }   
}

結果

ご覧のとおり、工場とDIは互いに補完し合っています。

static void Main()
{
     ICar car = CarFactory.BuildCar();
     // use car
}

ゴルディロックと三匹のクマを覚えていますか?まあ、依存性注入はそのようなものです。同じことを行う3つの方法を次に示します。

void RaceCar() // example #1
{
    ICar car = CarFactory.BuildCar();
    car.Race();
}

void RaceCar(ICarFactory carFactory) // example #2
{
    ICar car = carFactory.BuildCar();
    car.Race();
}

void RaceCar(ICar car) // example #3
{
    car.Race();
}

例#1-依存関係を完全に隠すため、これは最悪です。この方法をブラックボックスとして見ると、それが車を必要とすることはわかりません。

例2-これは少し良いです。なぜなら、自動車工場に通ったので、車が必要だということがわかったからです。ただし、実際に必要なメソッドはすべて自動車であるので、今回は通過しすぎています。メソッドの外で車を組み立てて渡すことができる場合は、車を組み立てるためだけに工場を通過します。

例3-メソッドが正確に要求するため、これは理想的です必要なものです。多すぎても少なすぎてもいけません。MockCarsを作成するためだけにMockCarFactoryを記述する必要はありません。モックを直接渡すことができます。これは直接であり、インターフェースはありません。

Misko HeveryによるこのGoogleテックトークは素晴らしく、私が私の例を導き出した基礎となっています。http://www.youtube.com/watch?v=XcT4yYu_TTs


1
ファクトリパターンはDIとして挿入されます。
Mangesh Pimpalkar 14

7
@PhilGoetzあなたが説明しているものは、Service Locatorパターンに似ています。彼らは、サービスを消費者から切り離すことを目的としているという点で、同様の目標を持っています。ただし、Service Locatorパターンには多くの欠点があります。主に、依存関係を隠すことは良いことではありません。消費者は依然として依存関係を取得する必要がありますが、明確なインターフェースを定義する代わりに、それらは「密かに」渡され、グローバルな状態に依存します。この例では、消費者はファクトリーについて何も知りません。必要なものを尋ねるだけで、そのニーズがどのように構築されているかを気にする必要はありません。
デスパタール2015年

1
@MatthewWhitedほとんどの設計決定にはトレードオフがあります。DIを使用すると、柔軟性、透明性、およびテストしやすいシステムを得ることができますが、根性を露呈することになります。多くの人がこれは許容できるトレードオフだと思っています。これは、DIが常に最良のソリューションであると言っているのではなく、この質問はそれについてではありません。この例は、DIとファクトリパターンの違いを示すことを目的としており、それぞれの良い使い方と悪い使い方を示しています。
デスパタール、2015

3
これはDIパターンではなく、単なるIoCの実装です。DIはServiceLocatorを使用して適切な依存関係を決定し、それをオブジェクトの作成中にコンストラクターに注入します。コードは、オブジェクトの作成をクラススコープから分離するだけです。
ディエゴメンデス

3
@DiegoMendesあなたが説明しているのは、DIを自動化するフレームワークです。呼び出すServiceLocatorは、DIを実行します。私が示しているのは、凝ったフレームワークを必要としないパターン自体です。stackoverflow.com/a/140655/1160036を参照するか、en.wikipedia.org / wiki /…を参照してください 。「[フレームワークのリスト]依存性注入をサポートしていますが、依存性注入を実行する必要はありません」。また、「インジェクションは依存関係を依存オブジェクトに渡すことです」。あなたは美しくシンプルなコンセプトを複雑にしています。
Despertar 2016

50

依存性注入(DI)とファクトリパターンが似ている理由は、ソフトウェアアーキテクチャである制御の反転(IoC)の2つの実装であるためです。簡単に言えば、それらは同じ問題に対する2つの解決策です。

したがって、質問に答えるために、FactoryパターンとDIの主な違いは、オブジェクト参照を取得する方法です。名前としての依存性注入では、参照が注入されるか、コードに与えられます。Factoryパターンでは、コードが参照を要求する必要があるため、コードはオブジェクトをフェッチします。どちらの実装でも、コードと、コードで使用されているオブジェクト参照の基になるクラスまたは型との間のリンケージが削除または分離されます。

注目に値するのは、実行時に要求されるオブジェクトのタイプまたはクラスを動的に選択またはリンクするために、ファクトリーパターン(または実際にはオブジェクト参照を返す新しいファクトリーを返すファクトリーである抽象ファクトリーパターン)を作成できることです。これにより、IoCの別の実装であるService Locatorパターンと非常によく似ています(DIよりもさらに)。

Factoryのデザインパターンは(ソフトウェアの観点から)かなり古く、しばらくの間使用されています。建築パターンIoCの最近の人気以来、復活しています。

IoCの設計パターンとなると、インジェクターが注入され、ロケーターが配置され、ファクトリーがリファクタリングされたと思います。


3
これが最良の答えです...他の答えはIoCについて触れていないか、DIがIoCの形式であることを認識していません。
Hooman Bahreini、2018年

おかげで、私が最初にIOCを研究したとき、これは工場パターンの単なる別の形態であるとほぼ叫びました。それらは互いに非常に似ていることが
Harvey Lin

40

一連のファクトリーではそれほど簡単に解決できない、依存性注入で簡単に解決できる問題があります。

一方では、制御と依存性注入(IOC / DI)の反転と、他方では、サービスロケータまたは一連のファクトリ(ファクトリ)との違いの一部は次のとおりです。

IOC / DIは、ドメインオブジェクトとサービス自体の完全なエコシステムです。指定した方法ですべてを設定します。あなたのドメイン・オブジェクトおよびサービスは、コンテナによって構築され、そして自分自身を構築していない:彼らはので、持っていない任意のコンテナ上またはいずれかの工場に依存し。IOC / DIは非常に高度な構成可能性を可能にし、すべての構成はアプリケーションの最上位層(GUI、Webフロントエンド)の単一の場所(コンテナーの構成)で行います。

Factoryは、ドメインオブジェクトとサービスの構築の一部を抽象化します。しかし、ドメインオブジェクトとサービスは、それ自体を構築する方法と、依存するすべてのものを取得する方法を理解する責任があります。これらすべての「アクティブな」依存関係は、アプリケーションのすべてのレイヤーを介してフィルタリングします。すべてを構成するための単一の場所はありません。


26

DIの1つの欠点は、ロジックでオブジェクトを初期化できないことです。たとえば、ランダムな名前と年齢を持つキャラクターを作成する必要がある場合、DIはファクトリーパターンよりも選択しません。工場では、オブジェクトの作成からランダムアルゴリズムを簡単にカプセル化できます。これは、「変化するものをカプセル化」と呼ばれる設計パターンの1つをサポートします。


22

ライフサイクル管理は、インスタンス化と注入に加えて、依存関係コンテナーが想定する責任の1つです。コンテナがインスタンス化後もコンポーネントへの参照を保持することがあるという事実は、ファクトリではなく「コンテナ」と呼ばれる理由です。依存関係注入コンテナーは、通常、ライフサイクルを管理するために必要なオブジェクト、またはシングルトンやフライウェイトなどの将来の注入に再利用されるオブジェクトへの参照のみを保持します。コンテナーへの呼び出しごとにいくつかのコンポーネントの新しいインスタンスを作成するように構成されている場合、コンテナーは通常、作成されたオブジェクトを忘れます。

送信元http : //tutorials.jenkov.com/dependency-injection/dependency-injection-containers.html


15

DIは工場の抽象化レイヤーの一種だと思いますが、抽象化以外のメリットも提供します。真のファクトリーは、単一のタイプをインスタンス化して構成する方法を知っています。優れたDIレイヤーは、構成を通じて、多くのタイプをインスタンス化および構成する機能を提供します。

明らかに、構築に比較的安定したビジネスロジックを必要とする単純なタイプがいくつかあるプロジェクトの場合、ファクトリパターンは理解、実装、および機能が簡単です。

OTOH、実装が頻繁に変更されることが予想される多数のタイプを含むプロジェクトがある場合、DIは、その構成を通じて、実行時にファクトリを再コンパイルせずにこれを行う柔軟性を提供します。


14

理論

考慮すべき重要な点が2つあります。

  1. 誰がオブジェクトを作成するか

    • [Factory]:HOWオブジェクトを作成する必要があります。作成ロジックを含む別個のFactoryクラスがあります。
    • [依存性注入]:実際のケースでは、外部フレームワークによって行われます(たとえば、Javaでは、spring / ejb / guiceになります)。新しいオブジェクトを明示的に作成することなく、注入が「魔法のように」行われる
  2. それが管理するオブジェクトの種類:

    • [ファクトリ]:通常、ステートフルオブジェクトの作成を担当します
    • [依存性注入]ステートレスオブジェクトを作成する可能性が高い

単一プロジェクトでファクトリと依存関係の注入の両方を使用する実際的な例

  1. 作りたいもの

オーダーラインと呼ばれる複数のエントリを含む注文を作成するためのアプリケーションモジュール。

  1. 建築

次のレイヤーアーキテクチャを作成するとします。

ここに画像の説明を入力してください

ドメインオブジェクトは、データベース内に格納されているオブジェクトである場合があります。リポジトリ(DAO)は、データベースからオブジェクトを取得するのに役立ちます。サービスは他のモジュールにAPIを提供します。orderモジュールでの操作に対応

  1. ドメイン層とファクトリーの使用

データベースに含まれるエンティティは、OrderとOrderLineです。Orderは複数のOrderLineを持つことができます。 OrderとOrderLineの関係

ここで重要な設計部分が来ます。これ以外のモジュールは、独自にOrderLineを作成および管理する必要がありますか?いいえ。オーダーラインは、オーダーが関連付けられている場合にのみ存在します。内部実装を外部クラスに隠すことができれば最適です。

しかし、どのようにOrderLineに関する知識なしにOrderを作成するのでしょうか?

工場

新しい注文を作成したい人は、OrderFactoryを使用しました(注文を作成する方法に関する詳細を非表示にします)。

ここに画像の説明を入力してください

それがIDE内でどのように見えるかです。domainパッケージ外部のクラスOrderFactoryは内部のコンストラクタの代わりに使用しますOrder

  1. 依存性注入依存性注入は、リポジトリやサービスなどのステートレスレイヤーでより一般的に使用されます。

OrderRepositoryとOrderServiceは、依存関係注入フレームワークによって管理されます。リポジトリは、データベースでのCRUD操作の管理を担当します。サービスはリポジトリを挿入し、それを使用して正しいドメインクラスを保存/検索します。

ここに画像の説明を入力してください


これを明確にしていただけますか?[Factory]: Usually responsible for creation of stateful objects [Dependency Injections] More likely to create stateless objects理由がわかりません
マクシムドミトリエフ2017年

2
ステートフルオブジェクトは、データをデータベースにマップするアプリケーションのドメインレイヤーにある可能性があります。データベースでは通常、依存関係の注入は使用しません。ファクトリは、複雑なオブジェクトのツリーからAggregateRootを作成するためによく使用されます
Marcin Szymczak

12

この質問が古いことは知っていますが、5セント追加したいと思います。

依存性注入(DI)は、構成可能なファクトリパターン(FP)のような多くの点で、その意味で、DIで実行できることなら何でも、そのようなファクトリで実行できると思います。

実際、たとえばSpringを使用している場合は、リソース(DI)を自動配線するか、次のようなオプションを選択できます。

MyBean mb = ctx.getBean("myBean");

そして、その「mb」インスタンスを使用して何でも行います。インスタンスを返すファクトリへの呼び出しではないですか?

ほとんどのFPの例の間で私が気づく唯一の本当の違いは、「myBean」がxmlまたは別のクラスにあるように構成でき、フレームワークがファクトリーとして機能することですが、それ以外は同じことです。確かに、必要に応じて、構成ファイルを読み取るか、実装を取得するファクトリーを持つことができます。

そして、あなたが私の意見を求めたら(そして私はあなたがそうしなかったことを知っています)、DIは同じことをするが、開発をより複雑にするだけだと思います。

1つには、DIで自動配線するBeanで使用されている実装を知るには、構成自体に移動する必要があります。

しかし...あなたが使用しているオブジェクトの実装を知る必要がないという約束はどうですか?PFFT!真剣に?このようなアプローチを使用すると...実装を書くのと同じではありませんか?そうでない場合でも、ほとんどの場合、実装が想定されていることを実装がどのように実行するかを確認する必要はありませんか?

最後に、DIフレームワークが、クラスに依存せずに、DIフレームワークから切り離されたものをビルドすることをどれだけ約束するかは問題ではありません。フレームワークを使用している場合は、フレームワーク全体をビルドする必要があります。アプローチやフレームワークを変更するのは簡単なことではありません... ...しかし、あなたはあなたのビジネスに最適なソリューションを心配するのではなく、その特定のフレームワークの周りにすべてを構築するので、それを行うと、二の問題に直面するでしょう。

実際、FPまたはDIアプローチで実際に見られる唯一のビジネスアプリケーションは、実行時に使用される実装を変更する必要があるかどうかですが、少なくとも、私が知っているフレームワークではそれができないため、そのままにしておく必要があります。開発時の構成ですべてが完璧であり、別のアプローチを使用する必要がある場合。

したがって、同じアプリケーションの2つのスコープ(たとえば、持ち株会社の2つの会社)で異なる動作をするクラスがある場合、2つの異なるBeanを作成するようにフレームワークを構成し、それぞれを使用するようにコードを調整する必要があります。それは私がこのようなものを書くのと同じではありません:

MyBean mb = MyBeanForEntreprise1(); //In the classes of the first enterprise
MyBean mb = MyBeanForEntreprise2(); //In the classes of the second enterprise

これと同じ:

@Autowired MyBean mbForEnterprise1; //In the classes of the first enterprise
@Autowired MyBean mbForEnterprise2; //In the classes of the second enterprise

この:

MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise1"); //In the classes of the first enterprise
MyBean mb = (MyBean)MyFactory.get("myBeanForEntreprise2"); //In the classes of the second enterprise

いずれの場合も、クラスまたは構成ファイルに関係なく、アプリケーションの何かを変更する必要がありますが、再デプロイしてそれを再デプロイする必要があります。

このようなことをするのはいいことではないでしょうか:

MyBean mb = (MyBean)MyFactory.get("mb"); 

そして、そのようにして、ログに記録されたユーザーのエンタープライズに応じて、実行時に適切な実装を取得するようにファクトリーのコードを設定しますか?今それは役に立ちます。新しいクラスで新しいjarを追加し、実行時にもルールを設定する(または、このオプションを開いたままにしておく場合は新しい構成ファイルを追加する)だけで、既存のクラスに変更を加えることはできません。これはダイナミックファクトリです。

これは、企業ごとに2つの構成を作成する必要があり、おそらくそれぞれに2つの異なるアプリケーションを作成するよりも役立つでしょうか?

言うまでもなく、実行時に切り替えを行う必要はないので、アプリを構成します。クラスを継承する場合や別の実装を使用する場合は、構成を変更して再デプロイするだけです。わかりました、それはまた、工場で行うことができます。そして正直に言うと、何回これをしますか?おそらく、社内の他の場所で使用される予定のアプリがあり、コードを別のチームに渡そうとすると、彼らはこのようなことを行います。でもねえ、それはファクトリーでもできますし、ダイナミックなファクトリーならもっと良いでしょう!!

とにかく、コメント欄は私を殺すために開いているなら。


3
Dependency Injectionフレームワークは何か新しいものをもたらすために作成されていると考える開発者が多すぎます。ご存じのとおり、従来のファクトリー(ほとんどの場合、抽象的なファクトリー)は、依存関係の逆転と同じ役割を果たすことができます。反転vs注入?私にとって、依存性注入フレームワークの唯一の「利点」は、依存関係が追加/変更されたときにコードを変更/再コンパイルする必要がないことです(ほとんどの場合、SpringのようなXMLで構成できるため)。なぜ再コンパイルを避けるのですか?依存関係/ファクトリーを変更する際の潜在的な人的エラーを回避するため。しかし、私たちの優れたIDEでは、リファクタリングはうまく機能します:)
Mik378

6

IOCは2つの方法で実装される概念です。依存関係の作成と依存関係の注入、ファクトリ/抽象ファクトリは依存関係の作成の例です。依存性注入は、コンストラクター、セッター、およびインターフェースです。IOCの中核は、具象クラスに依存せず、メソッドの抽象(インターフェース/抽象クラスなど)を定義し、その抽象を使用して具象クラスのメソッドを呼び出すことです。Factoryパターンと同様に、基本クラスまたはインターフェースを返します。類似性の依存性注入は、基本クラス/インターフェイスを使用してオブジェクトの値を設定します。


4

依存関係の注入により、クライアントは独自に依存関係を取得する必要がなく、すべて事前に準備されます。

工場では、生成されたオブジェクトを必要な場所に届けるために、誰かがそれらを呼び出す必要があります。

違いは、主にこの1行にあり、ここでファクトリーの呼び出しと構成済みオブジェクトのフェッチが行われます。

しかし、ファクトリーでは、そのようなオブジェクトが必要なところならどこにでもこの1行を書く必要があります。DIを使用すると、ワイヤリング(使用法と作成されたオブジェクトの関係)を一度作成するだけで、その後どこでもオブジェクトの存在に依存するだけで済みます。一方で、DIは、準備側でもう少し(フレームワークにどの程度依存するか)の作業を必要とすることがよくあります。


3

DIについて読んですぐに同じ質問があり、この投稿で終わりました。最後にこれは私が理解したことですが、間違っている場合は修正してください。

「ずっと前に、独自の統治機関が独自の書面のルールに基づいて決定を決定および決定する王国はほとんどありませんでした。その後、1組のルール(憲法)を持ち、裁判所を通じて実施されるこれらすべての小さな統治機関を排除する大政府を結成しました。」

小さな王国の統治体は「工場」です

大きな政府は「Dependency Injector」です。


1
それでは、以前の小さな政府が今、大きくなることを恐れているのはいつですか?どのような基準で?
囚人ZERO

3

実際の例で2つの(および他の)アプローチを比較するには、このリンクを参照してください

基本的に、要件が変更された場合、DIの代わりにファクトリを使用すると、最終的にはより多くのコードを変更することになります。

これは、手動DIでも有効です(つまり、オブジェクトへの依存関係を提供する外部フレームワークがなく、それらを各コンストラクターで渡す場合)。


3

ここでのほとんどの回答は、概念的な違いと両方の実装の詳細を説明しています。しかし、私はIMOが最も重要なアプリケーションの違いについての説明を見つけることができず、OPは尋ねました。では、このトピックをもう一度開いてみましょう...

誰かが私にあなたがそれをどのように使うかが違いをもたらすと私に言ったら!

丁度。90%の場合、ファクトリまたはDIのいずれかを使用してオブジェクト参照を取得でき、通常は後者になります。別の10%の場合、ファクトリを使用するのは正しい方法にすぎません。これらのケースには、実行時パラメーターでの変数によるオブジェクトの取得が含まれます。このような:

IWebClient client = factoryWithCache.GetWebClient(url: "stackoverflow.com",
        useCookies: false, connectionTimeout: 120);

この場合client、DIから取得することはできません(または、少なくともいくつかの醜い回避策が必要です)。したがって、決定を行うための一般的なルールとして、実行時に計算されるパラメーターなしで依存関係を取得できる場合はDIが推奨され、そうでない場合はファクトリーを使用します。


2

DIはBeanを構成またはインスタンス化する方法だと思います。DIは、コンストラクター、セッターゲッターなど、さまざまな方法で実行できます。

ファクトリパターンは、Beanをインスタンス化するもう1つの方法です。このパターンは、主にファクトリデザインパターンを使用してオブジェクトを作成する必要がある場合に使用されます。

このリンクを確認してください:依存性注入


2

ビノイ

どちらか一方を選ぶ必要はないと思います。

依存するクラスまたはインターフェイスをクラスコンストラクターまたはセッターに移動する動作は、DIパターンに従います。コンストラクターまたはセットに渡すオブジェクトは、Factoryで実装できます。

いつ使用するのですか?開発者の操舵室にあるパターンを使用します。彼らは何を最も快適に感じ、最も理解しやすいと思いますか。


2

私は、3つの重要な側面がオブジェクトとその使用法を管理していると考えています
。1. インスタンス化(クラスの初期化と、存在する場合)。
2. 必要な場所に(そのように作成されたインスタンスの)注入
3. (作成されたインスタンスの)ライフサイクル管理

ファクトリーパターンを使用すると、最初の側面(インスタンス化)は達成されますが、残りの2つは疑問です。他のインスタンスを使用するクラスは、(インスタンスが作成されるのではなく)ファクトリーをハードコーディングする必要があります。これにより、疎結合機能が妨げられます。さらに、ライフサイクル管理ファクトリが複数の場所で使用される大規模なアプリケーションでは、インスタンスの数が問題になります(特に、ファクトリが返すインスタンスのライフサイクルをファクトリが管理しない場合、醜くなります)。 、懸念分離は、工場よりもはるかに優れています。

一方、DI(IoCパターンの)を使用すると、3つすべてがコードの外で(DIコンテナーに)抽象化され、マネージドBeanはこの複雑さについて何も必要としません。非常に重要な建築目標であるルーズカップリングは、静かに静かに達成できます。もう1つの重要なアーキテクチャ上の目標、

ファクトリは小規模なアプリケーションに適しているかもしれませんが、大きなものはファクトリよりもDIを選択する方が良いでしょう。


1

私の考え:

Dependecy Injection:コラボレーターをパラメーターとしてコンストラクターに渡します。Dependency Injection Framework:コンストラクターにパラメーターとして渡すオブジェクトを作成するための一般的で構成可能なファクトリー。


1
はい、正確に。このQ&Aでの依存性注入(DI)に関するほとんどすべての言及は、この定義とは対照的に用語を誤用しています。依存性注入コンテナ(DIC)は、オブジェクトを作成するための汎用的で構成可能なファクトリとして機能する最も一般的なフレームワークです。
CXJ 2017

1

インジェクションフレームワークは、ファクトリーパターンの実装です。

それはすべてあなたの要件に依存します。アプリケーションにファクトリーパターンを実装する必要がある場合、無数のインジェクションフレームワーク実装の1つによって要件が満たされる可能性が非常に高くなります。

独自のソリューションを展開する必要があるのは、サードパーティのフレームワークで要件を満たせない場合のみです。記述するコードが多いほど、維持する必要のあるコードも多くなります。コードは資産ではなく負債です。

どの実装を使用すべきかについての議論は、アプリケーションのアーキテクチャ上のニーズを理解することほど根本的に重要ではありません。


1

工場設計パターン

工場の設計パターンは、

  • インターフェース
  • 実装クラス
  • 工場

以下のように質問すると、いくつかのことを観察できます

  • ファクトリはいつ実装クラスのオブジェクトを作成しますか-ランタイムまたは コンパイル時?
  • 実行時に実装を切り替える場合はどうなりますか?- 不可能

これらは、依存性注入によって処理されます。

依存性注入

依存関係を注入する方法はいくつかあります。簡単にするために、インターフェース注入を使いましょう

DIでは、コンテナーが必要なインスタンスを作成し、それらをオブジェクトに「挿入」します。

したがって、静的なインスタンス化が排除されます。

例:

public class MyClass{

  MyInterface find= null;

  //Constructor- During the object instantiation

  public MyClass(MyInterface myInterface ) {

       find = myInterface ;
  }

  public void myMethod(){

       find.doSomething();

  }
}

1

額面から同じように見える

非常に簡単に言えば、ファクトリーパターン、クリエーションパターンは、オブジェクトを作成するのに役立ちます-「オブジェクトを作成するためのインターフェースを定義する」。オブジェクトプールの一種のキー値(例:辞書)があり、ファクトリにキーを渡す場合(私は単純なファクトリパターンを参照しています)、タイプを解決できます。仕事完了!一方、Dependency Injection Framework(Structure Map、Ninject、Unityなど)は同じことをしているようです。

しかし...「車輪を再発明しないでください」

建築の観点から見ると、それは結合層であり、「車輪を再発明しないでください」です。

エンタープライズグレードのアプリケーションの場合、DIの概念は、依存関係を定義するアーキテクチャレイヤーに近いものです。これをさらに単純化するために、依存関係の解決を行う別個のクラスライブラリプロジェクトと考えることができます。メインアプリケーションはこのプロジェクトに依存しています。このプロジェクトでは、依存関係リゾルバーは他の具体的な実装と依存関係の解決を参照します。

ファクトリーからの「GetType / Create」に加えて、たいていの場合、より多くの機能(XMLを使用して依存関係、モック、ユニットテストなどを定義する機能)が必要です。構造マップを参照したので、構造マップ機能リストを見てください。。単純なオブジェクトマッピングを単に解決するだけではありません。ホイールを再発明しないでください!

あなたが持っているのがハンマーだけなら、すべてが釘のように見えます

要件と構築するアプリケーションのタイプに応じて、選択する必要があります。プロジェクトが少なく(1つまたは2つである可能性があります)、依存関係がほとんどない場合は、より簡単な方法を選択できます。それは、単純な1または2のデータベース呼び出しにEntity Frameworkを使用するのではなく、ADO .Netデータアクセスを使用するようなものです。EFの導入は、そのシナリオでは過剰です。

しかし、より大きなプロジェクトの場合、またはプロジェクトが大きくなる場合は、フレームワークを備えたDIレイヤーを用意し、使用するDIフレームワークを変更する余地を作ることを強くお勧めします(メインアプリ(Webアプリ、Web API、デスクトップでファサードを使用) ..等。)。


1

ファクトリーを使用すると、関連するインターフェースをグループ化できます。そのため、渡されたパラメーターをファクトリーでグループ化できる場合はconstructor overinjection、このコードを確認するための優れたソリューション*):

public AddressModelFactory(IAddressAttributeService addressAttributeService,
        IAddressAttributeParser addressAttributeParser,
        ILocalizationService localizationService,
        IStateProvinceService stateProvinceService,
        IAddressAttributeFormatter addressAttributeFormatter)
    {
        this._addressAttributeService = addressAttributeService;
        this._addressAttributeParser = addressAttributeParser;
        this._localizationService = localizationService;
        this._stateProvinceService = stateProvinceService;
        this._addressAttributeFormatter = addressAttributeFormatter;
    }

コンストラクタを見てください。IAddressModelFactoryそこに渡す必要があるので、パラメータを減らします*):

 public CustomerController(IAddressModelFactory addressModelFactory,
        ICustomerModelFactory customerModelFactory,
        IAuthenticationService authenticationService,
        DateTimeSettings dateTimeSettings,
        TaxSettings taxSettings,
        ILocalizationService localizationService,
        IWorkContext workContext,
        IStoreContext storeContext,
        ICustomerService customerService,
        ICustomerAttributeParser customerAttributeParser,
        ICustomerAttributeService customerAttributeService,
        IGenericAttributeService genericAttributeService,
        ICustomerRegistrationService customerRegistrationService,
        ITaxService taxService,
        CustomerSettings customerSettings,
        AddressSettings addressSettings,...

CustomerController渡された多くのパラメーターが表示されます。そうですconstructor overinjection。これはDIの動作方法です。そして何も問題はありませんCustomerController

*)コードはnopCommerceからのものです。


1

簡単に言えば、Dependency InjectionとFactoryメソッドは、それぞれプッシュとプルのメカニズムを意味します。

プルメカニズム:クラスは、ファクトリメソッドに間接的に依存しています。ファクトリメソッドは、具象クラスに依存しています。

プッシュメカニズム:ルートコンポーネントは、すべての依存コンポーネントを1つの場所に構成できるため、高度なメンテナンスと疎結合を促進できます。

Factoryメソッドを使用しても、(間接的ではありますが)クラスに責任があり、依存性注入と同様に、責任が外部委託されます(ただし、抽象化のリークが発生します)。


0

これらは直交しており、一緒に使用できると思います。私が最近出会った例を紹介しましょう。

私たちは、Java for DIでSpringフレームワークを使用していました。シングルトンクラス(Parent)は別のクラス(Child)の新しいオブジェクトをインスタンス化する必要があり、それらには複雑なコラボレーターがありました:

@Component
class Parent {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    void method(int p) {
        Child c = new Child(dep1, dep2, ..., depN, p);
        // ...
    }
}

この例でParentは、DepXインスタンスを受け取って、Childコンストラクタます。これに関する問題:

  1. Parent より多くの知識を持っています Child必要
  2. Parent 必要以上の協力者がいる
  3. Child変更を伴う依存関係の追加Parent

これは私Factoryがここにぴったり合うと気付いたときです:

  1. それはの真のパラメータを除いてすべてを隠します ChildクラスのParent
  2. これChildは、DI構成で一元化できるの作成に関する知識をカプセル化します。

これは、簡略化されたParentクラスとChildFactoryクラスです。

@Component
class Parent {
    // ...
    @Autowired
    Parent(ChildFactory childFactory) {
        this.childFactory = childFactory;
    }

    void method(int p) {
        Child c = childFactory.newChild(p);
        // ...
    }
}

@Component
class ChildFactory {
    // ...
    @Autowired
    Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
        this.dep1 = dep1;
        this.dep2 = dep2;
        // ...
        this.depN = depN;
    }

    Child newChild(int p) {
        return new Child(dep1, dep2, ..., depN, p);
    }
}

0

この時点で必要なオブジェクトのタイプが正確にわかっている場合は、依存性注入を使用します。ファクトリパターンの場合、必要なオブジェクトの正確なタイプが不明なため、オブジェクトを作成するプロセスをファクトリに委任するだけです。


-1

私は両方を使用して、私の後にそれを維持する必要がある開発者にとってより読みやすい制御の反転戦略を作成します。

ファクトリを使用して、さまざまなレイヤーオブジェクト(ビジネス、データアクセス)を作成します。

ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();

別の開発者はこれを見て、ビジネスレイヤーオブジェクトを作成するときにBusinessFactoryで調べ、Intellisenseは開発者が作成できるすべてのビジネスレイヤーを提供します。ゲームをプレイする必要はありません。作成したいインターフェイスを見つけてください。

この構造はすでに制御の反転です。特定のオブジェクトを作成する責任はなくなりました。ただし、物事を簡単に変更できるようにするには、依存関係注入を確実にする必要があります。独自のDependency Injectionを作成するのはばかげているので、私はUnityを使用しています。CreateCarBusiness()の中で、Unityにどのクラスがこれに属していて、それが存続期間かを解決するように依頼します。

したがって、私のコードのFactory Dependency Injection構造は次のとおりです。

public static class BusinessFactory
{
    public static ICarBusiness CreateCarBusiness()
    {
       return Container.Resolve<ICarBusiness>();
    }
}

今は両方のメリットがあります。クラスが作成されたときにすべてのオブジェクトが利用可能であるというコンストラクタ依存性注入の代わりに、使用するオブジェクトのスコープに向かって、私のコードは他の開発者にとっても読みやすくなっています。

ユニットテストを作成するときに、これを使用してデータベースデータアクセスをカスタムコード化データアクセスレイヤーに変更します。単体テストでデータベース、Webサーバー、電子メールサーバーなどと通信したくありません。インテリジェンスがあるため、ビジネスレイヤーをテストする必要があります。


-4

1.小さいパーティションにコードをデプロイします。これは、1つの大きなコードのデカップリングでうまく処理できるためです。2.テスト性は、分離されていないオブジェクトを簡単に模擬できるため、DIを使用しても問題ない場合の1つです。インターフェイスを使用すると、各オブジェクトを簡単にモックしてテストできます。3.疎結合であるため、プログラムの他の部分をコーディングする必要なく、プログラムの各部分を同時に修正できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.