一塊兒學設計模式 - 策略模式

策略模式(Strategy Pattern)屬於 對象行爲型模式的一種,其用意是 針對一組算法,將每個算法封裝到具備共同接口的獨立的類中,從而使得它們能夠相互替換。策略模式使得算法能夠在不影響到客戶端的狀況下發生變化。

<!-- more -->html

概述

策略模式: 是對算法的包裝,是把使用算法的責任和算法自己分割開來,委派給不一樣的對象管理。策略模式一般把一個系列的算法包裝到一系列的策略類裏面,做爲一個抽象策略類的子類。用一句話來講,就是:「準備一組算法,並將每個算法封裝起來,使得它們能夠互換」。下面就以一個示意性的實現講解策略模式實例的結構。java

UML結構圖

策略模式UML

模式結構
  • 環境(Context)角色: 持有一個Strategy的引用。
  • 抽象策略(Strategy)角色: 這是一個抽象角色,一般由一個接口或抽象類實現。此角色給出全部的具體策略類所需的接口。
  • 具體策略(ConcreteStrategy)角色: 包裝了相關的算法或行爲。

案例

採用上文的UML圖以及分析出的模式結構,寫一個簡單的購物折扣功能git

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

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

  • 算法一:對初級會員沒有折扣。
  • 算法二:對中級會員提供10%的促銷折扣。
  • 算法三:對高級會員提供20%的促銷折扣。
結構圖以下:

結構圖以下

1.定義抽象折扣類ide

/**
 * 會員優惠策略
 */
interface MemberStrategy {
    /**
     * 計算圖書的價格
     *
     * @param booksPrice 圖書的原價
     * @return 計算出打折後的價格
     */
    double calcPrice(double booksPrice);
}

2.建立三個 具體策略類 ,表明三種不一樣計算規則函數

class PrimaryMemberStrategy implements MemberStrategy {

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

}

class IntermediateMemberStrategy implements MemberStrategy {

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

}

class AdvancedMemberStrategy implements MemberStrategy {

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

3.建立 環境(Context)角色 價格類,持有抽象決策的引用測試

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);
    }
}

4.建立客戶端,用於測試網站

public class Client {

    public static void main(String[] args) {

        Price price;
        //建立環境
        price = new Price(new PrimaryMemberStrategy());
        //計算價格
        System.out.println("圖書的最終價格爲:" + price.quote(300));

        //建立環境
        price = new Price(new AdvancedMemberStrategy());
        //計算價格
        System.out.println("圖書的最終價格爲:" + price.quote(300));

    }
}

6.運行結果this

對於初級會員的沒有折扣
圖書的最終價格爲:300.0
對於高級會員的折扣爲20%
圖書的最終價格爲:240.0

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

總結

重心

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

算法平等性

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

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

策略的惟一性

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

公有的行爲

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

這其實也是典型的將代碼向繼承等級結構的上方集中的標準作法。

123123

優勢
  • 策略模式提供了管理相關的算法族的辦法。策略類的等級結構定義了一個算法或行爲族。恰當使用繼承能夠把公共的代碼移到父類裏面,從而避免代碼重複。
  • 使用策略模式能夠避免使用多重條件(if-else)語句。多重條件語句不易維護,它把採起哪種算法或採起哪種行爲的邏輯與算法或行爲的邏輯混合在一塊兒,通通列在一個多重條件語句裏面,比使用繼承的辦法還要原始和落後。
缺點
  • 客戶端必須知道全部的策略類,並自行決定使用哪個策略類。這就意味着客戶端必須理解這些算法的區別,以便適時選擇恰當的算法類。換言之,策略模式只適用於客戶端知道算法或行爲的狀況。
  • 因爲策略模式把每一個具體的策略實現都單獨封裝成爲類,若是備選的策略不少的話,那麼對象的數目就會很可觀。

說點什麼

參考文獻:http://www.cnblogs.com/java-my-life/archive/2012/05/10/2491891.html

全文代碼:https://gitee.com/battcn/design-pattern/tree/master/Chapter18/battcn-strategy

  • 我的QQ:1837307557
  • battcn開源羣(適合新手):391619659

微信公衆號:battcn(歡迎調戲)

相關文章
相關標籤/搜索