網上介紹設計模式的文章有很多,好文也不少。作為設計模式的初學者,實在不敢多加造次。就僅以此文作為我記憶的備忘錄吧! 一、介紹 策略模式是對演算法的包裝,是把使用演算法的責任和演算法本身分割開來,委派給不同的對象管理。策略模式通常把一個系列的演算法包裝到一系列的策略類裡面,作為一個抽象策略類的子類。用一句話來 ...
網上介紹設計模式的文章有很多,好文也不少。作為設計模式的初學者,實在不敢多加造次。就僅以此文作為我記憶的備忘錄吧!
設計模式的三要素:可復用、可維護、可擴展。
一、介紹
策略模式是對演算法的包裝,是把使用演算法的責任和演算法本身分割開來,委派給不同的對象管理。策略模式通常把一個系列的演算法包裝到一系列的策略類裡面,作為一個抽象策略類的子類。用一句話來說,就是:”準備一組演算法,並將每一個演算法封裝起來,使得它們可以互換”。
這個模式涉及到三個角色:
環境(Context):持有一個策略的引用。
抽象策略(Strategy):這是一個抽象角色,通常由一個介面或抽象類實現。此角色給出所有的具體策略類所需的介面。
具體策略(ConcreteStrategy):包裝了相關的演算法或行為,表示具體的實現方式。
二、Demo實現
理論看的再多,還不如一個 Demo 讓人簡單易懂:
public class Duke { /** * 策略對象 - 鴨子叫行為 */ private Quackbehavior quackbehavior; /** * 策略對象 - 鴨子飛行行為 */ private FlyBehavior flyBehavior; /** * 利用多態註入具體的策略對象 */ public Duke(Quackbehavior quackbehavior, FlyBehavior flyBehavior) { this.quackbehavior = quackbehavior; this.flyBehavior = flyBehavior; } /** * 策略方法 */ public void performFly() { flyBehavior.fly(); } /** * 策略方法 */ public void performQuack() { quackbehavior.quack(); } // 其他方法 }
Duke類在策略模式中扮演一個環境(Context)的角色,表示持有策略的引用(quackbehavior、flyBehavior)。
public interface Quackbehavior { void quack(); }
public interface FlyBehavior { void fly(); }
這兩個介面在策略模式中扮演抽象策略(Strategy)的角色,把公共的行為封裝成介面。
Quackbehavior 的實現類:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class Quack implements Quackbehavior { @Override public void quack() { System.out.println("嘎嘎叫..."); } }Quack.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class Squeak implements Quackbehavior { @Override public void quack() { System.out.println("吱吱叫..."); } }Squeak.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class MuteQuack implements Quackbehavior { @Override public void quack() { System.out.println("不會叫..."); } }MuteQuack.java
FlyBehavior 的實現類:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class FlyNoWay implements FlyBehavior { @Override public void fly() { System.out.println("不會飛..."); } }FlyNoWay.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class FlyWithWings implements FlyBehavior { @Override public void fly() { System.out.println("正在飛翔..."); } }FlyWithWings.java
這兩對實現類在策略模式中扮演具體策略(ConcreteStrategy)的角色,表示具體的實現行為。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class Test { public static void main(String[] args) { DivingDuck divingDuck = new DivingDuck(new Quack(), new FlyWithWings()); ToyDuck toyDuck = new ToyDuck(new MuteQuack(), new FlyNoWay()); divingDuck.performQuack(); divingDuck.performFly(); System.out.println("---華麗的分割線---"); toyDuck.performQuack(); toyDuck.performFly(); } }測試類
演示源代碼鏈接:https://github.com/JMCuixy/design-patterns
三、總結
1、找出應用中可能需要變化之處,把他們獨立出來,不要和那些不需要變化的代碼混在一起。
2、針對介面編程,而不是針對實現編程。
3、多用組合,少用繼承。
第一點的概念很簡單,但是它幾乎是每個設計模式的精神所在。至於第二點和第三點,我覺得應該放在一起理解,繼承導致新建子類行為的不可預知性,因為你不清楚是不是父類所有的行為都適用於子類;而實現卻導致代碼無法復用,產生大量重覆的代碼。所以我們考慮了使用組合,最好是使用介面組合,從而可以利用多態註入不同實現,而這正是策略模式的精神呀!
以下是一些優秀博文的總結:
策略模式的特點:
1、策略模式的重心不是如何實現演算法,而是如何組織、調用這些演算法,從而讓程式結構更靈活,具有更好的維護性和擴展性。
2、策略模式一個很大的特點就是各個策略演算法的平等性。對於一系列具體的策略演算法,大家的地位是完全一樣的,正因為這個平等性,才能實現演算法之間可以相互替換。所有的策略演算法在實現上也是相互獨立的,相互之間是沒有依賴的。所以可以這樣描述這一系列策略演算法:策略演算法是相同行為的不同實現。
3、運行期間,策略模式在每一個時刻只能使用一個具體的策略實現對象,雖然可以動態地在不同的策略實現中切換,但是同時只能使用一個。
策略模式的優點:
1、策略模式提供了管理相關的演算法族的辦法。策略類的等級結構定義了一個演算法或行為族。恰當使用繼承可以把公共的代碼移到父類裡面,從而避免代碼重覆。
2、使用策略模式可以避免使用多重條件(if-else)語句。多重條件語句不易維護,它把採取哪一種演算法或採取哪一種行為的邏輯與演算法或行為的邏輯混合在一起,統統列在一個多重條件語句裡面,比使用繼承的辦法還要原始和落後。
策略模式的缺點:
1、客戶端必須知道所有的策略類,並自行決定使用哪一個策略類。這就意味著客戶端必須理解這些演算法的區別,以便適時選擇恰當的演算法類。換言之,策略模式只適用於客戶端知道演算法或行為的情況。
2、由於策略模式把每個具體的策略實現都單獨封裝成為類,如果備選的策略很多的話,那麼對象的數目就會很不可觀。