摘要:今天和大家分享一下設計模式中的策略模式,這里只是分享樓主自己的見解,如有考慮不恰當的地方,還請理解,那么我們言歸正傳。那怎么辦呢,答案你懂的,就是用策略模式。
今天和大家分享一下設計模式中的策略模式,這里只是分享樓主自己的見解,如有考慮不恰當的地方,還請理解,那么我們言歸正傳。由于樓主自己工作的原因,常常需要將數據庫中資源數據生成相應的靜態化文件(json文件),也就是俗稱的打包,來給前端調用。資源數據可能有很多種類型。例如:新聞、電影、小說、動漫、游戲等。不同的類型,在打包時,可能有不一樣的流程,例如新聞和電影就有很大的不同,新聞在打包時,除了基本的流程外,還需要有上傳功能,也就是自動下發,因為新聞的實效性要求很高。但電影就不需要有此功能,因為打包文件太大,不能自動下發,需人工審批。下面我們按照上面的需求用一般的思維來設計我們相關的類。
按照需求我們需要一個接口來定義我們打包的所有方法,然后我們為該接口創建相應的實現類將公共的可以復用的方法封裝到這個實現類中,將每個模塊特有的方法放到它的子類里去自己實現。下面為具體的代碼:
/** * 定義所有打包的流程 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 10:45 * @since 1.0.0 */ public interface Staticize { /** * 初始化 如:創建相應文件夾、定義一些打包參數等 */ void doInit(); /** * 獲取數據庫資源數據 */ void findStaticData(); /** * 獲取相應的資源 如 圖片、音頻等 */ void doGetRes(); /** * 將生成的資源包打包ZIP文件 */ void doZip(); /** * 將ZIP文件自動下發 (只有新聞有此流程) */ void doUpload(); } /** * 公共流程方法實現 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:11 * @since 1.0.0 */ public class DetailStaticize implements Staticize { public void doInit() { System.out.println("初始化成功"); } public void findStaticData() { System.out.println("獲取新聞資源數據成功"); System.out.println("獲取電影資源數據成功"); } public void doGetRes() { System.out.println("獲取相應的資源成功"); } public void doZip() { System.out.println("ZIP創建成功"); } public void doUpload() { } } /** * 新聞特有流程方法處理 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:13 * @since 1.0.0 */ public class NewsStaticize extends DetailStaticize { @Override public void findStaticData() { System.out.println("獲取新聞資源數據成功"); } @Override public void doUpload() { System.out.println("新聞自動下發成功"); } } /** * 電影特有流程方法處理 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:13 * @since 1.0.0 */ public class VideoStaticize extends DetailStaticize { @Override public void findStaticData() { System.out.println("獲取電影資源數據成功"); } @Override public void doUpload() { } }
下面為測試結果 調用默認接口實現:
/** * 測試類 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:15 * @since 1.0.0 */ public class Test { @org.junit.Test public void test() { Staticize staticize = new DetailStaticize(); staticize.doInit(); staticize.findStaticData(); staticize.doGetRes(); staticize.doZip(); staticize.doUpload(); } }
結果為:
初始化成功 獲取新聞資源數據成功 獲取電影資源數據成功 獲取相應的資源成功 ZIP創建成功
調用新聞實現:
/** * 測試類 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:15 * @since 1.0.0 */ public class Test { @org.junit.Test public void test() { Staticize staticize = new NewsStaticize(); staticize.doInit(); staticize.findStaticData(); staticize.doGetRes(); staticize.doZip(); staticize.doUpload(); } }
結果為:
初始化成功 獲取新聞資源數據成功 獲取相應的資源成功 ZIP創建成功 新聞自動下發成功 調用電影實現:
/** * 測試類 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:15 * @since 1.0.0 */ public class Test { @org.junit.Test public void test() { Staticize staticize = new VideoStaticize(); staticize.doInit(); staticize.findStaticData(); staticize.doGetRes(); staticize.doZip(); staticize.doUpload(); } }
結果為:
初始化成功 獲取電影資源數據成功 獲取相應的資源成功 ZIP創建成功
按照執行結果來看,似乎實現了我們的需求。但有一點需要注意就是我們的子類里會有一些空實現,也就是電影子類重寫父類的upload()方法。如果我們的另一個模塊,例如 綜藝模塊,由于資源也是比較大的,不需要自動下發,那我們也要在此模塊中添加upload方法的空實現,可能有些人認為,只是一個空實現,沒啥大不了的,畢竟什么也沒有寫嗎。但是,如果需求變了,需要電影或者綜藝等沒有自動下發功能的模塊當ZIP文件生成成功時自動發郵件通知運營手動拷貝呢,這時我們就要在這個upload()方法里添加具體的發送郵件代碼了,并且這兩個模塊的業務邏輯完全相同的,這就造成了代碼的重復,不能復用。這時,可能用人還會說,我可以寫一個工具類來處理發送郵件的需求。這樣就解決了,代碼重復,不能復用的問題。這樣當然可以,但是還有一點別忘了,就是調用發送郵件的方法還是要寫在每一個具體的子類中,這個當工具類做某些修改,那么和它有關的所有的調用類都要做出相應修改,這就顯然也不是最好的解決方案。
那怎么辦呢,答案你懂的,就是用策略模式。那什么是策略模式呢?
策略模式的定義:定義了算法組,分別封裝起來,讓它們之間可以互相替換,此模式讓算法的變化獨立于使用算法的客戶。
按照設計模式的基本原則之一:找出應用中可能變化之處,把它們獨立出來,不要和那些不需要變化的代碼混在一起。也就是說,我們需要將接口中需要變化的地方提取出來。按照我們的需求也就是需要將upload()方法提取出來。那怎么提取呢,是提取成接口還是提取成一個多帶帶的類?這個還有一個設計模式的原則就是:針對接口編程,而不是針對實現編程。這句話的意思是:我們知道一個接口可以有很多個實現類,至于一共有哪些實現類,接口是不需要知道的,調用時只要實例化這個實現類并指向該接口就可執行調用,如果有新的實現類,只要新實例化這個新類即可,對接口方法的調用沒有改變,這樣就很方便擴展。
回到我們的需求上,我們需要將upload抽取成一個接口,然后為了它創建兩個實現類,一個為自動下發實現,一個為不需要自動下發實現。具體代碼如下:
/** * 下發接口 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 11:06 * @since 1.0.0 */ public interface UploadStaticize { void upload(); } /** * 自動下發接口實現 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 13:26 * @since 1.0.0 */ public class DefalutUploadStaticize implements UploadStaticize { public void upload() { System.out.println("upload"); } } /** * 不需要自動下發接口實現 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 13:27 * @since 1.0.0 */ public class DefalutUnUploadStaticize implements UploadStaticize { public void upload() { System.out.println("un upload"); } }
DefaultStaticize實現類修改如下:
/** * 公共流程方法實現 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:11 * @since 1.0.0 */ public class DetailStaticize implements Staticize { UploadStaticize uploadStaticize = new DefalutUnUploadStaticize(); public void doInit() { System.out.println("初始化成功"); } public void findStaticData() { System.out.println("獲取新聞資源數據成功"); System.out.println("獲取電影資源數據成功"); } public void doGetRes() { System.out.println("獲取相應的資源成功"); } public void doZip() { System.out.println("ZIP創建成功"); } public void doUpload() { uploadStaticize.upload(); } }
NewsStaticize實現類修改如下:
/** * 新聞特有流程方法處理 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:13 * @since 1.0.0 */ public class NewsStaticize extends DetailStaticize { public NewsStaticize() { uploadStaticize = new DefalutUploadStaticize(); } @Override public void findStaticData() { System.out.println("獲取新聞資源數據成功"); } }
測試類代碼未修改:新聞模塊
/** * 測試類 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:15 * @since 1.0.0 */ public class Test { @org.junit.Test public void test() { Staticize staticize = new NewsStaticize(); staticize.doInit(); staticize.findStaticData(); staticize.doGetRes(); staticize.doZip(); staticize.doUpload(); } }
測試結果:
初始化成功 獲取新聞資源數據成功 獲取相應的資源成功 ZIP創建成功 upload
電影模塊:
/** * 測試類 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:15 * @since 1.0.0 */ public class Test { @org.junit.Test public void test() { Staticize staticize = new VideoStaticize(); staticize.doInit(); staticize.findStaticData(); staticize.doGetRes(); staticize.doZip(); staticize.doUpload(); } }
測試結果:
初始化成功 獲取電影資源數據成功 獲取相應的資源成功 ZIP創建成功 un upload
這樣寫有有什么好處呢,就是方便擴展,如我上面所說如果需要將沒有自動下發功能的模塊添加發送郵件通知功能,那么我們只需要新創建一個UploadStaticize的子類就可以了。對應修改如下:
/** * 發送郵件實現類 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 17:57 * @since 1.0.0 */ public class EmailUploadStaticize implements UploadStaticize { public void upload() { System.out.println("send email"); } } /** * 電影特有流程方法處理 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:13 * @since 1.0.0 */ public class VideoStaticize extends DetailStaticize { public VideoStaticize() { uploadStaticize = new EmailUploadStaticize(); } @Override public void findStaticData() { System.out.println("獲取電影資源數據成功"); } }
測試類代碼不變 ,輸入結果為:
初始化成功 獲取電影資源數據成功 獲取相應的資源成功 ZIP創建成功 send email
結果似乎已經很完美了,但你可能會發現 ,就是我們改動了VideoStaticize 這個類,這個是電影模塊的核心類,我們不能隨隨便便就修改已經開發好的類,因為這樣就不是可擴展易維護的程序了,并且這也不符合設計模式的基本原則。那什么辦法嗎,答案還是有的。就是我們讓客戶端可以設置,如果客戶端不設置那么程序就按照原先的邏輯執行,如果設置了,就按照新設置的策略執行。具體代碼如下:
Staticize接口新增setUploadStaticize()方法:
/** * 定義所有打包的流程 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 10:45 * @since 1.0.0 */ public interface Staticize { /** * 初始化 如:創建相應文件夾、定義一些打包參數等 */ void doInit(); /** * 獲取數據庫資源數據 */ void findStaticData(); /** * 獲取相應的資源 如 圖片、音頻等 */ void doGetRes(); /** * 將生成的資源包打包ZIP文件 */ void doZip(); /** * 將ZIP文件自動下發 (只有新聞有此流程) */ void doUpload(); /** * 添加可以動態設置UploadStaticize的方法 * * @param uploadStaticzie */ void setUploadStaticzie(UploadStaticize uploadStaticzie); }
添加setUploadStaticize()方法具體的實現:
/** * 公共流程方法實現 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:11 * @since 1.0.0 */ public class DetailStaticize implements Staticize { UploadStaticize uploadStaticize = new DefalutUploadStaticize(); public void doInit() { System.out.println("初始化成功"); } public void findStaticData() { System.out.println("獲取新聞資源數據成功"); System.out.println("獲取電影資源數據成功"); } public void doGetRes() { System.out.println("獲取相應的資源成功"); } public void doZip() { System.out.println("ZIP創建成功"); } public void doUpload() { uploadStaticize.upload(); } public void setUploadStaticzie(UploadStaticize uploadStaticzie) { this.uploadStaticize = uploadStaticzie; } }
測試類代碼修改:
/** * 測試類 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:15 * @since 1.0.0 */ public class Test { @org.junit.Test public void test() { Staticize staticize = new NewsStaticize(); staticize.doInit(); staticize.findStaticData(); staticize.doGetRes(); staticize.doZip(); staticize.setUploadStaticzie(new EmailUploadStaticize()); staticize.doUpload(); } }
執行結果:
初始化成功 獲取新聞資源數據成功 獲取相應的資源成功 ZIP創建成功 send email
這樣程序就是一個可以擴展易維護的程序了。例如 如果需求變更需要新聞模塊不但自動下發還要發送郵件怎么辦呢。這時我們就不需要做任何開發了,只要客戶端自己調用就可以了。代碼如下:
/** * 測試類 * * @author Sama * @author jilinwula@foxmail.com * @date 2017-01-04 15:15 * @since 1.0.0 */ public class Test { @org.junit.Test public void test() { Staticize staticize = new NewsStaticize(); staticize.doInit(); staticize.findStaticData(); staticize.doGetRes(); staticize.doZip(); staticize.doUpload(); staticize.setUploadStaticzie(new EmailUploadStaticize()); staticize.doUpload(); } }
執行結果:
初始化成功 獲取新聞資源數據成功 獲取相應的資源成功 ZIP創建成功 upload send email
這就是我對設計模式中策略模式的理解 ,如本文有不正確之處,歡迎指出。謝謝。
原文地址:吉林烏拉
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66714.html
摘要:可以使用其他模式來修正這個缺陷,如工廠方法模式代理模式或享元模式。我們的策略模式只是實現了策略的管理,但是沒有嚴格地定義適當的場景使用適當的策略,在實際項目中,一般通過工廠方法模式來實現策略類的聲明。源碼地址參考文獻設計模式之禪 定義 Define a family of algorithms,encapsulate each one,and make them interchange...
摘要:一定義定義維基百科策略模式作爲一種軟件設計模式,指對象有某個行爲,但是在不同的場景中,該行爲有不同的實現算法。二策略模式圖我們看看策略模式是有怎樣設計結構的。如中創建線程池,線程池任務滿時,對提交的任務做處理就使用了策略模式。以前完整的看過《大話設計模式》,雖然完整看過,也做過筆記,但現在依然很多已經很模糊。這段時間趁著離職,有時間,打算重新過一遍,該篇將介紹策略模式。一、定義定義(維基百科...
摘要:孫臏心里一萬個草泥馬在奔騰,差點沒噎死自己滾一邊去,我們這盤跟他賽馬開始,策略模式上場。在設計模式之禪中的提出通過策略枚舉和反射機制對策略模式進行改良,膜拜了但是要添加或淘汰策略,還是得去對枚舉進行修改,也不符合開閉原則。 今天給大家說說田忌賽馬的故事。如有雷同,純屬巧合!話說在戰國時期,群雄割據,硝煙四起,茶余飯后還是少不了娛樂活動的,其中賽馬是最火爆的。一天,孫臏看到田忌像個死雞似...
閱讀 3063·2021-10-12 10:20
閱讀 2809·2021-09-27 13:56
閱讀 790·2021-09-27 13:36
閱讀 1424·2021-09-26 09:46
閱讀 2417·2019-08-30 14:02
閱讀 2685·2019-08-28 18:14
閱讀 1257·2019-08-26 10:32
閱讀 1700·2019-08-23 18:25