設計模式之策略模式
- 2019 年 10 月 6 日
- 筆記
今天和大家分享一下設計模式中的策略模式,這裡只是分享樓主自己的見解,如有考慮不恰當的地方,還請理解,那麼我們言歸正傳。由於樓主自己工作的原因,常常需要將數據庫中資源數據生成相應的靜態化文件(json文件),也就是俗稱的打包。資源數據可能有很多種類型。例如:新聞、電影、小說等。不同的類型,在打包時,有不一樣的流程,例如新聞和電影就有很大的不同,新聞在打包後還有要自動上傳功能,這是因為對新聞的實效性要求很高,自動上傳成功後,會自動調用下發服務器的下髮指令,來自動更新APP中的新聞數據。而電影就不需要有此功能,一是因為電影的打包文件相比新聞太大,所以沒必要調用自動上傳接口,因為這樣上傳會比較慢,還不一定能保證電影包的完整性。二是因為電影會因一些版權等原因,需要人工審批。所以,電影和新聞相比就少了一個自動上傳的功能。
下面我們按照上面的需求來設計我們相關的類,雖然新聞和電影有不同的打包流程,但我們分析後知道,除了生成json文件(數據不同)和自動上傳功能不同外,其他的流程是可以公用的,那麼按照面向對象的思想,我們應該設計出一個超類,將新聞和電影兩個模塊中相同的打包流程,在超類中實現,將兩個模塊不同的打包流程設計成抽象方法讓它們的子類去實現,這樣就可以將相同的打包流程復用了。具體的代碼如下:





現在看似乎沒有什麼問題,但是如果,我要把小說,遊戲等模塊都添加進來呢?上面的設計似乎就不太合理了,因為按照上面的設計,每一個子類都會默認繼承doUpload()方法,按照我們之前的分析,暫時只有新聞模塊是需要這個功能,其他的模塊都不需要,那麼這時我們子類就會包括大量的空實現。又如果我們的需求變了,其他的模塊也需要有上傳功能,但是是不同於新聞模塊的上傳邏輯的,那麼上面的設計的代碼就不用復用了,這就違背了面向對象的思想了。
現在我們知道使用繼承並不能很好的解決我們遇到的問題,現在我們只能藉助於設計模式了。我們首先看設計模式中的第一個原則:
- 找出程序中可能變化的,把它們提取出來,不要和那些不需要變化的代碼放在一起。
在說的簡單點就是,如果每次我們有新的需求開發時,如果要修改曾經已經編碼好的代碼時,那麼我們基本可以確定,要把這一部分提取出來,和其他已經編寫好的穩定的代碼分開。
按照我們之前的分析,我們知道打包類中只有兩部分是變化的,也就是生成json文件和自動上傳這兩個方法,所以我們把這兩個方法提取出來,這樣我們就可以把這兩個打包流程和真正的打包類分離了。
既然我們已經知道了要把生成json文件和自動上傳功能要分離,那我們到底要怎麼分離呢,也就是我們到底創建相關的類分離還是接口分離呢?這裡還有一個可以遵循的設計模式原則,也就是本篇中的第二個設計模式原則:
- 針對接口編程,而不是針對實現編程。
針對接口編程的意思是說針對超類型編程,針對接口編程的好處是,可以利用多態,這樣程序執行的時候,會根據真正執行的子類類型來執行。
在說的簡單點就是我們知道一個接口可以有很多個實現類,至於一共有哪些實現類,接口是不需要知道的,調用時只要實例化這個實現類並指向該接口就可執行調用,如果有新的實現類,只要新實例化這個新類即可,對接口方法的調用沒有改變,這樣就很方便擴展。
既然我們知道應該針對接口編程,那麼我們需要把生成json文件和自動上傳這兩個打包流程設計成兩個接口,然後設計不同的子類實現它們,讓子類去實現它們原有的邏輯。下面是具體的代碼。


這樣我們已經把生成json文件和自動上傳兩個流程的接口設計完了,那我們怎麼改原先的打包類呢?按照我們上面了解的那樣,我們需要針對接口編程,所以,我們需要把我們新設計的json文件和自動上傳這兩個流程的接口放到原先的打包類中,而原先的打包類中已經不需要自己處理這兩部分流程了,具體的流程而是我們已經設計好的相關的子類去實現。這樣我們就可以用多態的特性,動態改變它們的執行流程了。具體代碼如下:



這樣我們已經把生成json文件和自動上傳相關的流程已經和打包類分離了。這樣設計不但方便了我們日後擴展,我們還可以直接動態的改變原有的流程。具體代碼如下:



這樣我們就可以動態的改變原有打包類中的打包邏輯了。
這就是策略模式的具體應用。下面我們看策略模式的具體定義。
策略模式的定義:定義了算法組,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化獨立於使用算法的客戶。
這就是我對設計模式中策略模式的理解 ,如本文有不正確之處,歡迎指出。謝謝。