- 重學(xué)Java設(shè)計模式
- 付政委(小付哥)
- 1440字
- 2021-05-19 18:09:52
2.6 依賴倒置原則
2.6.1 依賴倒置原則定義
依賴倒置原則是Robert C.Martin于1996年在C++Report上發(fā)表的文章中提出的。
依賴倒置原則(Dependence Inversion Principle,DIP)是指在設(shè)計代碼架構(gòu)時,高層模塊不應(yīng)該依賴于底層模塊,二者都應(yīng)該依賴于抽象。抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象。
依賴倒置原則是實現(xiàn)開閉原則的重要途徑之一,它降低了類之間的耦合,提高了系統(tǒng)的穩(wěn)定性和可維護性,同時這樣的代碼一般更易讀,且便于傳承。
2.6.2 模擬場景
在互聯(lián)網(wǎng)的營銷活動中,經(jīng)常為了拉新和促活,會做一些抽獎活動。這些抽獎活動的規(guī)則會隨著業(yè)務(wù)的不斷發(fā)展而調(diào)整,如隨機抽獎、權(quán)重抽獎等。其中,權(quán)重是指用戶在當(dāng)前系統(tǒng)中的一個綜合排名,比如活躍度、貢獻度等。
下面模擬出抽獎的一個系統(tǒng)服務(wù),如果是初次搭建這樣的系統(tǒng)會怎么實現(xiàn)?這個系統(tǒng)是否有良好的擴展性和可維護性,同時在變動和新增業(yè)務(wù)時測試的復(fù)雜度是否高?這些都是在系統(tǒng)服務(wù)設(shè)計時需要考慮的問題。
2.6.3 違背原則方案
下面先用最直接的方式,即按照不同的抽獎邏輯定義出不同的接口,讓外部的服務(wù)調(diào)用。
1.定義抽獎用戶類

這個類就是一個普通的對象類,其中包括了用戶姓名和對應(yīng)的權(quán)重,方便滿足不同的抽獎方式。
接下來實現(xiàn)兩種不同的抽獎邏輯,在一個類中用兩個接口實現(xiàn),如下所示。


在這個抽獎邏輯類中包括了兩個接口,一個是隨機抽獎,另一個是按照權(quán)重排序。
·隨機抽取好理解,把集合中的元素使用工具包Collections.shuffle()進行亂序,之后選取三個元素。當(dāng)然,除了這樣的隨機抽取方式,還有其他方式。
·按照權(quán)重排序,這里使用了list.sort的方法,并按排序邏輯的方式進行自定義排序。最終選擇權(quán)重最高的前三名作為中獎用戶。
2.測試結(jié)果


這里使用單元測試的方式,在初始化數(shù)據(jù)后分別調(diào)用兩個接口方法進行測試。測試結(jié)果如下所示。

從測試結(jié)果上看,程序沒有問題,驗證結(jié)果正常。但是這樣實現(xiàn)有什么問題呢?
如果程序是一次性的、幾乎不變的,那么可以不考慮很多的擴展性和可維護性因素;但如果這些程序具有不確定性,或者當(dāng)業(yè)務(wù)發(fā)展時需要不斷地調(diào)整和新增,那么這樣的實現(xiàn)方式就很不友好了。
首先,這樣的實現(xiàn)方式擴展起來很麻煩,每次擴展都需要新增接口,同時對于調(diào)用方來說需要新增調(diào)用接口的代碼。其次,對于這個服務(wù)類來說,隨著接口數(shù)量的增加,代碼行數(shù)會不斷地暴增,最后難以維護。
2.6.4 依賴倒置原則改善代碼
既然上述方式不具備良好的擴展性,那么用依賴倒置、面向抽象編程的方式實現(xiàn)。
首先定義抽獎功能的接口,任何一個實現(xiàn)方都可以實現(xiàn)自己的抽獎邏輯。
1.抽獎接口
這里只有一個抽獎接口,接口中包括了需要傳輸?shù)?list 集合,以及中獎用戶數(shù)量。

2.隨機抽獎實現(xiàn)
這部分隨機抽獎邏輯與上面的抽獎方式邏輯是一樣的,只不過放到接口實現(xiàn)中了。


3.權(quán)重抽獎實現(xiàn)
權(quán)重抽獎也是一樣,把這些都放到自己的接口實現(xiàn)中。這樣一來,任何一種抽獎都有自己的實現(xiàn)類,既可以不斷地完善,也可以新增。

4.創(chuàng)建抽獎服務(wù)


在這個類中體現(xiàn)了依賴倒置的重要性,可以把任何一種抽獎邏輯傳遞給這個類。這樣實現(xiàn)的好處是可以不斷地擴展,但是不需要在外部新增調(diào)用接口,降低了一套代碼的維護成本,并提高了可擴展性及可維護性。
另外,這里的重點是把實現(xiàn)邏輯的接口作為參數(shù)傳遞,在一些框架源碼中經(jīng)常會有這種做法。
5.測試結(jié)果

這里與前面代碼唯一不同的是新增了實現(xiàn)抽獎的入?yún)?new DrawRandom()、new DrawWeightRank()。在這兩個抽獎的功能邏輯作為入?yún)⒑螅瑪U展起來會非常的方便。
以這種抽象接口為基準(zhǔn)搭建起來的框架結(jié)構(gòu)會更加穩(wěn)定,算程[1]已經(jīng)建設(shè)好,外部只需要實現(xiàn)自己的算子[2]即可,最終把算子交給算程處理。
[1] 算程是一段算法的執(zhí)行過程。
[2] 算子是具體算法的執(zhí)行邏輯。
- Mastering OpenCV Android Application Programming
- Visual Basic程序設(shè)計教程
- TestNG Beginner's Guide
- JavaScript by Example
- Building RESTful Python Web Services
- Java高并發(fā)核心編程(卷1):NIO、Netty、Redis、ZooKeeper
- ElasticSearch Cookbook(Second Edition)
- Java程序員面試筆試寶典(第2版)
- Java Web開發(fā)實例大全(基礎(chǔ)卷) (軟件工程師開發(fā)大系)
- Learning C++ by Creating Games with UE4
- HTML5游戲開發(fā)實戰(zhàn)
- Web開發(fā)新體驗
- Moodle 3.x Developer's Guide
- Building Web and Mobile ArcGIS Server Applications with JavaScript(Second Edition)
- Jenkins 2.x實踐指南