設計パターンに関する簡単なメモ-設計原理の依存関係逆転原理

3.5依存関係逆転原理

3.5.1制御の反転(IOC)

  • 制御の反転、略してIOC
public abstract class TestCase {
  public void run() {
    if (doTest()) {
      System.out.println("Test succeed.");
    } else {
      System.out.println("Test failed.");
    }
  }
  
  public abstract boolean doTest();
}

public class JunitApplication {
  private static final List<TestCase> testCases = new ArrayList<>();
  
  public static void register(TestCase testCase) {
    testCases.add(testCase);
  }
  
  public static final void main(String[] args) {
    for (TestCase case: testCases) {
      case.run();
    }
  }

この単純化されたバージョンのテストフレームワークをプロジェクトに導入したら、フレームワークによって予約されている拡張ポイント、つまりTestCaseクラスのdoTest()抽象関数に特定のテストコードを入力するだけです。プロセスの実行を担当するmain()関数を記述する必要はありません。具体的なコードは次のとおりです。

public class UserServiceTest extends TestCase {
  @Override
  public boolean doTest() {
    // ... 
  }
}

// 注册操作还可以通过配置的方式来实现,不需要程序员显示调用register()
JunitApplication.register(new UserServiceTest();
  • これは、フレームワークを通じて「制御の反転」を実装する典型的な例です。フレームワークは、オブジェクトを組み立て、実行プロセス全体を管理するための拡張可能なコードスケルトンを提供します。プログラマが開発にフレームワークを使用する場合、ビジネスに関連するコードを予約済みの拡張ポイントに追加するだけでよく、フレームワークを使用してプログラムプロセス全体の実行を制御できます。

  • 「制御」はプログラムの実行フローの制御を指し、「逆」はフレームワークが使用される前のプログラム全体の実行のプログラマー自身の制御を指します。フレームワークを使用した後、プログラム全体の実行フローをフレームワークで制御できます。プログラマーからフレームワークに「逆転」したプロセスの制御。

  • コントロールの反転は特定の実装手法ではなく、フレームワークレベルの設計をガイドするために一般的に使用される、より一般的な設計アイデアです。

3.5.2依存性注入(DI)

  • ディペンデンシーインジェクション、略してDI

  • 逆転を制御するのとは対照的に、それは特定のコーディング手法です

  • 1つの文で要約すると、new()を使用してクラス内に依存クラスオブジェクトを作成するのではなく、外部で依存クラスオブジェクトを作成した後、コンストラクターや関数パラメーターなどを介してクラスに渡します(または注入します)。

  • 例:Notificationクラスはメッセージのプッシュを担当し、MessageSenderクラスに依存して、製品のプロモーションや確認コードなどのメッセージをユーザーにプッシュします。これを実現するには、依存性注入と非依存性注入を使用します。具体的な実装コードは次のとおりです。

    // 非依赖注入实现方式
    public class Notification {
      private MessageSender messageSender;
      
      public Notification() {
        this.messageSender = new MessageSender(); //此处有点像hardcode
      }
      
      public void sendMessage(String cellphone, String message) {
        //...省略校验逻辑等...
        this.messageSender.send(cellphone, message);
      }
    }
    
    public class MessageSender {
      public void send(String cellphone, String message) {
        //....
      }
    }
    // 使用Notification
    Notification notification = new Notification();
    
    // 依赖注入的实现方式
    public class Notification {
      private MessageSender messageSender;
      
      // 通过构造函数将messageSender传递进来
      public Notification(MessageSender messageSender) {
        this.messageSender = messageSender;
      }
      
      public void sendMessage(String cellphone, String message) {
        //...省略校验逻辑等...
        this.messageSender.send(cellphone, message);
      }
    }
    //使用Notification
    MessageSender messageSender = new MessageSender();
    Notification notification = new Notification(messageSender);
    

    最適化:

    public class Notification {
      private MessageSender messageSender;
      
      public Notification(MessageSender messageSender) {
        this.messageSender = messageSender;
      }
      
      public void sendMessage(String cellphone, String message) {
        this.messageSender.send(cellphone, message);
      }
    }
    
    public interface MessageSender {
      void send(String cellphone, String message);
    }
    
    // 短信发送类
    public class SmsSender implements MessageSender {
      @Override
      public void send(String cellphone, String message) {
        //....
      }
    }
    
    // 站内信发送类
    public class InboxSender implements MessageSender {
      @Override
      public void send(String cellphone, String message) {
        //....
      }
    }
    
    //使用Notification
    MessageSender messageSender = new SmsSender();
    Notification notification = new Notification(messageSender);
    

    上記では、依存クラスオブジェクトは依存注入を通じて渡されます。これにより、依存クラスを柔軟に置き換え、コードのスケーラビリティを向上させることができます

3.5.3依存性注入フレームワーク(DIフレームワーク)

  • Google Guice、Java Spring、Pico Container、Butterfly Containerなど、多くの依存関係注入フレームワークがあります。
  • 作成する必要のあるすべてのクラスオブジェクト、依存関係注入フレームワークによって提供される拡張ポイントを介したクラスとクラス間の依存関係を構成するだけでよく、フレームワークを実装してオブジェクトを自動的に作成し、オブジェクトのライフサイクルを管理し、依存関係注入を実行できます。プログラマが行う必要があること。

3.5.4依存関係の逆転の原則(DIP)

  • 依存関係の逆転の原則、DIPと省略

  • 高レベルのモジュールは低レベルのモジュールに依存しません。高レベルのモジュールと低レベルのモジュールは、抽象化を通じて相互に依存する必要があります。

  • 抽象化(抽象化)は特定の実装の詳細(詳細)に依存せず、特定の実装詳細(詳細)は抽象化(抽象化)に依存します。

  • 高レベルモジュールと低レベルモジュールの区分は、呼び出しチェーンで、呼び出し元が高レベルに属し、呼び出し先が低レベルに属していることです。

  • 例:Tomcatは、Java Webアプリケーションを実行するためのコンテナーです。作成するWebアプリケーションコードは、Tomcatコンテナの下にデプロイするだけでよく、Tomcatコンテナで呼び出して実行できます。以前の分割の原則によると、Tomcatは高レベルモジュールであり、私たちが作成するWebアプリケーションコードは低レベルモジュールです。Tomcatとアプリケーションコードの間に直接の依存関係はなく、どちらもサーブレットの仕様である同じ「抽象化」に依存しています。サーブレット仕様は特定のTomcatコンテナーおよびアプリケーションの実装の詳細に依存しませんが、Tomcatコンテナーおよびアプリケーションはサーブレット仕様に依存します。

3.5.5レビュー

  • SmallFly:

    依存関係の逆転の原則の概念は、高レベルのモジュールが低レベルのモジュールに依存しないことです。高レベルのモジュールが必要なようですが、実際には低レベルのモジュールの設計を規制しています。

    低レベルモジュールによって提供されるインターフェイスは、十分に抽象的で一般的なものである必要があり、設計では高レベルモジュールの使用タイプとシナリオを考慮する必要があります

    明らかに、高レベルのモジュールは低レベルのモジュールを使用し、低レベルのモジュールに依存する必要があります。逆に、低レベルのモジュールは高レベルのモジュールに従って設計する必要があり、「逆」の外観が表示されます

    この設計には2つの利点があります。

    1. 低レベルのモジュールはより用途が広く、より適切です
    2. 高レベルモジュールは、低レベルモジュールの特定の実装に依存しないため、低レベルモジュールの交換が容易になります。

おすすめ

転載: www.cnblogs.com/wod-Y/p/12746794.html