【轉】Java策略消除if else


策略(Strategy)模式:又名Policy,它的用意是定義一組算法,把它們一個個封裝起來,並且使他們可以相互替換。策略模式可以獨立於使用他們的客戶端而變化。GOF策略模式靜態結構類圖如下:

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

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 {  
      
        /** 
         *  
         *作者:alaric 
         *時間:2013-8-5上午11:00:06 
         *描述:計算用戶所付金額 
         */  
        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;   
        }  
    }  

 

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

 


 實例代碼如下:

 

Java代碼   收藏代碼
  1. package strategy.strategy;  
  2.   
  3. import strategy.RechargeTypeEnum;  
  4.   
  5. /** 
  6.  *  
  7.  *作者:alaric 
  8.  *時間:2013-8-5上午11:03:17 
  9.  *描述:策略抽象類 
  10.  */  
  11. public interface Strategy {  
  12.   
  13.     /** 
  14.      *  
  15.      *作者:alaric 
  16.      *時間:2013-8-5上午11:05:11 
  17.      *描述:策略行為方法 
  18.      */  
  19.     public Double calRecharge(Double charge ,RechargeTypeEnum type );  
  20. }  

 

Java代碼   收藏代碼
  1. package strategy.strategy;  
  2.   
  3. import strategy.RechargeTypeEnum;  
  4. /** 
  5.  *  
  6.  *作者:alaric 
  7.  *時間:2013-8-5上午11:14:23 
  8.  *描述:網銀充值 
  9.  */  
  10. public class EBankStrategy implements Strategy{  
  11.   
  12.     @Override  
  13.     public Double calRecharge(Double charge, RechargeTypeEnum type) {  
  14.         return charge*0.85;  
  15.     }  
  16.   
  17.       
  18.   
  19. }  

 

Java代碼   收藏代碼
  1. package strategy.strategy;  
  2.   
  3. import strategy.RechargeTypeEnum;  
  4. /** 
  5.  *  
  6.  *作者:alaric 
  7.  *時間:2013-8-5上午11:14:08 
  8.  *描述:商戶賬號充值 
  9.  */  
  10. public class BusiAcctStrategy implements Strategy{  
  11.   
  12.     @Override  
  13.     public Double calRecharge(Double charge, RechargeTypeEnum type) {  
  14.         // TODO Auto-generated method stub  
  15.         return charge*0.90;  
  16.     }  
  17.   
  18. }  

 

Java代碼   收藏代碼
  1. package strategy.strategy;  
  2.   
  3. import strategy.RechargeTypeEnum;  
  4. /** 
  5.  *  
  6.  *作者:alaric 
  7.  *時間:2013-8-5上午11:14:43 
  8.  *描述:手機充值 
  9.  */  
  10. public class MobileStrategy implements Strategy {  
  11.   
  12.     @Override  
  13.     public Double calRecharge(Double charge, RechargeTypeEnum type) {  
  14.         // TODO Auto-generated method stub  
  15.         return charge;  
  16.     }  
  17.   
  18. }  

 

Java代碼   收藏代碼
  1. package strategy.strategy;  
  2.   
  3. import strategy.RechargeTypeEnum;  
  4. /** 
  5.  *  
  6.  *作者:alaric 
  7.  *時間:2013-8-5上午11:13:46 
  8.  *描述:充值卡充值 
  9.  */  
  10. public class CardStrategy implements Strategy{  
  11.   
  12.     @Override  
  13.     public Double calRecharge(Double charge, RechargeTypeEnum type) {  
  14.         return charge+charge*0.01;  
  15.     }  
  16.   
  17. }  

 

Java代碼   收藏代碼
  1. package strategy.strategy;  
  2.   
  3. import strategy.RechargeTypeEnum;  
  4.   
  5. /** 
  6.  *  
  7.  *作者:alaric 
  8.  *時間:2013-8-5上午11:03:38 
  9.  *描述:場景類 
  10.  */  
  11. public class Context {  
  12.   
  13.     private Strategy strategy;  
  14.       
  15.     public Double calRecharge(Double charge, Integer type) {  
  16.         strategy = StrategyFactory.getInstance().creator(type);  
  17.         return strategy.calRecharge(charge, RechargeTypeEnum.valueOf(type));  
  18.     }  
  19.   
  20.     public Strategy getStrategy() {  
  21.         return strategy;  
  22.     }  
  23.   
  24.     public void setStrategy(Strategy strategy) {  
  25.         this.strategy = strategy;  
  26.     }  
  27.       
  28. }  

 

Java代碼   收藏代碼
  1. package strategy.strategy;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import strategy.RechargeTypeEnum;  
  7. /** 
  8.  *  
  9.  *作者:alaric 
  10.  *時間:2013-8-5上午11:31:12 
  11.  *描述:策略工廠 使用單例模式 
  12.  */  
  13. public class StrategyFactory {  
  14.   
  15.     private static StrategyFactory factory = new StrategyFactory();  
  16.     private StrategyFactory(){  
  17.     }  
  18.     private static Map<Integer ,Strategy> strategyMap = new HashMap<>();  
  19.     static{  
  20.         strategyMap.put(RechargeTypeEnum.E_BANK.value(), new EBankStrategy());  
  21.         strategyMap.put(RechargeTypeEnum.BUSI_ACCOUNTS.value(), new BusiAcctStrategy());  
  22.         strategyMap.put(RechargeTypeEnum.MOBILE.value(), new MobileStrategy());  
  23.         strategyMap.put(RechargeTypeEnum.CARD_RECHARGE.value(), new CardStrategy());  
  24.     }  
  25.     public Strategy creator(Integer type){  
  26.         return strategyMap.get(type);  
  27.     }  
  28.     public static StrategyFactory getInstance(){  
  29.         return factory;  
  30.     }  
  31. }  

 

Java代碼   收藏代碼
  1. package strategy.strategy;  
  2.   
  3. import strategy.RechargeTypeEnum;  
  4.   
  5. public class Client {  
  6.   
  7.     /** 
  8.      * 作者:alaric 時間:2013-8-5上午11:33:52 描述: 
  9.      */  
  10.     public static void main(String[] args) {  
  11.   
  12.         Context context = new Context();  
  13.         // 網銀充值100 需要付多少  
  14.         Double money = context.calRecharge(100D,  
  15.                 RechargeTypeEnum.E_BANK.value());  
  16.         System.out.println(money);  
  17.   
  18.         // 商戶賬戶充值100 需要付多少  
  19.         Double money2 = context.calRecharge(100D,  
  20.                 RechargeTypeEnum.BUSI_ACCOUNTS.value());  
  21.         System.out.println(money2);  
  22.   
  23.         // 手機充值100 需要付多少  
  24.         Double money3 = context.calRecharge(100D,  
  25.                 RechargeTypeEnum.MOBILE.value());  
  26.         System.out.println(money3);  
  27.   
  28.         // 充值卡充值100 需要付多少  
  29.         Double money4 = context.calRecharge(100D,  
  30.                 RechargeTypeEnum.CARD_RECHARGE.value());  
  31.         System.out.println(money4);  
  32.     }  
  33.   
  34. }  

運行結果:

 

85.0

90.0

100.0

101.0

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM