高層模組不應該依賴低層模組。兩者都應該依賴抽象。
抽像不應該依賴細節,細節應該依賴抽象。
讓我們透過一個例子來了解高階模組和低階模組:
在像 Flipkart 這樣的電子商務應用程式中,高層次上它可以分為 ProductCatalog、PaymentProcessor 和 CustomerProfile(這些是一些主要業務功能)
這些業務功能相互依賴上圖所示的其他模組。
注意:上面的模組更接近業務功能,稱為高等級模組。
底部的模組接近稱為低等級模組的實作細節。
低階模組是 SQLProductRepository、GooglePayService、WireTransfer、EmailSender 和 VoiceDialer。
如果我們單獨考慮CustomerProfile(高級模組)和Communication模組,那麼Communication是一個低階模組,但是如果我們單獨考慮Communication、EmailSender和VoiceDialer,那麼Communication就成為一個高級模組,而EmailSender和VoiceDialer是低階模組。
這裡的重點是高低層模組的概念不是絕對的,而是相對的。
根據上圖,ProductCatalog 依賴 SQLProductRepository,即高階模組依賴低階模組,但這直接與 DIP 的第一個定義相衝突.
讓我們進一步分析 ProductCatalog → SQLProductRepository 關係。
由於 ProductCatalog 直接依賴 SQLProductRepository,這顯然違反了 DIP 定義 1(根據定義高級模組和低階模組都應該依賴抽象)
讓我們根據定義 1 修復此問題:
建立介面ProductRepository
在SQLProductRepository中實作此介面
最後,對於高階模組 ProductCatalog,我們不應該直接在其中實例化 SQLProductRepository。我們將使用 ProductFactory 類別來實現相同的目的
我們將使用 ProductFactory 實例化 SQLProductRepository
注意我們的引用物件是 ProductRepository 所以,我們與 SQLProductRepository 沒有任何緊密耦合
修改後,新的依賴項將如下所示
以上更改依照 DIP 定義 1.
上面的程式碼變更也遵循 DIP 的第二個定義,即抽像不應該依賴細節,細節應該依賴抽象。
正如我們在上圖中看到的,SQLProductRepository 依賴 ProductRepository,而不是相反。這就是為什麼這個原理被稱為依賴倒置原理
理解依賴注入:
在 ProductCatalog 中,我們使用工廠方法 ProductFactory.create() 來取得 SQLProductRepository 物件的實例。
雖然它將實例創建過程委託給工廠類別 ProductFactory,但初始化過程仍然由 ProductCatalog 類別完成。
理想情況下,我們不希望 ProductCatelog 類別擔心如何以及何時觸發實例化。
如果我們向 ProductCatalog 提供實例化的 ProductRepository 類,即使它沒有詢問,會怎麼樣?
因此,Main 類別 ECommerceMainApplication 使用工廠方法 ProductFactory.create() 來建立 ProductRepository 的實例,並且該實例作為參數傳遞到 ProductRepositroy 類別的建構函式中。
對應更新 ProductCatalog 類別後
現在 ProductCatalog 可以隨時隨地自由使用 SQLProductRepository 物件。它不再擔心自己建立 SQLProductRepository 物件。
換句話說,我們將相依性注入到 ProductCatalog 中,而不是讓 ProductCatalog 擔心實例化相依性。
這就是依賴注入的概念
雖然它不是DIP(依賴倒置原理)的一部分,但它是密切相關的
讓我們用上面相同的程式碼來理解這一點
ProductCatalog 類別有一個接受 ProductRepository 物件的建構子。
呼叫 ProductCatalog 的類別將提供或註入 ProductRepository 的對象,在本例中它是 ECommerceMainApplication。
請注意,即使注入發生在 ProductCatalog 類別之外,注入仍然發生在程式的主流程中。即註入發生在程式執行的主執行緒中。
如果我們希望所有註入都發生在單獨的執行緒或單獨的上下文中,以便主控制流與注入完全隔離,該怎麼辦?
這可以使用像Spring(Java 中)這樣的框架來實現。
Spring 將運行自己的上下文與程式的主流程不同
Spring 將負責注入類別所需的依賴項。所以如果你想要實例化一個類別的對象,不要直接在程式碼中自己做,而是要求 Spring 給你該類別的對象。
Spring框架檢視實例化物件所需的所有依賴項,然後繼續注入所有依賴項,實例化對象,並將其傳回給主控制流。
因此,對依賴注入的控製完全委託給 Spring 框架,並且不會發生在郵件控制流程中。
這個概念稱為控制反轉(IOC),Spring 稱為控制反轉容器或簡稱為IOC 容器
以上是依賴倒置原則的詳細內容。更多資訊請關注PHP中文網其他相關文章!