【設計模式學習筆記】 之 策略模式
簡介:
經常網購的可能發現京東、淘寶等電商平臺每到什麽節日都會進行打折,這種打折就是一種策略,策略模式的意思呢,就是把不變的和易變的策略分離開,需要什麽策略時候,把需要的策略傳給執行體,而不是執行體內置這些策略。
舉例1:
我們有一個CD播放器,cd播放器中如果內置了一些歌曲的話,那麽我們只能聽這些歌曲。但是cd本身並沒有內置播放資源(播放策略),而是通過插入cd進行播放cd碟片中的資源信息。
有了這個思路,我們先創建一個CD接口,讓每個CD實現類實現CD接口,cd接口中有一個sing方法
1 package com.mi.statege.statege1; 2 3 /** 4 * CD接口5 * @author hellxz 6 */ 7 public interface CD { 8 9 //cd的播放方法,為了不與CDPlayer方法重名,使用sing 10 public void sing(); 11 12 }
1 package com.mi.statege.statege1; 2 3 /** 4 * 周傑倫的專輯 5 * @author hellxz 6 */ 7 public class JayCD implements CD { 8 9 @Override 10 public void sing() {11 System.out.println("稻香"); 12 System.out.println("聽媽媽的話"); 13 System.out.println("最長的電影"); 14 System.out.println("等你下課"); 15 System.out.println("紅塵客棧"); 16 System.out.println("發如雪"); 17 } 18 19 }
1 package com.mi.statege.statege1; 2 3 /**4 * 五月天的專輯 5 * @author hellxz 6 */ 7 public class WuyuetianCD implements CD { 8 9 @Override 10 public void sing() { 11 System.out.println("倔強"); 12 System.out.println("你不是真正的快樂"); 13 } 14 15 }
接下來 創建一個CDPlayer 播放器類,這個類中持有CD接口引用,通過set方法為cd賦值,在play方法中調用cd的sing方法播放唱片內容
1 package com.mi.statege.statege1; 2 3 /** 4 * CD播放器 5 * @author hellxz 6 */ 7 public class CDPlayer { 8 9 private String brand; //CD播放器的品牌 10 11 private CD cd; //持有cd的引用 12 13 public CDPlayer(String brand) { //構造方法初始化品牌 14 this.brand = brand; 15 } 16 17 //播放 18 public void play() { 19 System.out.println(brand+"牌CD播放器啟動了……"); 20 cd.sing(); 21 } 22 23 //getters & setters 24 public CD getCd() { 25 return cd; 26 } 27 28 public void setCd(CD cd) { 29 this.cd = cd; 30 } 31 32 }
測試類
1 package com.mi.statege.statege1; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 CDPlayer player = new CDPlayer("步步高"); 7 player.setCd(new WuyuetianCD()); 8 // player.setCd(new JayCD()); 9 player.play(); 10 } 11 }
輸出:
步步高牌CD播放器啟動了……
倔強
你不是真正的快樂
打開第8行,關掉第七行
步步高牌CD播放器啟動了……
稻香
聽媽媽的話
最長的電影
等你下課
紅塵客棧
發如雪
觀察輸出,播放器中播放的歌曲的確切換了
舉例2:
這個是柳大對於hibernate組合查詢語句做的一個通用方法,使用了策略模式,試想:如果我們不用策略模式,而是通過傳參的判斷,通過傳的參數進行拼接sql的話,它同時需要反射生成POJO類,這樣一來POJO類名必須要和表名相同,而且如果我們需要傳入的參數是like查詢而不是=的時候,這樣會更加麻煩,對客戶端程序員的限制更大。
下面開始實現一下柳大的CommonQuery中如何使用的策略模式吧!
首先創建一個實體POJO的接口,並實現該接口,實現類為Student
1 package com.mi.statege.statege2; 2 3 /** 4 * 定義實體POJO接口 5 * @author hellxz 6 */ 7 public interface Entity { 8 9 //獲取sql的方法,返回一個拼接好的query sql 10 public String getSql(); 11 }
Student類中有兩個參數,學號以及姓名,學號使用“=”查詢,姓名使用“like %str%”進行模糊查詢,不為空則將不為空的參數拼接進sql
1 package com.mi.statege.statege2; 2 3 /** 4 * 學生POJO 5 * @author hellxz 6 */ 7 public class Student implements Entity { 8 9 private int stuNo; //學號 10 private String stuName; //姓名 11 12 @Override 13 public String getSql() { //重寫獲取query sql方法 14 StringBuffer sb = new StringBuffer(); 15 sb.append("select * from student where 1=1 "); 16 if(stuNo != 0) {//非空則學號使用"="進行查詢 17 sb.append(" and stuNo = "+stuNo+" "); 18 } 19 if(stuName != null && !stuName.trim().equals("")) {//非空則學生姓名使用"like %str%"進行查詢 20 sb.append(" and stuName like ‘%"+stuName+"%‘; "); 21 } 22 return sb.toString(); 23 } 24 25 //getters & setters 26 public int getStuNo() { 27 return stuNo; 28 } 29 30 public void setStuNo(int stuNo) { 31 this.stuNo = stuNo; 32 } 33 34 public String getStuName() { 35 return stuName; 36 } 37 38 public void setStuName(String stuName) { 39 this.stuName = stuName; 40 } 41 42 }
通用查詢類CommonQuery,運用多態動態指定POJO類型,獲取對應的sql
1 package com.mi.statege.statege2; 2 3 /** 4 * 通用查詢類 5 * @author hellxz 6 */ 7 public class CommonQuery { 8 9 private Entity entity; //持有一個Entity接口的引用 10 11 //查詢方法 12 public void query() { 13 //調用entity引用,運行期間綁定到實際類型中,調用getSql方法獲取拼接好的sql語句 14 String sql = entity.getSql(); 15 System.out.println(sql); //打印sql語句 16 } 17 18 //getters & setters 19 public Entity getEntity() { 20 return entity; 21 } 22 23 public void setEntity(Entity entity) { 24 this.entity = entity; 25 } 26 27 }
測試類
1 package com.mi.statege.statege2; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 Student student = new Student(); 7 student.setStuNo(1); 8 student.setStuName("Hellxz"); 9 CommonQuery query = new CommonQuery(); 10 query.setEntity(student); 11 query.query(); 12 } 13 }
查看輸出
select * from student where 1=1 and stuNo = 1 and stuName like ‘%Hellxz%‘;
這樣一來,我們就可以通過實現Entity接口的對象讓CommonQuery對象set進去就可以返回正確的sql了,而且不會有之前那些煩人的問題了
總結:
將執行體與策略分離開,這樣執行體中無需內置策略,只需要在執行特定策略的時候將策略set到執行體中執行策略內容即可。
優點: 1、算法可以自由切換。 2、避免使用多重條件判斷。 3、擴展性良好。
缺點: 1、策略類會增多。 2、所有策略類都需要對外暴露。
使用場景: 1、如果在一個系統裏面有許多類,它們之間的區別僅在於它們的行為,那麽使用策略模式可以動態地讓一個對象在許多行為中選擇一種行為。
2、一個系統需要動態地在幾種算法中選擇一種。
3、如果一個對象有很多的行為,如果不用恰當的模式,這些行為就只好使用多重的條件選擇語句來實現。
註意事項:如果一個系統的策略多於四個,就需要考慮使用混合模式,解決策略類膨脹的問題。
【設計模式學習筆記】 之 策略模式