JAVA設計模式:策略模式

JAVA設計模式:策略模式(你還在使用IF ELSE IF嗎?)

 (2013-08-06 15:38:31)
  分類: Java技術

策略(Strategy)模式:又名Policy,它的用意是定義一組算法,把它們一個個封裝起來,並且使他們可以相互替換。策略模式可以獨立於使用他們的客戶端而變化。GOF策略模式靜態結構類圖如下:
http://dl2.iteye.com/upload/attachment/0087/8884/0d024111-f198-3ff6-947e-8d75a7544901.png

通過上圖可以看出策略模式有以下角色構成:

1、抽象策略(Strategy)角色:抽象策略角色由抽象類或接口來承擔,它給出具體策略角色需要實現的接口;

2、具體策略(ConcreteStrategy)角色:實現封裝了具體的算法或行爲;

3、場景(Context)角色:持有抽象策略類的引用。

策略模式重點是封裝不同的算法和行爲,不同的場景下可以相互替換。策略模式是開閉原則的體現,開閉原則講的是一個軟件實體應該對擴展開放對修改關 閉。策略模式在新的策略增加時,不會影響其他類的修改,增加了擴展性,也就是對擴展是開放的;對於場景來說,只依賴於抽象,而不依賴於具體實現,所以對修 改是關閉的。策略模式的認識可以藉助《java與模式》一書中寫到諸葛亮的錦囊妙計來學習,在不同的場景下趙雲打開不同的錦囊,便化險爲夷,錦囊便是抽象 策略,具體的錦囊裏面的計策便是具體的策略角色,場景就是趙雲,變化的處境

選擇具體策略的條件。

 

策略模式在程序設計中也很常用,在板橋(banq)的博客裏有篇文章叫 你還在用if else嗎?
http://www.jdon.com/artichect/ifelse.htm
講的很好,策略模式不但是繼承的代替方案而且能很好地解決if else問題,下面舉個實例來說明,怎麼使用策略模式。

需求如下:

某支付系統接入以下幾種商戶進行充值:易寶網易,快線網銀,19pay手機支付,支付寶支付,駿網一卡通,由於每家充值系統的結算比例不一樣,而且 同一家商戶的不同充值方式也有所不同,具體系統情況比較複雜,像支付寶既有支付寶賬號支付和支付寶網銀支付等這些暫時不考慮,爲了講述策略模式這裏簡單描 述,假如分爲四種,手機支付,網銀支付,商戶賬號支付和點卡支付。因爲沒個支付結算比例不同,所以對手續費低的做一些優惠活動,儘可能讓用戶使用手續費低 的支付方式來充值,這樣降低渠道費用,增加收入,具體優惠政策如下:

網銀充值,8.5折;

商戶充值,9折;

手機充值,沒有優惠;

點卡充值,收取1%的渠道費;

對於一個新手的代碼如下:

Java代碼  

package strategy;

 

public class Example {

 

   

    public Double calRecharge(Double charge ,RechargeTypeEnum type ){

      

       if(type.equals(RechargeTypeEnum.E_BANK)){

           return charge*0.85;

       }else if(type.equals(RechargeTypeEnum.BUSI_ACCOUNTS)){

           return charge*0.90;

       }else if(type.equals(RechargeTypeEnum.MOBILE)){

           return charge;

       }else if(type.equals(RechargeTypeEnum.CARD_RECHARGE)){

           return charge+charge*0.01;

       }else{

           return null;

       }

 

    }

   

Java代碼  

package strategy;

 

public enum RechargeTypeEnum {

 

    E_BANK(1, "網銀"),

   

    BUSI_ACCOUNTS(2, "商戶賬號"),

   

    MOBILE(3,"手機卡充值"),

   

    CARD_RECHARGE(4,"充值卡")

    ;

   

   

    private int value;

   

   

    private String description;

   

   

   

    private RechargeTypeEnum(int value, String description) {

       this.value = value;

       this.description = description;

    }

      

    public int value() {

       return value;

    }

    public String description() {

       return description;

    }

   

 

    public static RechargeTypeEnum valueOf(int value) {

        for(RechargeTypeEnum type : RechargeTypeEnum.values()) {

            if(type.value() == value) {

                return type;

            }

        }

        return null;

    }

}

