Java設計模式之策略模式(Strategy Pattern)

簡介

  策略模式定義了算法族,分別封裝起來,讓它們之間能夠互相替換,此模式讓算法的變化獨立於使用算法的客戶。java

組成

  1.抽象策略角色(Strategy): 策略類,一般由一個接口或者抽象類實現。算法

  2.具體策略角色(ConcreteStrategy):包裝了相關的算法和行爲。ide

  3.環境角色(Context):持有一個策略類的引用,最終給客戶端調用。函數

類圖

  

使用場景

  一、若是在一個系統裏面有許多類,它們之間的區別僅在於它們的行爲,那麼使用策略模式能夠動態地讓一個對象在許多行爲中選擇一種行爲。網站

  二、一個系統須要動態地在幾種算法中選擇一種。this

  三、若是一個對象有不少的行爲,若是不用恰當的模式,這些行爲就只好使用多重的條件選擇語句來實現。spa

 

優缺點

優勢

  一、 策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行爲族。恰當使用繼承能夠把公共的代碼轉移到父類裏面,從而避免重複的代碼。設計

  二、 策略模式提供了能夠替換繼承關係的辦法。繼承能夠處理多種算法或行爲。若是不是用策略模式,那麼使用算法或行爲的環境類就可能會有一些子類,每個子類提供一個不一樣的算法或行爲。可是,這樣一來算法或行爲的使用者就和算法或行爲自己混在一塊兒。決定使用哪種算法或採起哪種行爲的邏輯就和算法或行爲的邏輯混合在一塊兒,從而不可能再獨立演化。繼承使得動態改變算法或行爲變得不可能。對象

  三、 使用策略模式能夠避免使用多重條件(if-else)轉移語句。多重轉移語句不易維護,它把採起哪種算法或採起哪種行爲的邏輯與算法或行爲的邏輯混合在一塊兒,通通列在一個多重轉移語句裏面,比使用繼承的辦法還要原始和落後。繼承

缺點

  一、客戶端必須知道全部的策略類,並自行決定使用哪個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道全部的算法或行爲的狀況。

  二、 策略模式形成不少的策略類,每一個具體策略類都會產生一個新類。有時候能夠經過把依賴於環境的狀態保存到客戶端裏面,而將策略類設計成可共享的,這樣策略類實例能夠被不一樣客戶端使用。換言之,可使用享元模式來減小對象的數量。

 

練習案例

實現一

 

咱們將建立一個定義活動的 Strategy 接口和實現了 Strategy 接口的實體策略類。Context 是一個使用了某種策略的類。

StrategyPatternDemo,咱們的演示類使用 Context 和策略對象來演示 Context 在它所配置或使用的策略改變時的行爲變化。

 

步驟 1

建立一個接口。

Strategy.java

public interface Strategy { public int doOperation(int num1, int num2); }

步驟 2

建立實現接口的實體類。

OperationAdd.java

public class OperationAdd implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 + num2; } }

OperationSubstract.java

public class OperationSubstract implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 - num2; } }

OperationMultiply.java

public class OperationMultiply implements Strategy{ @Override public int doOperation(int num1, int num2) { return num1 * num2; } }

步驟 3

建立 Context 類。

Context.java

public class Context { private Strategy strategy; public Context(Strategy strategy){ this.strategy = strategy; } public int executeStrategy(int num1, int num2){ return strategy.doOperation(num1, num2); } }

步驟 4

使用 Context 來查看當它改變策略 Strategy 時的行爲變化。

StrategyPatternDemo.java

public class StrategyPatternDemo { public static void main(String[] args) { Context context = new Context(new OperationAdd()); System.out.println("10 + 5 = " + context.executeStrategy(10, 5)); context = new Context(new OperationSubstract()); System.out.println("10 - 5 = " + context.executeStrategy(10, 5)); context = new Context(new OperationMultiply()); System.out.println("10 * 5 = " + context.executeStrategy(10, 5)); } }

步驟 5

執行程序,輸出結果:

10 + 5 = 15
10 - 5 = 5
10 * 5 = 50

 

 

實現二

 

假設如今要設計一個販賣各種書籍的電子商務網站的購物車系統。一個最簡單的狀況就是把全部貨品的單價乘上數量,可是實際狀況確定比這要複雜。好比,本網站可能對全部的高級會員提供每本20%的促銷折扣;對中級會員提供每本10%的促銷折扣;對初級會員沒有折扣。

  根據描述,折扣是根據如下的幾個算法中的一個進行的:

  算法一:對初級會員沒有折扣。

  算法二:對中級會員提供10%的促銷折扣。

  算法三:對高級會員提供20%的促銷折扣。

  使用策略模式來實現的結構圖以下:

 

