策略模式 定義了算法族,分別封裝起來,讓他們能夠互相替換,此模式讓算法的變化獨立於使用算法的客戶。java
策略模式的三要素:git
抽象策略角色: 策略類,一般由一個接口或者抽象類實現。github
具體策略角色:包裝了相關的算法和行爲。算法
環境角色:持有一個策略類的引用,最終給客戶端調用。編程
提出問題:要求作出一套模擬鴨子的遊戲,遊戲中會出現各類鴨子,它們一邊游泳,一邊呱呱叫。cookie
分析:根據OO設計思想,無非就是使各類鴨子實現本身相應的功能便可,如鴨子游泳,鴨子呱呱叫。this
解決方案1.0:設計一個接口(Duck),而後根據須要完成不一樣的實現,如紅頭鴨,綠頭鴨。。。。設計
public interface Duck { public abstract void quack(); public abstract void swim(); public abstract void display(); } public MallardDuck implements Duck{ public abstract void quack(){ System.out.println("呱呱~~"); } public abstract void swim(){ System.out.println("歡快的游泳~~"); } public abstract void display(){ System.out.println("綠頭鴨~~"); } } public RedHeadDuck implements Duck{ public abstract void quack(){ System.out.println("呱呱~~"); } public abstract void swim(){ System.out.println("歡快的游泳~~"); } public abstract void display(){ System.out.println("紅頭鴨~~"); } }
忽然增長一個新的需求,要求有野鴨,除了具備這兩個功能外,還會飛(fly),同時還有一種橡皮鴨,叫聲時吱吱。。code
此時該方案便暴露了一下缺點。。。。orm
缺點:牽一髮而動全身,咱們很難知道全部鴨子的行爲,當針對有些實現須要添加新的功能時
解決方案1.1
爲了更加靈活,面向接口編程。
public interface Flyable { public abstract void fly(); } public interface Swimable { public abstract void swim(); } public interface Quackable { public abstract void quack(); } public RedHeadDuck implements Quackable implements Swimable {...} public WildDuck implements Quackable implements Swimable implements Flyable {...}
若是有一萬種鴨子,這種方式簡直不敢想象,重複代碼太多!
解決方案2.0
採用策咯模式解決此問題。
step1:把會變化的部分取出來,並封裝起來,好讓其餘代碼不受影響。
step2:封裝行爲的大局觀
step3:代碼實現
抽象策略角色
// 飛行行爲 public interface FlyBehavior { public abstract void fly(); } // 叫聲行爲 public interface QuackBehavior { public abstract void quack(); }
具體策略對象
// 橡皮鴨叫 public RubberDuckBehavior implements QuackBehavior { public void quack(){ System.out.println("吱吱~~"); } } // 野鴨叫 public WildDuckBehavior implements QuackBehavior { public void quack(){ System.out.println("嘎嘎~~"); } } // 大黃鴨叫 public YellowDuckBehavior implements QuackBehavior { public void quack(){ System.out.println("呱呱~~"); } }
// 不會飛 public class FlyNoWay implements FlyBehavior { public void fly(){ System.out.println("不會飛~~"); } } // 用翅膀飛 public class FlyWithWings implements FlyBehavior { public void fly(){ System.out.println("用翅膀飛~~"); } } // 螺旋槳飛 public class FlyLikePlane implements FlyBehavior { public void fly(){ System.out.println("用螺旋槳~~"); } }
環境角色
抽象類
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; // 動態設定行爲 public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } public void performFly() { flyBehavior.fly(); } public void performQuack() { quackBehavior.quack(); } public abstract void display(); public void swim() { System.out.println("鴨子天生會游泳!"); } }
實現
public class WildDuck extends Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public WildDuck() { // 默認會飛,野鴨叫嘎嘎 this.flyBehavior = new FlyWithWings(); this.quackBehavior = new WildDuckBehavior(); } // 動態設定行爲 public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } public void performFly() { flyBehavior.fly(); } public void performQuack() { quackBehavior.quack(); } public void display(){ System.out.println("這是一隻野鴨"); }; public void swim() { System.out.println("鴨子天生會游泳!"); } }
需求改變:野鴨的翅膀受傷,不會飛了
public static void main(String[] args) { Duck duck = new WildDuck(); duck.setFlyBehavior(new FlyNoWay()); duck.performFly();// 輸出:不會飛~~ }
需改改變:新增一隻火箭鴨,能飛到太空,不會游泳,外形像火箭同樣,叫嘎嘎
public RocketDuckFlyBehavior implements FlyBehavior { public void fly(){ System.out.println("飛到太空~~"); } }
public class RocketDuck extends Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public WildDuck() { // 默認會飛,野鴨叫嘎嘎 this.flyBehavior = new RocketDuckFlyBehavior(); this.quackBehavior = new WildDuckQuackBehavior(); } // 動態設定行爲 public void setFlyBehavior(FlyBehavior flyBehavior) { this.flyBehavior = flyBehavior; } public void setQuackBehavior(QuackBehavior quackBehavior) { this.quackBehavior = quackBehavior; } public void performFly() { flyBehavior.fly(); } public void performQuack() { quackBehavior.quack(); } public abstract display() { System.out.println("外形像火箭~~"); } public void swim() { System.out.println("不會游泳"); } }
優勢:
1.策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行爲族。恰當使用繼承能夠把代碼轉移到符類,從而避免重複代碼 。
2.在策略模式中利用組合和委託來讓環境角色擁有執行算法的能力,這也是繼承的一種更輕便的替代方案。
3.提供了對開放—封閉原則的完美支持,將算法封裝在獨立的strategy中,使得它們易於切換,易於理解,易於擴展
4.利用組合、委託和多態等技術和思想,能夠有效地避免多重條件選擇語句
缺點:
1.客戶端必須知道全部的策略類,區分他們之間的區別,並自行決定使用哪個策略類。
2.針對每一種行爲狀況須要建立一個策略類,形成不少的策略類。
我的站點地址:www.mycookies.cn(適合java初學者的我的博客項目) github:https://github.com/liqianggh/blog