依存関係逆転の原則

王林
リリース: 2024-08-26 06:32:31
オリジナル
676 人が閲覧しました

高レベルのモジュールは低レベルのモジュールに依存すべきではありません。どちらも抽象化に依存する必要があります。

抽象化は詳細に依存すべきではなく、詳細は抽象化に依存する必要があります。

例を通して 高レベル モジュール低レベル モジュール を理解しましょう:

Dependency Inversion Principle

Flipkart のような e コマース アプリでは、高レベルで ProductCatalog、PaymentProcessor、CustomerProfile に分類できます (これらは主要なビジネス機能の一部です)
これらのビジネス機能は、上の図に示されている他のモジュールに相互依存しています。

注: 上のモジュールは、 レベル モジュールと呼ばれるビジネス機能に近いものです。
下部のモジュールは、 レベル モジュールと呼ばれる実装の詳細に近いものです。

低レベル モジュールは、SQLProductRepository、GooglePayService、WireTransfer、EmailSender、および VoiceDialer です。

CustomerProfile (高レベル モジュール) と通信モジュールだけを考慮すると、通信は低レベル モジュールですが、通信、EmailSender、および VoiceDialer だけを考慮すると、通信は高レベル モジュールになり、EmailSender とVoiceDialer は低レベルのモジュールです。

ここでのポイントは、高レベルおよび低レベル モジュールの概念は絶対的なものではなく、相対的なです。

上の画像によると、ProductCatalog は SQLProductRepository に依存しています。つまり、高レベルのモジュールは低レベルのモジュールに依存していますが、これは直接DIP の最初の定義と競合します


ProductCatalog → SQLProductRepository の関係を取り上げ、さらに分析してみましょう。

import java.util.List;
/*
 * High-Level module
*/
public class ProductCatalog {
    public void listAllProducts(){
        SQLProductRepository sqlProductRepository = new SQLProductRepository();
        List<String> allProductsNames = sqlProductRepository.getAllProductNames();
        //Display all products names
    }
}
ログイン後にコピー
/*
 * Low-level module 
*/
import java.util.Arrays;
import java.util.List;
public class SQLProductRepository {
    public List<String> getAllProductNames(){
        return Arrays.asList("soap","toothpaste");
    }
}
ログイン後にコピー

ProductCatalog は SQLProductRepository に直接依存しているため、これは明らかに DIP 定義 1 の違反です (定義によれば、高レベルと低レベルのモジュールは両方とも抽象化に依存する必要があります)

定義 1 に従ってこれを修正しましょう:

インターフェース ProductRepository の作成

import java.util.List;

public interface ProductRepository {
    public List<String> getAllProductNames();
}
ログイン後にコピー

SQLProductRepository でのこのインターフェイスの実装

/*
 * Low-level module 
*/
import java.util.Arrays;
import java.util.List;
public class SQLProductRepository  implements ProductRepository{
    @Override
    public List<String> getAllProductNames(){
        return Arrays.asList("soap","toothpaste");
    }
}
ログイン後にコピー

最後に、高レベル モジュール ProductCatalog については、その中で SQLProductRepository を直接インスタンス化すべきではありません。同じ
に ProductFactory クラスを使用します。

public class ProductFactory {
    public static ProductRepository create(){
        return new SQLProductRepository();
    }
}
ログイン後にコピー

ProductFactory を使用して SQLProductRepository をインスタンス化します

/*
 * High-Level module
*/
import java.util.List;

public class ProductCatalog {
    public void listAllProducts(){
        ProductRepository productRepository = ProductFactory.create();
        List<String> allProductsNames = productRepository.getAllProductNames();
        //Display all products names
    }
}
ログイン後にコピー

参照オブジェクトは ProductRepository であることに注意してください。そのため、SQLProductRepository との密結合はありません

変更後の新しい依存関係は次のようになります

Dependency Inversion Principle

