策略模式定義了算法族,分別封裝起來,讓它們之間能夠互相替換,此模式讓算法的變化獨立於使用算法的客戶。java
不少同窗可能不太理解這個定義,我舉個簡單的例子,好比客戶要實現一個功能,分爲A,B,C,D4個步驟完成,其中A和C步驟是很容易發生改變的,因此咱們將A和C步驟分別封裝起來,算法
具體實現方式是將A和C定義爲接口,各自分別有1,2,3種實現方式。此時A和C對應的就是算法族,各自的實現叫作算法,各個算法之間能夠相互替換,來達到不一樣的實現目的。客戶編程
須要實現的功能能夠由A和C算法族組合實現各式各樣不一樣的功能,而咱們實現功能的主幹永遠不會改變。ide
上面的小例子也用到了幾個設計原則:測試
1,將程序中可能須要改變的部分獨立出來,不要和不須要變化的代碼放在一塊兒。this
2,針對接口編程,而不是針對實現編程。設計
3,少用繼承,多用組合。對象
第1點相信你們都能理解,可是在實際工做中,要完美的運用實際上並無那麼簡單。blog
第2點,先說說針對接口編程的好處,就好比例子中,主幹功能代碼不須要任何改變,咱們就能實現各類不一樣功能的實現,精髓就在各個具體的算法實現了一個接口,咱們只須要傳入不一樣的具體的實現繼承
就能輕鬆實現不一樣的功能。若是你不理解爲何能這樣作,那你可能還不理解java的多態,父類引用指向子類對象。咱們也能夠經過這個例子來反向理解多態,你會發現原來多態就是這樣,so easy!
第3點,少用繼承,多用組合。繼承太過於笨重,若是我繼承某個接口或者類,我就必須實現這個接口或者類的全部方法,這顯然是不合理的,組合就不同了,我能夠任意組合實現各類各樣的功能。
好比A的一種具體實現和C的一種具體實現就是一類組合,這裏咱們能夠實現3x3=9種組合,也就意味着有9種實現該功能的方式,若是須要增長,咱們只須要增長一種實現類,而不須要修改主幹的任意
代碼就能輕易實現。
這裏舉一個簡單的小例子,好比某明顯開一場演唱會,後臺調音師須要根據明星演唱的歌曲準備背景音樂。這裏就能夠運用策略模式去實現。
1,先定義一個背景音樂的接口,建立一個播放的方法。
package strategy; /** * @ClassName BackgroundMusic * @Description 背景音樂接口 * @Author liuyi * @Date 2020/6/14 11:08 * @Version 1.0 */ public interface BackgroundMusic { /** * @Author liuyi * @Description 定義播放的方法 * @Date 11:10 2020/6/14 * @Param [] * @return void **/ public void play(); }
2,分別有三種背景音樂去實現該接口
背景音樂1
package strategy; /** * @ClassName BackgroundMusic1 * @Description TODO * @Author liuyi * @Date 2020/6/14 11:12 * @Version 1.0 */ public class BackgroundMusic1 implements BackgroundMusic { @Override public void play() { System.out.println("開始播放背景音樂1"); } }
背景音樂2
package strategy; /** * @ClassName BackgroundMusic2 * @Description TODO * @Author liuyi * @Date 2020/6/14 11:13 * @Version 1.0 */ public class BackgroundMusic2 implements BackgroundMusic{ @Override public void play() { System.out.println("開始播放背景音樂2"); } }
背景音樂3
package strategy; /** * @ClassName BackgroundMusic3 * @Description TODO * @Author liuyi * @Date 2020/6/14 11:13 * @Version 1.0 */ public class BackgroundMusic3 implements BackgroundMusic { @Override public void play() { System.out.println("開始播放背景音樂3"); } }
3,建立背景音樂編號枚舉類
package strategy; /** * @ClassName MusicNumEnum * @Description 背景音樂編號枚舉類 * @Author liuyi * @Date 2020/6/14 11:20 * @Version 1.0 */ public enum MusicNumEnum { music1(1,"strategy.BackgroundMusic1"), music2(2,"strategy.BackgroundMusic2"), music3(3,"strategy.BackgroundMusic3"); MusicNumEnum(int num, String className){ this.num = num; this.className = className; } //編號 private int num; //類名稱 private String className; public int getNum() { return num; } public void setNum(int num) { this.num = num; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } //根據num獲取className public static String getClassNameByNum(int num){ MusicNumEnum[] values = MusicNumEnum.values(); for (MusicNumEnum value : values) { if(value.getNum()==num){ return value.getClassName(); } } return null; } }
4,測試
package strategy; /** * @ClassName StrategyTest * @Description 策略模式測試類 * @Author liuyi * @Date 2020/6/14 11:16 * @Version 1.0 */ public class StrategyTest { public static void main(String[] args) throws Exception { palyByNum(1); palyByNum(3); palyByNum(2); } /** * @Author liuyi * @Description 根據播放編號播放對應的背景音樂 * @Date 11:41 2020/6/14 * @Param [num] * @return void **/ public static void palyByNum(int num) throws Exception{ //根據背景音樂編號播放對應的背景音樂 BackgroundMusic backgroundMusic = (BackgroundMusic)(Class.forName(MusicNumEnum.getClassNameByNum(num)).newInstance()); backgroundMusic.play(); } }
從代碼能夠看出咱們須要播放某個由於,只須要傳入對應的編號便可,不須要對主幹代碼進行修改。若是下場演唱會須要新增背景音樂,則添加一個背景音樂類,而後在枚舉類配置對應的編號和類的關係便可。
從策略模式的概念來看,每一種背景音樂其實就是一種具體的算法,背景音樂1,背景音樂2,背景音樂3它們之間能夠互相替換,來達到不一樣的目的,而使用的客戶是不須要知道這些的存在的, 用戶只須要傳入算法
對應的編號或者類型便可。