依賴倒置原則是系統解耦的重要原則,遵循它可讓咱們的系統更加健壯。java
依賴倒置原則(Dependency Inversion Principle)是 Robert C. Martin 提出的,原則聲明瞭兩個方面:算法
依賴倒置原則的聲明中有幾個概念:上層、下層,抽象、實現。ui
上層、下層是一類概念,在計算機的設計中,分層是常見的任務分解方法,每一層都使用下層提供的功能,又爲更上層提供本身的功能。依賴倒置原則要求在設計層間通訊、交互標準時,不該依賴於某個下層,而是應該依賴於抽象,這樣上下層之間就沒有強耦合,若是兩個實現都遵循了一樣的抽象,則能夠在上層無感知的狀況下替換下層實現。設計
抽象、實現是一類概念,抽象是對同一類任務本質屬性的表達,實現則是具體每一類任務的細節的表達。依賴倒置原則說明實現應該依賴於抽象,是由於實現是對抽象骨架的填充,而抽象不該依賴於實現,是由於抽象是對本質的概括,應去掉細節的干擾。code
看了上面的規則,還須要問一下依賴倒置原則倒置了什麼呢?排序
從字面看依賴倒置固然是倒置了依賴,但核心是控制權的反轉。咱們從下面的例子來解釋。接口
需求要求實現一個排序系統,系統須要實現各類排序算法,使用方能夠根據須要調用不一樣的排序算法來對本身的數據進行排序。ip
設計的接口以下:ci
public interface Sort { public void sort(int[] nums); }
有不一樣的排序算法實現:get
public class QuickSort { public void sort(int[] nums) { //quick sort implementation ... } } public class MergeSort { public void sort(int[] nums) { //merge sort implementation ... } } public class BubbleSort { public void sort(int[] nums) { //bubble sort implementation ... } } ......
使用方使用:
public class Client { public static void main(String[] args) { Sort sort = new QuickSort(); int[] nums = new int[10]; // initial nums sort.sort(nums); } }
能夠看到,使用方在使用的時候依賴的是抽象的Sort
接口,可是接口是無法實例化的,所以第一句 Sort sort = new QuickSort();
將實現實例化後賦值給變量,這裏,使用方做爲上層模塊就依賴了下層實現,違反了依賴倒置原則。
要解決這個問題,須要將實例化的過程遷移到排序系統中,使用方經過配置、參數等方式選擇本身要使用的算法,這樣使用方就不依賴排序系統具體的實現,而只依賴於Sort
的接口抽象。
咱們實現一種由排序系統智能判斷返回排序算法的簡單工廠。
public final class SortFactory { private static final int SIZE_THRESHOLD = 300; public static Sort choose (int sortSize) { if (sortSize < SIZE_THRESHOLD) { return new BubbleSort(); } return new QuickSort(); } }
使用方在在使用時直接使用 Sort sort = SortFactory.choose(size)
的形式來得到排序實例便可。
從這個例子中,咱們能夠看到,實例化的控制權本來是在使用方的手中,但這樣就將抽象與實現耦合在了一塊兒,後面咱們使用簡單工廠模式將控制權交回到排序系統,使用方就只須要調用工廠方法來獲取實例便可而無需關心具體實現了。
在考慮依賴倒置原則的使用時,跟單一職責原則同樣,須要注意使用的粒度。若是全部的代碼都符合依賴倒置原則,那就過猶不及了。
依賴倒置原則要求系統創建在抽象的基石之上,而不是實現的浮土之上。需求的變化是迅速而猛烈的,相應的就要求實現也是隨時隨地變化的,而其中的本質抽象倒是相對不變的,如此係統就能夠保持健壯,不會因外部紛擾左右搖擺。