23種設計模式(十九)策略者模式

1.定義:html

定義一系列的算法,把他們一個個封裝起來,而且使它們能夠相互替換,使得算法可獨立於使用它的客戶而變化。java

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

2.結構數據結構

策略模式是對算法的包裝,是把使用算法的責任和算法自己分隔開來,委派給不一樣的對象管理,策略模式一般把一系列的算法包裝到一系列的策略類裏,做爲一個抽象策略類的子類。 通俗講就是準備一組算法,並將每個算法封裝起來,使他們能夠互換。ide

具體策略(ConcreteStrategy)角色:包裝了相關的算法或行爲。函數

抽象策略(Strategy)角色: 抽象角色,一般由一個接口或抽象類實現,此角色給出全部的具體策略類所需的接口。工具

環境(Context)角色:持有一個Strategy的引用網站

環境角色類:ui

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

/** * 策略方法 */
public void contextInterface(){
strategy.strategyInterface();
}

}

抽象策略類:this

public Interface Strategy{

 /**
     * 策略方法
     */
    public void strategyInterface()
}

具體策略類:

public class ConcreteStrategyA implements Strategy {
@Override
public void strategyInterface() {
//相關的業務 System.out.println("A算法")
}

}

public class ConcreteStrategyB implements Strategy {

    @Override
    public void strategyInterface() {
        //相關的業務
       System.out.println("B算法")
    }

}
public class ConcreteStrategyC implements Strategy {
@Override
public void strategyInterface() {
//相關的業務
System.out.println("C算法")
}
}

3.使用場景

 假設如今要設計一個販賣各種書籍的電子商務網站的購物車系統。一個最簡單的狀況就是把全部貨品的單價乘上數量,可是實際狀況確定比這要複雜。好比,本網站可能對全部的高級會員提供每本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); 
   } 
}

從上面的例子能夠看出,策略模式主要包含如下幾個要點:

有一個存放公共接口的抽象策略類

多個實現抽象策略類的具體策略類封裝了算法

策略模式並不決定在什麼時候使用何種算法,這些是客戶端決定的

提供新的算法插入到已有系統中,以及老算法從系統中退休的方法,符合開閉原則 對擴展開放,對修改關閉。

例2:在java加密中,咱們會常常看到 MessageDigest md5 = MessageDigest.getInstance("MD5")、MessageDigest sha = MessageDigest.getInstance("SHA")。

給一個不一樣的參數,不同的加密算法,(ps:java加密底層我也不是道是否是使用了策略模式、可是跟策略模式的定義很像,有空研究研究)

例3:出行旅遊:咱們能夠有幾個策略能夠考慮:能夠騎自行車,汽車,作火車,飛機。每一個策略均可以獲得相同的結果,可是它們使用了不一樣的資源。選擇策略的依據是費用,時間,使用工具還有每種方式的方便程度 。

如何讓算法和對象分開來,使得算法能夠獨立於使用它的客戶而變化?

結構圖以下:

出行旅遊策略(Strategy):

/** 
* 出行旅遊 
* 
*  
*/  
public interface TravelStrategy{  
    public void travelAlgorithm();  
}

 具體策略類(ConcreteStrategy):乘坐飛機 

/** 
 * 具體策略類(ConcreteStrategy)2:乘坐飛機
 */  
class AirPlanelStrategy implements TravelStrategy {  
    public void travelAlgorithm(){  
        System.out.println("坐飛機") 
    }  
}

具體策略類(ConcreteStrategy):坐火車

/** 
 * 具體策略類(ConcreteStrategy)2:乘坐火車 
 */  
class TrainStrategy implements TravelStrategy {  
    public void travelAlgorithm(){  
        System.out.println("坐火車");
    }  
}

具體策略類(ConcreteStrategy) : 騎自行車

/** 
 * 具體策略類(ConcreteStrategy)3:騎自行車 
 */  
class BicycleStrategy implements TravelStrategy {  
    public void travelAlgorithm(){  
        System.out.println("騎自行車");
    }  
}

環境類(Context):用一個ConcreteStrategy對象來配置。維護一個對Strategy對象的引用。可定義一個接口來讓Strategy訪問它的數據。算法解決類,以提供客戶選擇使用何種解決方案: 

class PersonContext{  

    private TravelStrategy travelStrategy ;  
  
    public PersonContext(TravelStrategy travelStrategy ){  
        this.travelStrategy = travelStrategy ;  
    }  

    /** 
    * 旅行 
    */  
    public void travel(){  
        return this.travelStrategy.travelAlgorithm();  
    }  
}

客戶端:

public class Client {

    public static void main(String[] args) {
        //選擇並建立須要使用的策略對象
        TravelStrategy strategy = new BicycleStrategy();
        //建立環境
        PersonContext personContext = new PersonContext(strategy);
        //選擇自行車方式
        personContext.travelAlgorithm(); 
    }

}

 

4.使用場合

當存在如下狀況時使用Strategy模式
1)• 許多相關的類僅僅是行爲有異。 「策略」提供了一種用多個行爲中的一個行爲來配置一個類的方法。即一個系統須要動態地在幾種算法中選擇一種。
2)• 須要使用一個算法的不一樣變體。例如,你可能會定義一些反映不一樣的空間 /時間權衡的算法。當這些變體實現爲一個算法的類層次時 ,可使用策略模式。
3)• 算法使用客戶不該該知道的數據。可以使用策略模式以免暴露覆雜的、與算法相關的數據結構。
4)• 一個類定義了多種行爲 , 而且這些行爲在這個類的操做中以多個條件語句的形式出現。將相關的條件分支移入它們各自的Strategy類中以代替這些條件語句。

 

5.策略模式優缺點

優勢

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

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

缺點

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

  (2)因爲策略模式把每一個具體的策略實現都單獨封裝成爲類,若是備選的策略不少的話,那麼對象的數目就會很可觀。

6.總結

策略模式重心

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

算法的平等性

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

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

運行時策略模式的惟一性

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

公有的行爲

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

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

摘自:

https://www.cnblogs.com/java-my-life/archive/2012/05/10/2491891.html

http://blog.csdn.net/hguisu/article/details/7558249

加深理解:

http://blog.csdn.net/hguisu/article/details/7558249

相關文章
相關標籤/搜索