首頁 > Java > java教程 > 主體

依賴倒置原則

王林
發布: 2024-08-26 06:32:31
原創
676 人瀏覽過

高層模組不應該依賴低層模組。兩者都應該依賴抽象。

抽像不應該依賴細節,細節應該依賴抽象。

讓我們透過一個例子來了解高階模組低階模組

Dependency Inversion Principle

在像 Flipkart 這樣的電子商務應用程式中,它可以被分類為 ProductCatalog、PaymentProcessor 和 CustomerProfile(這些是一些主要的業務功能)
這些業務功能相互依賴上圖所示的其他模組。

注意:頂部的模組更接近稱為高級級別模組的業務功能。
底部的模組接近稱為等級模組的實作細節。

低階模組是 SQLProductRepository、GooglePayService、WireTransfer、EmailSender 和 VoiceDialer。

如果我們單獨考慮CustomerProfile(高級模組)和Communication模組,那麼Communication是一個低階模組,但是如果我們單獨考慮Communication、EmailSender和VoiceDialer那麼,Communication成為一個高級模組,而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 的第二個定義,即抽像不應該依賴細節,細節應該依賴抽象。
正如我們在上圖中看到的,SQLProductRepository 依賴 ProductRepository,而不是相反。 這就是為什麼這個原理稱為依賴倒置原理


依賴注入 VS 依賴反轉

Even though they are related, they are not the same and can not be used interchangeably 
登入後複製

理解依賴注入:

在 ProductCatalog 中,我們使用工廠方法 ProductFactory.create() 來取得 SQLProductRepository 物件的實例。
雖然它將實例創建過程委託給工廠類別 ProductFactory,但初始化過程仍然由 ProductCatalog 類別完成。
理想情況下,我們不希望 ProductCatelog 類別擔心如何以及何時觸發實例化。
如果我們向 ProductCatalog 提供實例化的 ProductRepository 類,即使它沒有詢問,會怎麼樣?

因此,Main 類別 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(依賴倒置原理)的一部分,但它是密切相關的

讓我們用上面相同的程式碼來理解這一點

ProductCatalog 類別有一個接受 ProductRepository 物件的建構子。

呼叫 ProductCatalog 的類別將提供或註入 ProductRepository 的對象,在本例中它是 ECommerceMainApplication。
請注意,即使注入發生在 ProductCatalog 類別之外,注入仍然發生在程式的主流程中。即註入發生在程式執行的主執行緒中。

如果我們希望所有註入都發生在單獨的執行緒或單獨的上下文中,以便主控制流與注入完全隔離怎麼辦?

這可以使用 Spring(Java 中)等框架來實現。

Dependency Inversion Principle

Spring 將運行與程式主流程不同的自己的上下文
Spring 將負責注入類別所需的依賴項。所以如果你想要實例化一個類別的對象,你不需要直接在程式碼中自己做,而是要求 Spring 給你該類別的對象。
Spring框架會檢視實例化物件所需的所有依賴項,然後繼續注入所有依賴項,實例化對象,並將其傳回給主控制流。
因此,對依賴注入的控製完全委託給 Spring 框架,並且不會發生在郵件控制流程中。
這個概念稱為控制反轉(IOC),Spring 稱為控制反轉容器或簡稱為 IOC 容器

以上是依賴倒置原則的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!