高レベルのモジュールは低レベルのモジュールに依存すべきではありません。どちらも抽象化に依存する必要があります。
抽象化は詳細に依存すべきではなく、詳細は抽象化に依存する必要があります。
例を通して、高レベルモジュールと低レベルモジュールを理解しましょう:
Flipkart のような e コマース アプリでは、高レベルで ProductCatalog、PaymentProcessor、CustomerProfile に分類できます (これらは主要なビジネス機能の一部です)
これらのビジネス機能は、上の図に示されている他のモジュールに相互依存しています。
注: 上部のモジュールは、高レベルのモジュールと呼ばれるビジネス機能に近いです。
一番下のモジュールは、低レベルレベルのモジュール
低レベル モジュールは、SQLProductRepository、GooglePayService、WireTransfer、EmailSender、および VoiceDialer です。
CustomerProfile (高レベル モジュール) と通信モジュールだけを考慮すると、通信は低レベル モジュールですが、通信、EmailSender、および VoiceDialer だけを考慮すると、通信は高レベル モジュールになり、EmailSender と VoiceDialer は低レベルモジュール
ここでのポイントは、高レベルモジュールと低レベルモジュールの概念は絶対的なものではなく、相対的なものです。
上の画像によると、ProductCatalog は SQLProductRepository に依存しています。つまり、高レベルのモジュールは低レベルのモジュールに依存していますが、これは直接DIP の最初の定義と競合しています。
ProductCatalog → SQLProductRepository の関係を取り上げて、さらに分析してみましょう。リーリー リーリー
ProductCatalog は SQLProductRepository に直接依存しているため、これは明らかに DIP 定義 1 の違反です (定義によれば、
)定義 1 に従ってこれを修正しましょう:
インターフェース ProductRepository の作成
リーリー
SQLProductRepository でのこのインターフェイスの実装
リーリー
最後に、高レベル モジュール ProductCatalog については、その中で SQLProductRepository を直接インスタンス化すべきではありません
リーリーProductFactory を使用して SQLProductRepository をインスタンス化します
参照オブジェクトは ProductRepository であることに注意してください。そのため、SQLProductRepository との密結合はありません
変更後の新しい依存関係は次のようになります
上記の変更はDIP定義1によるものです。上記のコード変更は、DIP の 2 番目の定義にも準拠しています。つまり、抽象化は詳細に依存すべきではなく、詳細は抽象化に依存する必要があります。
上の画像からわかるように、SQLProductRepository は ProductRepository に依存しており、その逆ではありません。これが、この原則が依存関係逆転の原則と呼ばれる理由です
依存関係の注入 VS 依存関係の反転
インスタンス作成プロセスはファクトリ クラス ProductFactory に委任されますが、初期化プロセスは依然として ProductCatalog クラスで行われます。
理想的には、ProductCatelog クラスがインスタンス化をいつどのようにトリガーするかについて心配する必要はありません。インスタンス化された ProductRepository クラスを、要求されなくても ProductCatalog に提供したらどうなるでしょうか?
そのため、メイン クラス ECommerceMainApplication は、ファクトリ メソッド ProductFactory.create() を使用して ProductRepository のインスタンスを作成し、このインスタンスは ProductRepositroy クラスのコンストラクターの引数として渡されます。
リーリー
リーリー
言い換えれば、
依存関係のインスタンス化について心配する ProductCatalog ではなく、ProductCatalog に依存関係
これが
依存性注入の概念です
制御の反転 - IOC
クラス ProductCatalog には、ProductRepository オブジェクトを受け取るコンストラクターがありました。
ProductCatalog を呼び出すクラスは、ProductRepository のオブジェクトを提供または注入します。この場合、それは ECommerceMainApplication です。
注: 注入は ProductCatalog クラスの外部で発生しますが、注入は依然としてプログラムのメイン フロー中に発生します。つまり、インジェクションはプログラム実行のメインスレッドで発生します。
すべてのインジェクションを別のスレッドまたは別のコンテキストで完全に実行して、メインの制御フローをインジェクションから完全に分離したい場合はどうすればよいでしょうか?
これは、Spring(Java) のようなフレームワークを使用して実現できます。
Spring はプログラムのメインフローとは異なる独自のコンテキストを実行します
Spring は、クラスに必要な依存関係の注入を処理します。したがって、クラスのオブジェクトをインスタンス化したい場合は、コード内で直接行うのではなく、Spring にクラスのオブジェクトを提供するよう依頼します。
Spring フレームワークは、オブジェクトのインスタンス化に必要なすべての依存関係を調べてから、すべての依存関係を注入し、オブジェクトをインスタンス化し、それをメインの制御フローに返します。
したがって、依存関係注入の制御は Spring フレームワークに完全に委任され、メール制御フローでは発生しません。
この概念は制御の反転 (IOC)と呼ばれ、スプリングは制御の反転コンテナー、または単にIOC コンテナー
以上が依存関係逆転の原則の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。