 可以看出上面四種不同的計算方式在一個方法內部,不利於擴展和維護,當然也不符合面向對象設計原則。對以上的代碼利用策略模式進行修改,類圖如下:

 

http://dl2.iteye.com/upload/attachment/0087/8886/3ca5e83f-f6ad-3c77-a320-e716f5c3b639.png
 
實例代碼如下:

 

Java代碼  

package strategy.strategy;

 

import strategy.RechargeTypeEnum;

 

 

public interface Strategy {

 

   

    public Double calRecharge(Double charge ,RechargeTypeEnum type );

}

 

Java代碼  

package strategy.strategy;

 

import strategy.RechargeTypeEnum;

 

public class EBankStrategy implements Strategy{

 

    @Override

    public Double calRecharge(Double charge, RechargeTypeEnum type) {

       return charge*0.85;

    }

 

   

 

Java代碼  

package strategy.strategy;

 

import strategy.RechargeTypeEnum;

 

public class BusiAcctStrategy implements Strategy{

 

    @Override

    public Double calRecharge(Double charge, RechargeTypeEnum type) {

       // TODO Auto-generated method stub

       return charge*0.90;

    }

 

 

Java代碼  

package strategy.strategy;

 

import strategy.RechargeTypeEnum;

 

public class MobileStrategy implements Strategy {

 

    @Override

    public Double calRecharge(Double charge, RechargeTypeEnum type) {

       // TODO Auto-generated method stub

       return charge;

    }

 

}

 

Java代碼  

package strategy.strategy;

 

import strategy.RechargeTypeEnum;

 

public class CardStrategy implements Strategy{

 

    @Override

    public Double calRecharge(Double charge, RechargeTypeEnum type) {

       return charge+charge*0.01;

    }

 

Java代碼  

package strategy.strategy;

 

import strategy.RechargeTypeEnum;

 

 

public class Context {

 

    private Strategy strategy;

   

    public Double calRecharge(Double charge, Integer type) {

       strategy = StrategyFactory.getInstance().creator(type);

       return strategy.calRecharge(charge, RechargeTypeEnum.valueOf(type));

    }

 

    public Strategy getStrategy() {

       return strategy;

    }

 

    public void setStrategy(Strategy strategy) {

       this.strategy = strategy;

    }

   

Java代碼  

package strategy.strategy;

 

import java.util.HashMap;

import java.util.Map;

 

import strategy.RechargeTypeEnum;

 

public class StrategyFactory {

 

    private static StrategyFactory factory = new StrategyFactory();

    private StrategyFactory(){

    }

    private static Map strategyMap = new HashMap<>();

    static{

       strategyMap.put(RechargeTypeEnum.E_BANK.value(), new EBankStrategy());

       strategyMap.put(RechargeTypeEnum.BUSI_ACCOUNTS.value(), new BusiAcctStrategy());

       strategyMap.put(RechargeTypeEnum.MOBILE.value(), new MobileStrategy());

       strategyMap.put(RechargeTypeEnum.CARD_RECHARGE.value(), new CardStrategy());

    }

    public Strategy creator(Integer type){

       return strategyMap.get(type);

    }

    public static StrategyFactory getInstance(){

       return factory;

    }

Java代碼  

package strategy.strategy;

 

import strategy.RechargeTypeEnum;

 

public class Client {

 

   

    public static void main(String[] args) {

 

       Context context = new Context();

       // 網銀充值100 需要付多少

       Double money = context.calRecharge(100D,

              RechargeTypeEnum.E_BANK.value());

       System.out.println(money);

 

       // 商戶賬戶充值100 需要付多少

       Double money2 = context.calRecharge(100D,

              RechargeTypeEnum.BUSI_ACCOUNTS.value());

       System.out.println(money2);

 

       // 手機充值100 需要付多少

       Double money3 = context.calRecharge(100D,

              RechargeTypeEnum.MOBILE.value());

       System.out.println(money3);

 

       // 充值卡充值100 需要付多少

       Double money4 = context.calRecharge(100D,

              RechargeTypeEnum.CARD_RECHARGE.value());

       System.out.println(money4);

    }

 

}

運行結果:

 

85.0

90.0

100.0

101.0

從上面類圖和代碼可以看出,策略模式把具體的算法封裝到了具體策略角色內部,增強了可擴展性,隱蔽了實現細節;它替代繼承來實現,避免了if- else這種不易維護的條件語句。當然我們也可以看到,策略模式由於獨立策略實現,使得系統內增加了很多策略類;對客戶端來說必須知道兜友哪些具體策略, 而且需要知道選擇具體策略的條件。

 轉自:http://alaric.iteye.com/blog/1920714

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章