源代碼

  抽象折扣類

 

public interface MemberStrategy {
    /**
     * 計算圖書的價格
     * @param booksPrice    圖書的原價
     * @return    計算出打折後的價格
     */
    public double calcPrice(double booksPrice);
}

 

  初級會員折扣類

 

public class PrimaryMemberStrategy implements MemberStrategy {
 
    @Override
    public double calcPrice(double booksPrice) {
        
        System.out.println("對於初級會員的沒有折扣");
        return booksPrice;
    }
 
}

 

  中級會員折扣類

 

public class IntermediateMemberStrategy implements MemberStrategy {
 
    @Override
    public double calcPrice(double booksPrice) {
 
        System.out.println("對於中級會員的折扣爲10%");
        return booksPrice * 0.9;
    }
 
}

 

  高級會員折扣類

 

public class AdvancedMemberStrategy implements MemberStrategy {
 
    @Override
    public double calcPrice(double booksPrice) {
        
        System.out.println("對於高級會員的折扣爲20%");
        return booksPrice * 0.8;
    }
}

 

   價格類

 

public class Price {
    //持有一個具體的策略對象
    private MemberStrategy strategy;
    /**
     * 構造函數,傳入一個具體的策略對象
     * @param strategy    具體的策略對象
     */
    public Price(MemberStrategy strategy){
        this.strategy = strategy;
    }
    
    /**
     * 計算圖書的價格
     * @param booksPrice    圖書的原價
     * @return    計算出打折後的價格
     */
    public double quote(double booksPrice){
        return this.strategy.calcPrice(booksPrice);
    }
}

 

  客戶端

 

public class Client {
 
    public static void main(String[] args) {
        //選擇並建立須要使用的策略對象
        MemberStrategy strategy = new AdvancedMemberStrategy();
        //建立環境
        Price price = new Price(strategy);
        //計算價格
        double quote = price.quote(300);
        System.out.println("圖書的最終價格爲:" + quote);
    }
 
}

 

   從上面的示例能夠看出,策略模式僅僅封裝算法,提供新的算法插入到已有系統中,以及老算法從系統中「退休」的方法,策略模式並不決定在什麼時候使用何種算法。在什麼狀況下使用什麼算法是由客戶端決定的。

 

策略模式的重心

  策略模式的重心不是如何實現算法,而是如何組織、調用這些算法,從而讓程序結構更靈活,具備更好的維護性和擴展性。

算法的平等性

  策略模式一個很大的特色就是各個策略算法的平等性。對於一系列具體的策略算法,你們的地位是徹底同樣的,正由於這個平等性,才能實現算法之間能夠相互替換。全部的策略算法在實現上也是相互獨立的,相互之間是沒有依賴的。

  因此能夠這樣描述這一系列策略算法:策略算法是相同行爲的不一樣實現。

運行時策略的惟一性

  運行期間,策略模式在每個時刻只能使用一個具體的策略實現對象,雖然能夠動態地在不一樣的策略實現中切換,可是同時只能使用一個。

公有的行爲

  常常見到的是,全部的具體策略類都有一些公有的行爲。這時候,就應當把這些公有的行爲放到共同的抽象策略角色Strategy類裏面。固然這時候抽象策略角色必需要用Java抽象類實現,而不能使用接口。

 

 

源代碼

  環境角色類

 

public class Context {
    //持有一個具體策略的對象
    private Strategy strategy;
    /**
     * 構造函數,傳入一個具體策略對象
     * @param strategy    具體策略對象
     */
    public Context(Strategy strategy){
        this.strategy = strategy;
    }
    /**
     * 策略方法
     */
    public void contextInterface(){
        
        strategy.strategyInterface();
    }
    
}

 

  抽象策略類

 

public interface Strategy {
    /**
     * 策略方法
     */
    public void strategyInterface();
}

 

  具體策略類

 

public class ConcreteStrategyA implements Strategy {
 
    @Override
    public void strategyInterface() {
        //相關的業務
    }
 
}

 

 

public class ConcreteStrategyB implements Strategy {
 
    @Override
    public void strategyInterface() {
        //相關的業務
    }
 
}

 

 

public class ConcreteStrategyC implements Strategy {
 
    @Override
    public void strategyInterface() {
        //相關的業務
    }
 
}
相關文章
相關標籤/搜索