上記の変更は DIP 定義 1 によるものです。
上記のコード変更は、DIP の 2 番目の定義にも準拠しています。つまり、抽象化は詳細に依存すべきではなく、詳細は抽象化に依存する必要があります。
上の画像からわかるように、SQLProductRepository は ProductRepository に依存しており、その逆ではありません。 これが、この原則が依存関係逆転の原則と呼ばれる理由です


依存関係の注入 VS 依存関係の反転

Even though they are related, they are not the same and can not be used interchangeably 
ログイン後にコピー

依存性の注入について:

ProductCatalog では、Factory メソッド ProductFactory.create() を使用して SQLProductRepository オブジェクトのインスタンスを取得します。
インスタンス作成プロセスはファクトリ クラス ProductFactory に委任されますが、初期化プロセスは依然として ProductCatalog クラスで行われます。
理想的には、ProductCatelog クラスがインスタンス化をいつどのようにトリガーするかについて心配する必要はありません。
インスタンス化された ProductRepository クラスを、要求されなくても ProductCatalog に提供したらどうなるでしょうか?

メイン クラス ECommerceMainApplication は、ファクトリ メソッド ProductFactory.create() を使用して ProductRepository のインスタンスを作成し、このインスタンスは ProductRepositroy クラスのコンストラクターの引数として渡されます。

public class ECommerceMainApplication {
    public static void main(String agrs[]) {
        ProductRepository productRepository = ProductFactory.create();
        ProductCatalog productCatalog = new ProductCatalog(productRepository);
        productCatalog.listAllProducts();
    }
}
ログイン後にコピー

それに応じて ProductCatalog クラスを更新した後

import java.util.List;

public class ProductCatalog {

    private ProductRepository productRepository;

    public ProductCatalog(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public void listAllProducts(){
        List<String> allProductsNames = productRepository.getAllProductNames();
        //Display all products names
        allProductsNames.forEach(product-> System.out.println(product));
    }
}
ログイン後にコピー

これで、ProductCatalog はいつでもどこでも自由に SQLProductRepository オブジェクトを使用できるようになりました。 SQLProductRepository オブジェクトを独自に作成することを心配する必要はなくなりました。
言い換えれば、ProductCatalog が依存関係のインスタンス化を心配するのではなく、依存関係を ProductCatalog に注入しています
これは依存性注入

の概念です。

制御の反転 - IOC

DIP (Dependency Inversion Principle) の一部ではありませんが、密接に関連しています

上記と同じコードでこれを理解してみましょう

クラス ProductCatalog には、ProductRepository オブジェクトを受け取るコンストラクターがありました。

ProductCatalog を呼び出すクラスは、ProductRepository のオブジェクトを提供または注入します。この場合、それは ECommerceMainApplication です。
注: 注入は ProductCatalog クラスの外部で発生しますが、注入はプログラムのメイン フロー中に発生します。つまり、注入はプログラム実行のメインスレッドで行われます。

すべてのインジェクションを別のスレッドまたは別のコンテキストで完全に実行して、メインの制御フローをインジェクションから完全に分離したい場合はどうなるでしょうか?

これは、Spring(Java の場合) のようなフレームワークを使用して実現できます。

Dependency Inversion Principle

Spring はプログラムのメインフローとは異なる独自のコンテキストを実行します
Spring は、クラスに必要な依存関係の注入を処理します。したがって、クラスのオブジェクトをインスタンス化したい場合は、コード内で直接行うのではなく、Spring にクラスのオブジェクトを提供するよう依頼します。
Spring フレームワークは、オブジェクトのインスタンス化に必要なすべての依存関係を調べてから、すべての依存関係を注入し、オブジェクトをインスタンス化し、それをメインの制御フローに返します。
したがって、依存関係注入の制御は Spring フレームワークに完全に委任され、メール制御フローでは発生しません。
この概念は制御の反転 (IOC) と呼ばれ、スプリングは制御の反転コンテナ、または単に IOC コンテナ

と呼ばれます。

以上が依存関係逆転の原則の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!